Android自定义View实现通讯录字母索引(仿微信通讯录)

一、效果:我们看到很多软件的通讯录在右侧都有一个字母索引功能,像微信,小米通讯录,QQ,还有美团选择地区等等。这里我截了一张美团选择城市的图片来看看;

我们今天就来实现图片中右侧模块的索引功能,包括触摸显示以选中的索引字母。这里我的UI界面主要是参照微信的界面来实现,所以各位也可以对照微信来看看效果,什么都不说了,只有效果图最具有说服力!

二、分析:

我们看到这样的效果我们心理都回去琢磨,他是如何实现的;

首先,它肯定是通过自定义 View 来实现的,因为 Android 没有提供类似这样的控件、那么接下来就是如何自定义我们的 View ,我们知道自定义 View 最最主要的两个方法就是 onDraw(Canvas canvas)和

onMeasure(int widthMeasureSpec, int heightMeasureSpec)方法,当然,如果是自定义 ViewGroup 的话就必须实现

onLayout(boolean changed, int left, int top, int right, int bottom) 方法,这里我们显然用自定义 View 就能够实现此功能,通过效果图可以看带,当触摸这块区域的时候,会弹出一个悬浮类似 Toast 的框来显示已经选中的索引内容,所以这里还需要重写View 的onTouchEvent(MotionEvent event)事件,最后就是悬浮框的实现。那么接下来就开始我们编码。

三、编码实现:

我们就按照 View 的执行顺序来实现

1、实现onMeasure(int widthMeasureSpec, int heightMeasureSpec)方法,这个方法的功能是测量出我们的宽和高,具体实现看代码

@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(measureWidth(widthMeasureSpec),measureHeight(heightMeasureSpec)); }

这里定义了两个方法measureWidth( int) 和 measureHeight(int) ,通过方法名可以很清楚的知道,其功能分别是测量宽和高,进去看看是如何测量的。

/** * 测量本身的大小,这里只是测量宽度 * @param widthMeaSpec 传入父View的测量标准 * @return 测量的宽度 */ private int measureWidth(int widthMeaSpec){ /*定义view的宽度*/ int width ; /*获取当前 View的测量模式*/ int mode = MeasureSpec.getMode(widthMeaSpec) ; /* * 获取当前View的测量值,这里得到的只是初步的值, * 我们还需根据测量模式来确定我们期望的大小 * */ int size = MeasureSpec.getSize(widthMeaSpec) ; /* * 如果,模式为精确模式 * 当前View的宽度,就是我们 * 的size ; * */ if(mode == MeasureSpec.EXACTLY){ width = size ; }else { /*否则的话我们就需要结合padding的值来确定*/ int desire = size + getPaddingLeft() + getPaddingRight() ; if(mode == MeasureSpec.AT_MOST){ width = Math.min(desire,size) ; }else { width = desire ; } } mViewWidth = width ; return width ; }

以上是测量宽度的代码,其测量高度的代码,跟测量宽度的代码大致雷同,就不贴出来了,我会在最后附上源码。

2、实现onDraw(Canvas c)方法,这个方法相信大家都非常熟悉,就是把这些索引的内容绘制到 View 上显示出来,包括选中的时候背景颜色的变化;

@Override protected void onDraw(Canvas canvas) { if(mTouched){ canvas.drawColor(0x30000000); } for (int i = 0 ; i < mIndex.length ; i ++){ mPaint.setColor(0xff000000); mPaint.setTextSize(mTextSize * 3.0f / 4.0f); mPaint.setTypeface(Typeface.DEFAULT) ; mPaint.getTextBounds(mIndex[i],0,mIndex[i].length(),mTextBound); float formX = mViewWidth/2.0f - mTextBound.width()/2.0f ; float formY = mTextSize*i + mTextSize/2.0f + mTextBound.height()/2.0f ; canvas.drawText(mIndex[i],formX,formY,mPaint); mPaint.reset(); } }

我来讲一下 onDraw 方法中大致做了什么事,第一,绘制背景颜色,注意不是一上来就绘制,而是等到有手指触摸的时候就绘制背景颜色,第二,就是绘制索引的内容,这里需要根据当前 View 的宽和高来决定绘制内容的大小,和位置。

3、onTouchEvent(MotionEvent event)方法的实现

@Override public boolean onTouchEvent(MotionEvent event) { float y = event.getY() ; int index = (int) (y / mTextSize); if(index >= 0 && index < mIndex.length){ Log.v("zgy","======index======="+index) ; selectItem(index); } if(event.getAction() == MotionEvent.ACTION_MOVE){ mTouched = true ; }else if (event.getAction() == MotionEvent.ACTION_MOVE){ }else { mFloatView.setVisibility(INVISIBLE); mTouched = false ; } invalidate(); /*过滤点其他触摸事件*/ return true; }

代码也相对比较简单,首先获取当前触摸的点,根据点的坐标来获取索引的位置,从而拿到索引的位置。

4、到这里其实就已经实现了我们想要的效果,但是这样我们还是无法运用它,这里就需要定义一个回调接口

/*定义一个回调接口*/ public interface OnIndexSelectListener{ /*返回选中的位置,和对应的索引名*/ void onItemSelect(int position, String value) ; }

回调接口我们放在哪里调用呢,当我们手指按下的时候,这时候其实我们需要确定我们按下的是哪个索引,滑动的时候也是一样,所以,这个没什么好商量的,直接放在onTouchEvent(MotionEvent event)中就可以,

float y = event.getY() ; int index = (int) (y / mTextSize); if(index >= 0 && index < mIndex.length){ Log.v("zgy","======index======="+index) ; selectItem(index); }

selectItem(int)方法中就是执行的回调方法。

5、实现悬浮框显示已经选中的索引内容

这里需要用到 WindowManager 容器,然需要现实的 View 附在这上面的就行,当手指按下的时候,让 View 显示出来,松开不显示就行了

/*设置浮动选中的索引*/ /*获取windowManager*/ mWindowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); /*overly 视图,通过LayoutInflater 获取*/ mFloatView = LayoutInflater.from(getContext()).inflate(R.layout.overlay_indexview,null) ; /*开始让其不可见*/ mFloatView.setVisibility(INVISIBLE); /*转换 高度 和宽度为Sp*/ mOverlyWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,70,getResources().getDisplayMetrics()) ; mOverlyHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,70,getResources().getDisplayMetrics()) ; post(new Runnable() { @Override public void run() { WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(mOverlyWidth,mOverlyHeight, WindowManager.LayoutParams.TYPE_APPLICATION, WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT) ; mWindowManager.addView(mFloatView,layoutParams); } }) ;

同样的道理,如果需要改变显示的内容,就需要在调用回调的位置,为 View 中的 TextView 设置当前的索引内容。

好了此 View 的代码就这么多,

接下来就把引用他的 Xml 和浮动 View 的 Xml 也贴出来,

引用的布局文件

<moon.wechat.view.IndexView android:layout_width="25dp" android:layout_height="match_parent" android:layout_alignParentRight="true"/>

浮动 View 的布局文件

<?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/overly_text" android:layout_width="70dp" android:layout_height="70dp" android:text="A" android:gravity="center" android:background="@drawable/bg_overly_text" android:textSize="40sp" android:textColor="#ffffffff" android:layout_gravity="center"> </TextView>

浮动 View 的背景

<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item> <shape> <solid android:color="#88000000"/> <corners android:radius="5dp"/> </shape> </item> </layer-list>

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持脚本之家!

时间: 2024-09-22 20:54:09

Android自定义View实现通讯录字母索引(仿微信通讯录)的相关文章

Android自定义View系列之Path绘制仿支付宝支付成功动画_Android

前言 使用支付宝付款时,我们可以看到成功或者失败都会有个动画提示,如果我们需要做这样的效果的话,当然,你可以让设计师给你做个GIF,但是我们知道图像比较耗内存的,我们自己可以用代码实现还是代码实现好点吧. 效果 实现方法 首先我们需要了解PathMeasure这个类,这个类我们可以理解为用来管理Path.我们主要看几个方法. PathMeasure(): 构造方法 ,实例化一个对象 PathMeasure(Path path,boolean isClosed):传入Path对象和是否闭合,pat

android仿微信通讯录搜索示例(匹配拼音,字母,索引位置)

前言: 仿微信通讯录搜索功能,通过汉字或拼音首字母找到匹配的联系人并显示匹配的位置 一:先看效果图 字母索引 搜索匹配 二:功能分析 1:汉字转拼音 通讯录汉字转拼音(首个字符当考虑姓氏多音字), 现在转换拼音常见的有pinyin4j和tinypinyin, pinyin4j的功能强大,包含声调多音字,tinypinyin执行快占用内存少, 如果只是简单匹配通讯录,建议使用tinypinyin,用法也很简单这里不详细介绍 拼音类 public class CNPinyin <T extends

界面-Android自定义View画笔颜色改变问题(画笔颜色改变了,但是实际上ABCD这些字母的颜色没变)

问题描述 Android自定义View画笔颜色改变问题(画笔颜色改变了,但是实际上ABCD这些字母的颜色没变) package com.eage.tbw.view; import com.eage.tbw.R; import com.eage.tbw.R.color; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import andro

Android自定义View实现字母导航栏的代码_Android

思路分析: 1.自定义View实现字母导航栏 2.ListView实现联系人列表 3.字母导航栏滑动事件处理 4.字母导航栏与中间字母的联动 5.字母导航栏与ListView的联动 效果图: 首先,我们先甩出主布局文件,方便后面代码的说明 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/re

Android自定义View实现字母导航栏_Android

很多的Android入门程序猿来说对于Android自定义View,可能都是比较恐惧的,但是这又是高手进阶的必经之路,所有准备在自定义View上面花一些功夫,多写一些文章. 思路分析: 1.自定义View实现字母导航栏 2.ListView实现联系人列表 3.字母导航栏滑动事件处理 4.字母导航栏与中间字母的联动 5.字母导航栏与ListView的联动 效果图: 首先,我们先甩出主布局文件,方便后面代码的说明 <!--?xml version="1.0" encoding=&qu

Android自定义View仿支付宝输入六位密码功能_Android

跟选择银行卡界面类似,也是用一个PopupWindow,不过输入密码界面是一个自定义view,当输入六位密码完成后用回调在Activity中获取到输入的密码并以Toast显示密码.效果图如下: 自定义view布局效果图及代码如下: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/

Android自定义View仿IOS圆盘时间选择器

通过自定义view实现仿iOS实现滑动两端的点选择时间的效果 效果图 自定义的view代码 public class Ring_Slide2 extends View { private static final double RADIAN = 180 / Math.PI; private int max_progress; // 设置最大进度 private int cur_progress; //设置锚点1当前进度 private int cur_progress2; //设置锚点2进度 p

Android自定义View实现仿驾考宝典显示分数效果(收藏)

小编最近发现,一些炫酷的view效果,通过需要自定义view和属性动画结合在一起,才能更容易的实现. 实现的效果图如下: 所用的知识有: (1)自定义View中的 path ,主要用来绘制指示块. (2)属性动画-ValueAnimator,并设置属性动画的监听器. (3)根据属性动画是否结束的标志,决定是否绘制分数对应的描述文本内容. 实现步骤: 继承自View,在构造函数中获取自定义属性和初始化操作(初始化画笔) private void obtainAttrs(Context contex

Android自定义View仿支付宝输入六位密码功能

跟选择银行卡界面类似,也是用一个PopupWindow,不过输入密码界面是一个自定义view,当输入六位密码完成后用回调在Activity中获取到输入的密码并以Toast显示密码.效果图如下: 自定义view布局效果图及代码如下: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/

Android自定义View实现字母导航栏的代码

思路分析: 1.自定义View实现字母导航栏 2.ListView实现联系人列表 3.字母导航栏滑动事件处理 4.字母导航栏与中间字母的联动 5.字母导航栏与ListView的联动 效果图: 首先,我们先甩出主布局文件,方便后面代码的说明 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/re