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

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

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

一、效果:我们看到很多软件的通讯录在右侧都有一个字母索引功能,像微信,小米通讯录,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 就能够实现此功能,通过效果图可以看带,当触摸这块区域的时候,会d出一个悬浮类似 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],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,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"?><@R_212_3419@ xmlns:androID="http://schemas.androID.com/apk/res/androID"> <item>  <shape>   <solID androID:color="#88000000"/>   <corners androID:radius="5dp"/>  </shape> </item></@R_212_3419@>

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

总结

以上是内存溢出为你收集整理的Android自定义View实现通讯录字母索引(仿微信通讯录)全部内容,希望文章能够帮你解决Android自定义View实现通讯录字母索引(仿微信通讯录)所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1147365.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存