android仿ios版本飞常准app字母列表索引,纯原创。
16lz
2021-01-26
仿飞常准字母索引,纯原创。
偶然看见飞常准(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 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"?>"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"> "@+id/listview" android:layout_width="match_parent" android:layout_height="match_parent"> "@+id/text" android:layout_width="wrap_content" android:layout_centerInParent="true" android:layout_height="wrap_content" android:text="Hello World!" /> "@+id/letter" android:layout_width="match_parent" android:layout_height="match_parent"/> ... prompt'''
下载地址
http://download.csdn.net/detail/qq_35959231/9923874
更多相关文章
- 史上最全的Android开发索引帖
- Android动画资源(三)——插值器
- NDK编译Libyuv
- MD2模型結構解釋
- Realm简单使用
- Android(安卓)Toast大全(五种情形)建立属于你自己的Toast
- Ionic Tabs
- Android(安卓)Eclipse 自动安装到真机(免去选择的麻烦)
- [转]微信ANDROID客户端-会话速度提升70%的背后