1. 程式人生 > >android仿ios版本飛常準app字母列表索引,純原創。

android仿ios版本飛常準app字母列表索引,純原創。

仿飛常準字母索引,純原創。

這裡寫圖片描述

這裡寫圖片描述

偶然看見飛常準(ios)的字母列表索引,覺得很酷炫,ios可以的android沒有不行的,所以就寫了一個demo,實現效果完全一樣。

自定義字母索引view

package com.example.sunsh.letter;

import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import
android.graphics.Paint; import android.graphics.Rect; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import java.util.ArrayList; import java.util.List; /** * Created by sunsh on 2017/8/7. */ public class LetterIndext extends View { private Paint paint
; private float TEXT_WIDTH = 60; private float MAX_DISTANCE = 140; private final float NORMAL_SIZE = 26; private float MAX_SIZE = 80; private String DEFAULT_COLOR = "606060"; private int SELECT_COLOR = Color.WHITE; //字母容器 private ArrayList<LetterData> list = new ArrayList
<>(); private int width; private int height; private int text_height; //拋物線係數 private float ratio = 0.005f; private int position; public LetterIndext(Context context) { super(context); initPaint(); } public LetterIndext(Context context, AttributeSet attrs) { super(context, attrs); initPaint(); } public LetterIndext(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initPaint(); } public void setList(List<String> list) { this.list.clear(); for (int i = 0; i < list.size(); i++) { //預設距離移動距離0,預設大小40,預設顏色灰色cdcdcd,預設不加粗 this.list.add(new LetterData(list.get(i), 0, NORMAL_SIZE, Color.parseColor("#"+DEFAULT_COLOR), false)); } invalidate(); } public void setSelectColor(int color){ this.SELECT_COLOR = color; } private void initPaint() { paint = new Paint(); paint.setStyle(Paint.Style.FILL); paint.setTextAlign(Paint.Align.CENTER); paint.setAntiAlias(true); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); width = canvas.getWidth(); height = canvas.getHeight(); canvas.translate(width - TEXT_WIDTH, 0); if (list.size() > 0) { text_height = height / list.size(); for (int i = 0; i < list.size(); i++) { if (i != position) { LetterData letterData = list.get(i); paint.setColor(Color.TRANSPARENT); Rect rect = new Rect(0, i * text_height, (int) TEXT_WIDTH, i * text_height + text_height); canvas.drawRect(rect, paint); Paint.FontMetrics fontMetrics = paint.getFontMetrics(); int baseline = (int) ((rect.bottom + rect.top - fontMetrics.bottom - fontMetrics.top) / 2); paint.setTextSize(letterData.getTextSize()); paint.setColor(letterData.getTextColor()); if (letterData.isBlod) paint.setFakeBoldText(true); else paint.setFakeBoldText(false); canvas.drawText(letterData.getText(), 30 - letterData.distance, baseline, paint); } } if (position < list.size() && position >= 0) { LetterData letterData = list.get(position); paint.setColor(Color.TRANSPARENT); Rect rect = new Rect(0, position * text_height, (int) TEXT_WIDTH, position * text_height + text_height); canvas.drawRect(rect, paint); Paint.FontMetrics fontMetrics = paint.getFontMetrics(); int baseline = (int) ((rect.bottom + rect.top - fontMetrics.bottom - fontMetrics.top) / 2); paint.setTextSize(letterData.getTextSize()); paint.setColor(letterData.getTextColor()); if (letterData.isBlod) paint.setFakeBoldText(true); else paint.setFakeBoldText(false); canvas.drawText(letterData.getText(), 30 - letterData.distance, baseline, paint); } } } private boolean isAnimation = false; @Override public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); if (event.getPointerCount() == 1) { switch (action) { case MotionEvent.ACTION_DOWN:
float x = event.getX(); float y = event.getY(); if (x > width - TEXT_WIDTH) { if (text_height != 0) { position = (int) (y / text_height); if (position >= 0 && position < list.size()) if (!isAnimation) { isAnimation = true; onActionDown(position, y); } } return true; } break; case MotionEvent.ACTION_MOVE: float moveX = event.getX(); float moveY = event.getY(); if (text_height != 0) { position = (int) (moveY / text_height); if (position >= 0 && position < list.size()) onActionMove(position, moveY); else { if (position < 0) position = 0; if (position >= list.size()) position = list.size() - 1; onActionUp(); } return true; } break; case MotionEvent.ACTION_UP: if (text_height != 0) { int upPosition = (int) (event.getY() / text_height); if (upPosition >= 0 && upPosition < list.size()) { isAnimation = true; if (onSeletListener!=null){ onSeletListener.onSelect(upPosition,list.get(upPosition).getText()); } onActionUp(); return true; } } break; default: isAnimation = true; onActionUp(); break; } } return super.onTouchEvent(event); } private void onActionUp() { for (int i = position - 4; i <= position + 4; i++) { if (i >= 0 && i < list.size()) { final LetterData letterData = list.get(i); final float distance = letterData.getDistance(); final ValueAnimator valueAnimator = ValueAnimator.ofFloat(distance, 0); if (i == position) { valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { float animatedValue = (float) valueAnimator.getAnimatedValue(); float scaleSize = animatedValue / MAX_DISTANCE; float offsetSize = (MAX_SIZE - NORMAL_SIZE) * scaleSize; int alpha = (int) (255 * (1 - (animatedValue / MAX_DISTANCE))); String str_alpha = Integer.toHexString(alpha); int length = str_alpha.length(); if (length < 2) { str_alpha = "0" + str_alpha; } if (animatedValue < 70) { letterData.setState(animatedValue, NORMAL_SIZE + offsetSize, Color.parseColor("#" + str_alpha + DEFAULT_COLOR), false); } else { letterData.setState(animatedValue, NORMAL_SIZE + offsetSize, SELECT_COLOR, false); } invalidate(); } }); valueAnimator.setDuration(100); valueAnimator.start(); } else { valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { float animatedValue = (float) valueAnimator.getAnimatedValue(); float scaleSize = animatedValue / MAX_DISTANCE; float offsetSize = (MAX_SIZE - NORMAL_SIZE) * scaleSize; int alpha = (int) (255 * (1 - (animatedValue / MAX_DISTANCE))); String str_alpha = Integer.toHexString(alpha); int length = str_alpha.length(); if (length < 2) { str_alpha = "0" + str_alpha; } letterData.setState(animatedValue, NORMAL_SIZE + offsetSize, Color.parseColor("#" + str_alpha + DEFAULT_COLOR), false); invalidate(); } }); valueAnimator.setDuration(100); valueAnimator.start(); } if (i == position + 4 || i == list.size() - 1) { valueAnimator.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animator) { } @Override public void onAnimationEnd(Animator animator) { isAnimation = false; animator.removeAllListeners(); } @Override public void onAnimationCancel(Animator animator) { } @Override public void onAnimationRepeat(Animator animator) { } }); } } } } private void onActionDown(final int indext, float downY) { for (int i = 0; i < list.size(); i++) { if (i >= indext - 4 && i <= indext + 4) { float distance = -ratio * (downY - getCenterY(i)) * (downY - getCenterY(i)) + MAX_DISTANCE; if (distance < 0) distance = 0; final LetterData data = list.get(i); ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, distance); if (i != indext) { valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { float animatedValue = (float) valueAnimator.getAnimatedValue(); float scaleSize = animatedValue / MAX_DISTANCE; float offsetSize = (MAX_SIZE - NORMAL_SIZE) * scaleSize; int alpha = (int) (255 * (1 - (animatedValue / MAX_DISTANCE))); String str_alpha = Integer.toHexString(alpha); int length = str_alpha.length(); if (length < 2) { str_alpha = "0" + str_alpha; } data.setState(animatedValue, NORMAL_SIZE + offsetSize, Color.parseColor("#" + str_alpha + DEFAULT_COLOR), false); invalidate(); } }); valueAnimator.setDuration(100); valueAnimator.start(); } else { valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { float animatedValue = (float) valueAnimator.getAnimatedValue(); float scaleSize = animatedValue / MAX_DISTANCE; float offsetSize = (MAX_SIZE - NORMAL_SIZE) * scaleSize; int alpha = (int) (255 * (1 - (animatedValue / MAX_DISTANCE))); String str_alpha = Integer.toHexString(alpha); int length = str_alpha.length(); if (length < 2) { str_alpha = "0" + str_alpha; } if (animatedValue > 70) data.setState(animatedValue, NORMAL_SIZE + offsetSize, SELECT_COLOR, true); else data.setState(animatedValue, NORMAL_SIZE + offsetSize, Color.parseColor("#" + str_alpha + DEFAULT_COLOR), false); } }); valueAnimator.setDuration(100); valueAnimator.start(); } } else { list.get(i).setState(0, NORMAL_SIZE, Color.parseColor("#"+DEFAULT_COLOR), false); } } invalidate(); } private void onActionMove(int indext, float downY) { for (int i = 0; i < list.size(); i++) { LetterData data = list.get(i); if (i >= indext - 4 && i <= indext + 4) { float distance = -ratio * (downY - getCenterY(i)) * (downY - getCenterY(i)) + MAX_DISTANCE; if (distance < 0) distance = 0; float scaleSize = distance / MAX_DISTANCE; float offsetSize = (MAX_SIZE - NORMAL_SIZE) * scaleSize; int alpha = (int) (255 * (1 - (distance / MAX_DISTANCE))); String str_alpha = Integer.toHexString(alpha); int length = str_alpha.length(); if (length < 2) { str_alpha = "0" + str_alpha; } if (i == indext) { data.setState(distance, NORMAL_SIZE + offsetSize, SELECT_COLOR, true); } else { data.setState(distance, NORMAL_SIZE + offsetSize, Color.parseColor("#" + str_alpha + DEFAULT_COLOR), false); } } else { data.setState(0, NORMAL_SIZE, Color.parseColor("#"+DEFAULT_COLOR), false); } } invalidate(); } private OnSeletListener onSeletListener; public void setOnSeletListener(OnSeletListener o) { this.onSeletListener = o; } public interface OnSeletListener { void onSelect(int position, String letter); } private float getCenterY(int index) { int i = text_height / 2 + index * text_height; return i; } class LetterData { private float distance; private float textSize; private String text; private int textColor; private boolean isBlod; public LetterData(String text, float distance, float textSize, int textColor, boolean isBlod) { this.distance = distance; this.textSize = textSize; this.text = text; this.textColor = textColor; this.isBlod = isBlod; } public void setState(float distance, float textSize, int textColor, boolean isBlod) { this.distance = distance; this.textSize = textSize; this.textColor = textColor; this.isBlod = isBlod; } public boolean isBlod() { return isBlod; } public void setBlod(boolean blod) { isBlod = blod; } public int getTextColor() { return textColor; } public void setTextColor(int textColor) { this.textColor = textColor; } public float getDistance() { return distance; } public void setDistance(float distance) { this.distance = distance; } public float getTextSize() { return textSize; } public void setTextSize(int textSize) { this.textSize = textSize; } public String getText() { return text; } public void setText(String text) { this.text = text; } } } ... prompt'''

Activity

package com.example.sunsh.letter;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    private ArrayList<String> strings;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final ListView listView = (ListView) findViewById(R.id.listview);

        LetterIndext letterIndext = (LetterIndext) findViewById(R.id.letter);
        final ArrayList<String> list = new ArrayList<>();
        for (char i = 63; i <= 90; i++) {
            list.add(i+"");
        }
        letterIndext.setList(list);
        letterIndext.setOnSeletListener(new LetterIndext.OnSeletListener() {
            @Override
            public void onSelect(int position,String letter) {
                int i = strings.indexOf(letter);
                listView.setSelection(i);
            }
        });
        findViewById(R.id.text).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this,"keyi ",Toast.LENGTH_SHORT).show();
            }
        });

        strings = new ArrayList<>();

        for (char i = 63; i <= 90; i++) {
            strings.add(i+"");
            for (int j = 0; j < 10; j++) {
                strings.add(i+""+i);
            }
        }
        listView.setAdapter(new BaseAdapter() {
            @Override
            public int getCount() {
                return strings.size();
            }

            @Override
            public Object getItem(int i) {
                return null;
            }

            @Override
            public long getItemId(int i) {
                return 0;
            }

            @Override
            public View getView(int i, View view, ViewGroup viewGroup) {
                TextView textView = new TextView(MainActivity.this);
                textView.setText(strings.get(i));
                textView.setPadding(20,20,20,20);
                return textView;
            }
        });

    }
}

... prompt'''

xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:background="#70000000"
    android:layout_height="match_parent"
    tools:context="com.example.sunsh.letter.MainActivity">
    <ListView
        android:id="@+id/listview"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </ListView>
    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_centerInParent="true"
        android:layout_height="wrap_content"
        android:text="Hello World!" />

    <com.example.sunsh.letter.LetterIndext
        android:id="@+id/letter"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</RelativeLayout>

... prompt'''

下載地址