因项目需要,有重新写了一个获取手机联系人模块,再此记录一下,看效果图:
如图中所示,我们本篇文章要实现的有:
1、自定义view——–字母索引列表view
2、listview数据的展示
3、查询本地联系人的相关信息,如姓名、电话号
4、6.0权限适配
由上面的效果图,我们来分析实现步骤:
1、自定义一个字母索引view
2、写一个listview,还有适配器adapter
3、通过Cursor获取本地的联系人数据,添加进listview中
4、实现字母左侧滑动,listview也跟着滑动,同事listview滑动,字母列表也实现滑动
一、自定义索引列表
1、就是一个自定义view,效果是当我们滑动到某个字母时当前字母变为白色,当前字母背景为蓝色,所以需要两个画笔,一个画字母,一个画背景:
public class SpellsSortView extends View{
/*绘制的列表导航字母*/
private String spells[]= {"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 Paint spellPaint;
//字母背景画笔
private Paint spellbgPaint;
/*每一个字母的宽度*/
private int itemWidth;
/*每一个字母的高度*/
private int itemHeight;
/*手指按下的字母索引*/
private int touchIndex = 0;
/*手指按下的字母改变接口*/
private onWordsChangeListener listener;
public SpellsSortView(Context context) {
super(context);
}
public SpellsSortView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public SpellsSortView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
2、初始化字母画笔,背景画笔及设置字母大小
//进行一些初始化操作
private void init() {
//初始化字母画笔
spellPaint = new Paint();
spellPaint.setColor(Color.parseColor("#F7F7F7"));
spellPaint.setAntiAlias(true);
spellPaint.setTextSize(40);
spellPaint.setTypeface(Typeface.DEFAULT_BOLD);
//初始化字母背景画笔
spellbgPaint = new Paint();
spellbgPaint.setAntiAlias(true);
spellbgPaint.setColor(Color.parseColor("#1dcdef"));
}
3、我们知道要字母,我们首先要知道字母的宽高,所以需要重写Onmeasue();如下:
//测量每个字母的宽高
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
itemWidth = getMeasuredWidth();
//使得边距好看一些
int height = getMeasuredHeight() - 10;
itemHeight = height / 27;//spells.length 总27个字母,均匀分布
}
4、接下来就是绘制字母及其背景了:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (int i = 0; i <spells.length ; i++) {
//判断是不是我们按下的当前字母,让字母显示为白色,其他的为灰色
if (touchIndex==i){
//绘制文字圆形背景
canvas.drawCircle(itemWidth / 2, itemHeight / 2 + i * itemHeight, 23, spellbgPaint);
spellPaint.setColor(Color.WHITE);
}else {
spellPaint.setColor(Color.GRAY);
}
//获取文字的宽高
Rect rect = new Rect();
spellPaint.getTextBounds(spells[i], 0, 1, rect);
int wordWidth = rect.width();
//绘制字母
float wordX = itemWidth / 2 - wordWidth / 2;
float wordY = itemWidth / 2 + i * itemHeight;
canvas.drawText(spells[i], wordX, wordY, spellPaint);
}
}
5、就是当滑动到某个字母时让其变色,而这个字母我们给的是touchIndex来指定,所以我们需要在ontouch事件里对touchIndex进行赋值,然后重新绘制。
/**
* 当手指触摸按下的时候改变字母背景颜色
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
float y = event.getY();
//获得我们按下的是那个索引(字母)
int index = (int) (y / itemHeight);
if (index != touchIndex)
touchIndex = index;
//重新绘制
invalidate();
break;
case MotionEvent.ACTION_UP:
//手指抬起,不做任何操作
break;
}
return true;
}
这样,我们就完成了其基本功能,然后再xml里把布局写上即可
二、写一个listview,还有适配器adapter 这个就比较简单,在布局中加入listview,并且写一个adapter就好了,比较简单就不在这里写了,可以去看我的demo
三、通过Cursor获取本地的联系人数据,添加进listview中前提,需要在manifest中添加读取联系人的权限
String[] cols = {ContactsContract.PhoneLookup.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone.NUMBER};
Cursor cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
cols, null, null, null);
for (int i = 0; i < cursor.getCount(); i++) {
cursor.moveToPosition(i);
// 取得联系人名字
int nameFieldColumnIndex = cursor.getColumnIndex(ContactsContract.PhoneLookup.DISPLAY_NAME);
int numberFieldColumnIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
String name = cursor.getString(nameFieldColumnIndex);
String number = cursor.getString(numberFieldColumnIndex);
Person person=new Person();
person.setName(name);
person.setUserphone(number);
list.add(person);
}
四、实现字母左侧滑动,listview也跟着滑动,同事listview滑动,字母列表也实现滑动
要实现listview滑动,同时字母列表也滑动,我们常用的方式就是写一个接口,然后这面实现接口,就能实现两个类之间的联动了,如下:首先在SpellsSortView里定义接口:
/*手指按下了哪个字母的回调接口*/
public interface onWordsChangeListener {
void wordsChange(String words);
}
/*设置手指按下字母改变监听*/
public void setOnWordsChangeListener(onWordsChangeListener listener) {
this.listener = listener;
}
然后在onTouch时调用方法:
/**
* 当手指触摸按下的时候改变字母背景颜色
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
float y = event.getY();
//获得我们按下的是那个索引(字母)
int index = (int) (y / itemHeight);
if (index != touchIndex)
touchIndex = index;
//防止数组越界
if (listener != null && 0 <= touchIndex && touchIndex <= spells.length - 1) {
//回调按下的字母
listener.wordsChange(spells[touchIndex]);
}
//重新绘制
invalidate();
break;
case MotionEvent.ACTION_UP:
//手指抬起,不做任何操作
break;
}
return true;
}
然后让列表随着字母所以滑动就比较简单了,
/**
* @param words 首字母
*/
private void updateListView(String words) {
for (int i = 0; i < list.size(); i++) {
String headerWord = list.get(i).getHeaderWord();
//将手指按下的字母与列表中相同字母开头的项找出来
if (words.equals(headerWord)) {
//将列表选中哪一个
lv_list.setSelection(i);
//找到开头的一个即可
return;
}
}
}
大致思路就是这样的,具体的可以看我的demo,本篇也参考网上的一些资料,本着分享的精神,希望大家能学到自己想要的知识。
可以去这里下载demo,没有cb的可以加我qq2145228494
http://download.csdn.net/download/ali18510953445/10213819