Android之联系人A~Z快速索引效果
说到android的联系人的快速索引,很快就能想到系统自带的快速索引效果,而且现在很多主流的应用都有用到,如QQ的通讯录,微信的通讯录等等。
要想实现快速索引的效果,我们先来理下其实现原理:
首先,我们需要定义一个自定义的控件,得到控件(自定义控件SlideBar)的总高度与宽度,通过SlideBar控件的总高度算出从A~Z(一般最后都有个#)每个字符的需要的高度,再通过循环偏移单个字符高度来画出每个字符,这样第一步就完成了,接着我们要想象下,当我们触摸手机来滑动快速索引的时候,控件变化的原理,在这里最重要的一点就是计算出我们触摸手机时,当前位置的索引(通过当前触摸手机所在的Y坐标除以SlideBar的总高度得出触摸位置所占等分,然后乘以字符的总个数得出当前索引),并有个监听回调提供出去,然后再在画字符的时候根据当前触摸的索引位置来画出触摸时的效果,这样A~Z快速索引自定义控件原理就算基本完成了,然后获取获取手机联系人通过监听回调的索引的字符与联系人首字母的字符做匹配就可以实现联系人的快速索引了。
理解了其原理实现起来就简单了,仔细观察QQ通讯录的快速索引,会发现它的控件正常(非触摸)时和触摸时用的是两张图片切换,不过实现原理也一样啦,只不过省掉了话字母那一段流程,改成画图片而已。还有,我看到Miui系统的自带联系人快速索引效果也蛮好看的,它是已一个圆形背景来标识当前选中字母所在位置的。
下面是最近写的一个A~Z快速索引的效果,那个圆形背景风格的跟Miui的还是有点区别,滑动时非平滑滑动,暂时有四种风格,后续想到其他风格的可能会再添加,并且文本的字体大小,颜色,背景都可以自己随意设置。
先看下效果图:
快速索引控件核心实现代码如下:
/** * A~Z快速索引 * @author Jenly */ public class SlideBar extends View{ /** 画笔 */ private Paint paint = new Paint(); /** 选中的字母索引 */ private int index = -1; /** 字母默认颜色 */ private int defaultColor = Color.BLACK; /** 字母选中颜色 */ private int chooseColor = Color.MAGENTA; /** 选中背景颜色 */ private int chooseBackgroundColor = Color.LTGRAY; /** 是否触摸 */ private boolean isTouch; /** 字母字体大小 */ private int textSize = 16; /** 字母改变监听 */ private OnTouchLetterChangeListenner onTouchLetterChangeListenner; /** 字母数组 */ public static String[] letters = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" ,"#"}; private STYLE chooseStyle = STYLE.DEFAULT; /** * 选中时背景风格 */ public enum STYLE { /** * 默认:椭圆全背景 */ DEFAULT, /** * 无 */ NONE, /** * 圆形 */ CIRCLE, /** * 拉伸 */ STRETCH } public SlideBar(Context context) { super(context); } public SlideBar(Context context, AttributeSet attrs) { super(context, attrs); } public SlideBar(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } /** * 设置字母默认色 * @param color */ public void setDefaultColor(int color){ this.defaultColor = color; } /** * 设置字母选中色 * @param color */ public void setChooseColor(int color){ this.chooseColor = color; } /** * 设置选中时控件的背景色 * @param color */ public void setChooseBacegroundColor(int color){ this.chooseBackgroundColor = color; } /** * 设置选中时控件的风格 * @param color */ public void setChooseStyle(STYLE style){ this.chooseStyle = style; } /** * 文本字体大小 单位:dp * @param size */ public void setTextSize(int size){ this.textSize = size; } /** * 设置字母改变回调监听 * @param onTouchLetterChangeListenner */ public void setOnTouchLetterChangeListenner(OnTouchLetterChangeListenner onTouchLetterChangeListenner){ this.onTouchLetterChangeListenner = onTouchLetterChangeListenner; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); int width = getWidth(); int height = getHeight(); //字母的个数 int len = letters.length; //单个字母的高度 int singleHeight = height/(len); if(isTouch && chooseBackgroundColor!=Color.TRANSPARENT && chooseStyle!=STYLE.NONE){ //触摸时画出背景色 paint.setAntiAlias(true); paint.setColor(chooseBackgroundColor); if(chooseStyle == STYLE.CIRCLE){//选中 圆形背景效果 float maxVaule = Math.max(width, singleHeight); float minVaule = Math.min(width, singleHeight); canvas.drawArc(new RectF((maxVaule-minVaule)/2, singleHeight*(index), singleHeight+(maxVaule-minVaule)/2, singleHeight*(index)+singleHeight), 0, 360,true, paint); }else if(chooseStyle == STYLE.STRETCH){//选中背景拉伸效果 canvas.drawArc(new RectF(0, 0, width, singleHeight*index), 0, 360,true, paint); }else{//默认:全椭圆背景效果 canvas.drawArc(new RectF(0, 0, width, singleHeight), 180, 180,true, paint); canvas.drawRect(new RectF(0, singleHeight/2, width, height-singleHeight/2), paint); canvas.drawArc(new RectF(0, height-singleHeight, width, height), 0, 180,true, paint); } } //画字母 for(int i=0;i<len;i++){ // 设置字体格式 paint.setTypeface(Typeface.DEFAULT); paint.setTextAlign(Align.CENTER); // 抗锯齿 paint.setAntiAlias(true); // 设置字体大小 paint.setTextSize(DisplayUtils.dip2px(getContext(),textSize)); if(i == index){//选中时的画笔颜色 paint.setColor(chooseColor); }else{//未选中时的画笔颜色 paint.setColor(defaultColor); } if(isTouch){//触摸时设为粗体字 paint.setFakeBoldText(true); }else{ paint.setFakeBoldText(false); } //要画的字母的x,y坐标 float x = width/2; float y = singleHeight*(i+1)- paint.measureText(letters[i])/2; //画字母 canvas.drawText(letters[i], x, y, paint); //重置画笔 paint.reset(); } } @Override public boolean dispatchTouchEvent(MotionEvent event) { //当前选中字母的索引 final int index = (int)(event.getY()/getHeight() * letters.length); //老的索引 int oldIndex = this.index; switch (event.getAction()) { case MotionEvent.ACTION_DOWN: isTouch = true; if(index!=oldIndex && index>=0 && index<letters.length){ this.index = index; if(onTouchLetterChangeListenner!=null){//监听回调 onTouchLetterChangeListenner.onTouchLetterChange(isTouch, letters[index]); } invalidate(); } break; case MotionEvent.ACTION_MOVE: isTouch = true; if(index!=oldIndex && index>=0 && index<letters.length){ this.index = index; if(onTouchLetterChangeListenner!=null){//监听回调 onTouchLetterChangeListenner.onTouchLetterChange(isTouch, letters[index]); } invalidate(); } break; case MotionEvent.ACTION_UP: isTouch = false; if(index>=0 && index<letters.length){ if(onTouchLetterChangeListenner!=null){//监听回调 onTouchLetterChangeListenner.onTouchLetterChange(isTouch, letters[index]); } } this.index = -1; invalidate(); break; default: break; } return true; } /** * 字母改变监听接口 */ public interface OnTouchLetterChangeListenner { void onTouchLetterChange(boolean isTouch, String letter); } }
关于作者
Name: Jenly
Email: jenly1314@gmail.com
Email: jenly1314@vip.qq.com
Github: github.com/jenly1314