项目需求:仿微信快速索引功能,手指点击索引字母时,对应字母变色,并且有背景颜色,手指离开时,需要记录最后点击的字母。
效果预览:
话不多说,开撸:
1.新建类:
public class FastIndexView extends View {
public FastIndexView(Context context) {
this(context, null);
}
public FastIndexView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public FastIndexView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
}
2.定义画笔、需要用到的变量和需要绘制的文字:
private static final String INDEX_NAME = "#ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private Paint mPaint;
3.做一些初始化操作:
mPaint = new Paint();
mPaint.setTextSize(DpUtil.dip2px(16));
mPaint.setAntiAlias(true);
4.变量赋值:
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
//得到当前控件的宽度
viewWidth = getMeasuredWidth();
int mHeight = getMeasuredHeight();
//获取单个字符能够拥有的高度
cellHeight = mHeight * 1.0f / INDEX_NAME.length();
}
5.绘制字符:
@Override
protected void onDraw(Canvas canvas) {
for (int i = 0; i < INDEX_NAME.length(); i++) {
String text = INDEX_NAME.substring(i, i + 1);
//计算绘制字符的X方向起点
int x = (int) (viewWidth / 2.0f - mPaint.measureText(text) / 2.0f);
Rect bounds = new Rect();
mPaint.getTextBounds(text, 0, text.length(), bounds);
int textHeight = bounds.height();
//计算绘制字符的Y方向起点
int y = (int) (cellHeight / 2.0f + textHeight / 2.0f + i
* cellHeight);
//绘制选中字符的背景
if (touchIndex == i) {
mPaint.setColor(Color.RED);
canvas.drawCircle(viewWidth / 2, cellHeight * i + cellHeight / 2, cellHeight / 2, mPaint);
}
mPaint.setColor(touchIndex == i ? Color.WHITE : selectedColor);
canvas.drawText(text, x, y, mPaint);
}
}
6.处理手势事件:
@Override
public boolean onTouchEvent(MotionEvent event) {
int index;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//计算当前触摸的字符索引
index = (int) (event.getY() / cellHeight);
if (index >= 0 && index < INDEX_NAME.length()) {
if (index != touchIndex) {
if (listener != null) {
listener.onLetterUpdate(INDEX_NAME.substring(index, index + 1));
}
touchIndex = index;
}
}
break;
case MotionEvent.ACTION_MOVE:
//计算当前触摸的字符索引
index = (int) (event.getY() / cellHeight);
if (index >= 0 && index < INDEX_NAME.length()) {
if (index != touchIndex) {
if (listener != null) {
listener.onLetterUpdate(INDEX_NAME.substring(index, index + 1));
}
touchIndex = index;
}
}
break;
}
invalidate();
return true;
}
注释很详细,下面是完整源码:
package com.dongdongkeji.wangwangsocial.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import com.base.utils.DpUtil;
import com.dongdongkeji.wangwangsocial.R;
/**
* 快速索引控件
* Created by chao on 2018/2/28.
*/
public class FastIndexView extends View {
private static final String INDEX_NAME = "#ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private OnLetterUpdateListener listener;
private Paint mPaint;
private float cellHeight, viewWidth;
private int touchIndex = -1, selectedColor;
public FastIndexView(Context context) {
this(context, null);
}
public FastIndexView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public FastIndexView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mPaint = new Paint();
mPaint.setTextSize(DpUtil.dip2px(16));
mPaint.setAntiAlias(true);
//获取文字被选中的颜色
selectedColor = ContextCompat.getColor(context, R.color.font_color_normal);
}
@Override
protected void onDraw(Canvas canvas) {
for (int i = 0; i < INDEX_NAME.length(); i++) {
String text = INDEX_NAME.substring(i, i + 1);
//计算绘制字符的X方向起点
int x = (int) (viewWidth / 2.0f - mPaint.measureText(text) / 2.0f);
Rect bounds = new Rect();
mPaint.getTextBounds(text, 0, text.length(), bounds);
int textHeight = bounds.height();
//计算绘制字符的Y方向起点
int y = (int) (cellHeight / 2.0f + textHeight / 2.0f + i
* cellHeight);
//绘制选中字符的背景
if (touchIndex == i) {
mPaint.setColor(Color.RED);
canvas.drawCircle(viewWidth / 2, cellHeight * i + cellHeight / 2, cellHeight / 2, mPaint);
}
mPaint.setColor(touchIndex == i ? Color.WHITE : selectedColor);
canvas.drawText(text, x, y, mPaint);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int index;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//计算当前触摸的字符索引
index = (int) (event.getY() / cellHeight);
if (index >= 0 && index < INDEX_NAME.length()) {
if (index != touchIndex) {
if (listener != null) {
listener.onLetterUpdate(INDEX_NAME.substring(index, index + 1));
}
touchIndex = index;
}
}
break;
case MotionEvent.ACTION_MOVE:
//计算当前触摸的字符索引
index = (int) (event.getY() / cellHeight);
if (index >= 0 && index < INDEX_NAME.length()) {
if (index != touchIndex) {
if (listener != null) {
listener.onLetterUpdate(INDEX_NAME.substring(index, index + 1));
}
touchIndex = index;
}
}
break;
}
invalidate();
return true;
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
//得到当前控件的宽度
viewWidth = getMeasuredWidth();
int mHeight = getMeasuredHeight();
//获取单个字符能够拥有的高度
cellHeight = mHeight * 1.0f / INDEX_NAME.length();
}
public interface OnLetterUpdateListener {
void onLetterUpdate(String letter);
}
public void setListener(OnLetterUpdateListener listener) {
this.listener = listener;
}
/**
* 匹配字母
*
* @param letter
*/
public void matchingLetter(String letter) {
for (int i = 0; i < INDEX_NAME.length(); i++) {
if (letter.equals(INDEX_NAME.substring(i, i + 1))) {
touchIndex = i;
invalidate();
}
}
}
}