您的位置:首页 > 移动开发 > Android开发

关于android实现fastindexbar(快速索引)详解

2016-04-12 15:47 676 查看
首先看下自定义viewfastindex的实现

package cn.yuan.yu.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.support.v4.view.MotionEventCompat;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;

import cn.yuan.yu.R;

/**
* Created by yukuo on 2016/4/7.
* 这是一个自定义的一个快速索引的自定义的控件
*/
public class FastIndexBar extends View {
/**
* 上下文
*/
private Context context;
/**
* 宽度
*/
private int Width;
/**
* 高度
*/
private int Height;
/**
* 字体的颜色
*/
private int TextColor;
/**
* 字体大小
*/
private int TextSize;
/**
* 控件的背景色
*/
private int BackgroundColor;

/**
* 单元格高度
*/
private float cellHeight;
private static final String[] WORDS = new String[]{"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 paint;
//这是一个索引
int index = -1;
//监听器
private OnLetterChangeListener onLetterChangeListener;

/**
* 字母更新监听
*/
public interface OnLetterChangeListener {
/**
* 当手指移动或者按下的时候调用的方法
*
* @param letter
*/
void onLetterChange(String letter);

/**
* 当手指离开这个控件的时候调用的方法
*/
void onUp();
}

public void setOnLetterChangeListener(
OnLetterChangeListener onLetterChangeListener) {
this.onLetterChangeListener = onLetterChangeListener;
}

public FastIndexBar(Context context, AttributeSet attrs) {
this(context, attrs, 0);
this.context = context;
}

public FastIndexBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context = context;
init(attrs, defStyleAttr);
}

/**
* 初始化各种属性
*/
private void init(AttributeSet attrs, int defStyleAttr) {
/**
* 获得我们所定义的自定义样式属性
*/
TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.FastIndexBar, defStyleAttr, 0);
for (int i = 0; i < typedArray.getIndexCount(); i++) {
int attr = typedArray.getIndex(i);
if (attr == R.styleable.FastIndexBar_BackgroundColor) {
BackgroundColor = typedArray.getColor(attr, Color.WHITE);
} else if (attr == R.styleable.FastIndexBar_TextColor) {
TextColor = typedArray.getColor(attr, Color.BLUE);
} else if (attr == R.styleable.FastIndexBar_TextSize) {
TextSize = typedArray.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 10, getResources().getDisplayMetrics()));
}
}
//释放资源
typedArray.recycle();
/**
* 初始化一个画笔
*/
paint = new Paint();
paint.setColor(TextColor);//设置画笔的颜色
paint.setTextSize(TextSize);//设置字体的大小
}

/**
* 绘制
*
* @param canvas
*/
@Override
protected void onDraw(Canvas canvas) {
for (int i = 0; i < WORDS.length; i++) {
String text = WORDS[i];
float x = (int) (Width * 0.5f - paint.measureText(text) * 0.5f);
Rect bounds = new Rect();
// 把矩形对象赋值
paint.getTextBounds(text, 0, text.length(), bounds);
int textHeight = bounds.height();
float y = (int) (cellHeight * 0.5f + textHeight * 0.5 + cellHeight
* i);
// 如果当前绘制的字母和按下的字母索引一样, 用灰色的画笔
//  paint.setColor(i == index ? Color.GRAY : Color.BLACK);
canvas.drawColor(BackgroundColor);
canvas.drawText(text, x, y, paint);
}
}

/**
* 控件的手指触摸事件的监听
*
* @param event
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
float y = -1;
//选择的索引
int currentIndex = -1;
switch (MotionEventCompat.getActionMasked(event)) {
case MotionEvent.ACTION_DOWN://按下的时候
y = event.getY();//获得当时按下的y值
currentIndex = (int) (y / cellHeight);
if (currentIndex >= 0 && currentIndex < WORDS.length) {
// 健壮性处理, 在正常范围内
if (index != currentIndex) {
// 字母的索引发生了变化
if (onLetterChangeListener != null) {
onLetterChangeListener
.onLetterChange(WORDS[currentIndex]);
}
index = currentIndex;
}
}
break;
case MotionEvent.ACTION_MOVE://移动的时候
y = event.getY();
currentIndex = (int) (y / cellHeight);
if (currentIndex >= 0 && currentIndex < WORDS.length) {
// 健壮性处理, 在正常范围内
if (index != currentIndex) {
// 字母的索引发生了变化
if (onLetterChangeListener != null) {
onLetterChangeListener
.onLetterChange(WORDS[currentIndex]);
}
index = currentIndex;
}
}
break;
case MotionEvent.ACTION_UP://离开的时候
index = -1;
if (onLetterChangeListener != null) {
onLetterChangeListener
.onUp();
}
break;
}
invalidate();
return true;
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
//单元格宽度
Width = getMeasuredWidth();
Height = getMeasuredHeight();
//单元格高度
cellHeight = Height * 1.0f / WORDS.length;
}
}

布局如何应用呢?如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<cn.yuan.yu.view.ElasticListView
android:id="@+id/lv_mylistview"
android:layout_width="match_parent"
android:layout_height="match_parent" />

<cn.yuan.yu.view.FastIndexBar
android:id="@+id/fib_demo"
android:layout_width="30dp"
android:layout_height="280dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
app:TextColor="@color/themecolor"
app:TextSize="9sp" />

<TextView
android:id="@+id/tv_tip"
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_centerInParent="true"
android:background="@drawable/text_bg_tip"
android:gravity="center"
android:textColor="@android:color/white"
android:textSize="100sp"
android:visibility="gone" />
</RelativeLayout>

定义这个列表的适配器

package cn.yuan.qi.demomodule.adapter;

import android.content.Context;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import java.util.List;

import cn.yuan.qi.R;
import cn.yuan.yu.bean.PhoneNumber;

/**
* Created by yukuo on 2016/4/12.
*/
public class PhoneNumberAdapter extends BaseAdapter {
private List<PhoneNumber> list;
private Context context;

public PhoneNumberAdapter(Context context, List<PhoneNumber> list) {
this.list = list;
this.context = context;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
MyHolder myHolder;
if (convertView == null) {
myHolder = new MyHolder();
convertView = View.inflate(context, R.layout.item_fastindex, null);
myHolder.textViewname = (TextView) convertView.findViewById(R.id.tv_item_phone_name);
myHolder.textViewphone = (TextView) convertView.findViewById(R.id.tv_item_phone_number);
myHolder.index = (TextView) convertView.findViewById(R.id.tv_index);
convertView.setTag(myHolder);
} else {
myHolder = (MyHolder) convertView.getTag();
}
// 进行分组, 比较上一个拼音的首字母和自己是否一致, 如果不一致, 就显示tv_index
String currentLetter = list.get(position).getPinyin();
String indexStr = null;
if (position == 0) {
// 1. 如果是第一位
indexStr = currentLetter;
} else {
// 获取上一个拼音
String preLetter = list.get(position-1).getPinyin();
if (!TextUtils.equals(currentLetter, preLetter)) {
// 2. 当跟上一个不同时, 赋值, 显示
indexStr = currentLetter;
}
}
myHolder.index.setVisibility(indexStr == null ? View.GONE
: View.VISIBLE);
myHolder.index.setText(indexStr == null ? "" : list.get(position).getPinyin());
myHolder.textViewname.setText(list.get(position).getName());
myHolder.textViewphone.setText(list.get(position).getNumber());
return convertView;
}

@Override
public int getCount() {
return list.size();
}

@Override
public Object getItem(int position) {
return null;
}

@Override
public long getItemId(int position) {
return 0;
}

class MyHolder {
TextView textViewname;
TextView textViewphone;
TextView index;
}
}

条目布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<TextView
android:id="@+id/tv_index"
android:layout_width="match_parent"
android:layout_height="20dp"
android:background="@color/themecolor"
android:gravity="center_vertical"
android:paddingLeft="10dp"
android:text="A"
android:textColor="@android:color/white"
android:textSize="15sp" />

<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal">

<TextView
android:id="@+id/tv_item_phone_name"
android:layout_width="100dp"
android:layout_height="match_parent"
android:layout_marginLeft="15dp"
android:gravity="center_vertical" />

<TextView
android:id="@+id/tv_item_phone_number"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginLeft="50dp"
android:gravity="center_vertical" />
</LinearLayout>

</LinearLayout>

Activity界面业务代码

package cn.yuan.qi.demomodule.activity;

import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import butterknife.Bind;
import cn.yuan.qi.R;
import cn.yuan.qi.common.activity.BaseActivity;
import cn.yuan.qi.common.application.QiApplication;
import cn.yuan.qi.demomodule.adapter.PhoneNumberAdapter;
import cn.yuan.yu.bean.PhoneNumber;
import cn.yuan.yu.utils.GetPhoneData;
import cn.yuan.yu.view.ElasticListView;
import cn.yuan.yu.view.FastIndexBar;

/**
* Created by yukuo on 2016/4/4.
*/
public class FastIndexOfActivity extends BaseActivity {

@Bind(R.id.lv_mylistview)
ElasticListView lvMylistview;
@Bind(R.id.fib_demo)
FastIndexBar fibDemo;
@Bind(R.id.tv_tip)
TextView tvTip;
private PhoneNumberAdapter phoneNumberAdapter;
private List<PhoneNumber> lists;

@Override
public void initdata(Bundle extras) {
//     WeekGridAdapter weekGridAdapter = new WeekGridAdapter(this);
fibDemo.setOnLetterChangeListener(new FastIndexBar.OnLetterChangeListener() {
@Override
public void onLetterChange(String letter) {
tvTip.setText(letter);
tvTip.setVisibility(View.VISIBLE);
if (lists != null) {
for (int i = 0; i < lists.size(); i++) {
if (letter.equals(lists.get(i).getPinyin())) {
lvMylistview.setSelection(i);
return;
}
}
}

}

@Override
public void onUp() {
tvTip.setVisibility(View.GONE);
}
});
GetPhoneData.getPhoneNumberData(this, new GetPhoneData.OnLoadSuccessListener() {

@Override
public void onSuccess(final List<PhoneNumber> list) {
QiApplication.mainHandler.post(new Runnable() {
@Override
public void run() {
lists = list;
// 排序
Collections.sort(list, new Comparator<PhoneNumber>() {
@Override
public int compare(PhoneNumber lhs, PhoneNumber rhs) {
return lhs.getPinyin().compareToIgnoreCase(rhs.getPinyin());
}
});
phoneNumberAdapter = new PhoneNumberAdapter(FastIndexOfActivity.this, list);
lvMylistview.setAdapter(phoneNumberAdapter);
}
});

}

@Override
public void onFailure() {

}
});
}

@Override
public int getContentLayout() {
return R.layout.activity_fastindex;
}

}

用到的工具类和实体

package cn.yuan.yu.utils;

import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.provider.ContactsContract;

import java.util.ArrayList;
import java.util.List;

import cn.yuan.yu.bean.PhoneNumber;

/**
* Created by yukuo on 2016/4/12.
* 这是一个获取手机联系人等信息的工具类
*/
public class GetPhoneData {
public interface OnLoadSuccessListener {
void onSuccess(List<PhoneNumber> list);

void onFailure();
}

/**
* 这是一个返回一个联系人信息列表集合的方法
*
* @param context 上下文
* @return
*/
public static void getPhoneNumberData(final Context context, final OnLoadSuccessListener onLoadSuccessListener) {
new Thread() {
@Override
public void run() {
List<PhoneNumber> list = new ArrayList<PhoneNumber>();
ContentResolver cr = context.getContentResolver();
Cursor cursor = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
if (cursor != null) {
while (cursor.moveToNext()) {
int PhoneName = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
int phoneNumbe = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
PhoneNumber phoneNumber = new PhoneNumber();
//电话号码
phoneNumber.setNumber(cursor.getString(phoneNumbe));
L.i("手机号码", cursor.getString(phoneNumbe));
//名字
phoneNumber.setName(cursor.getString(PhoneName));
L.i("名字", cursor.getString(PhoneName));
list.add(phoneNumber);
}
if (onLoadSuccessListener != null) {
onLoadSuccessListener.onSuccess(list);
}
} else {
if (onLoadSuccessListener != null) {
onLoadSuccessListener.onFailure();
}
}
}
}.start();
}
}

实体

package cn.yuan.yu.bean;

import net.sourceforge.pinyin4j.PinyinHelper;

/**
* Created by yukuo on 2016/4/12.
* 这是一个联系人的实体类
*/
public class PhoneNumber {
private String number;
private String name;
private String email;
/**
* 这是一个存储每个名字首字母的变量
*/
private String pinyin;

public String getNumber() {
return number;
}

public void setNumber(String number) {
this.number = number;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
this.pinyin = getHeadChar(name);

}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

public String getPinyin() {
return pinyin;
}

public void setPinyin(String pinyin) {
this.pinyin = pinyin;
}

/**
* 得到首字母
*
* @param str
* @return
*/
public String getHeadChar(String str) {
String convert = "";
char word = str.charAt(0);
String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(word);
if (pinyinArray != null) {
convert += pinyinArray[0].charAt(0);
} else {
convert += word;
}
return convert.toUpperCase();
}

}

最后的效果图

图片


选中效果


ok祝小伙伴成功吧
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: