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

android快速索引的实现

2016-06-14 11:36 507 查看


从图中可以看出,这种快速索引在客户端的运用非常多,例如:快速检索城市,快速检索联系人等。接下来就来看看如何实现这种效果吧。

画字母

        要实现这个效果, 先得把右侧的字母条画出来, 这里我们写个类, 继承自 View, 由于其内部不需要包含其他布局, 所以继承 View 即可, 无需继承 ViewGroup.public class QuickIndexBar extends View {
private static final String TAG = "TAG";
private static final String[] LETTERS = 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 mPaint;

public interface OnLetterChangeListener{
void OnLetterChange(String letter);
}
public QuickIndexBar(Context context) {
this(context, null);
}
public QuickIndexBar(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public QuickIndexBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// 初始化画笔
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(Color.WHITE);
mPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 12f, getResources().getDisplayMetrics()));
mPaint.setTypeface(Typeface.DEFAULT_BOLD);
}
}


既然要画字母, 就要有画笔, 这里在构造方法里完成画笔的初始化, 创建一个抗锯齿, 颜色为白色, 大小12sp, 粗体的画笔. 有了画笔, 就要开始画了, 画法如图所示。



        这里面要注意的是, 使用 Canvas 画文字的时候, 是从左下角开始的.

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mHeight = getMeasuredHeight();
mCellHeight = mHeight * 1.0f / LETTERS.length;
mCellWidth = getMeasuredWidth();
}
@Override
protected void onDraw(Canvas canvas) {
// 绘制字母
for (int i = 0; i < LETTERS.length; i++) {
String text = LETTERS[i];
// 求x坐标
int x = (int) (mCellWidth / 2.0f - mPaint.measureText(text) / 2.0f);
// 求y坐标
// 格子高度的一半 + 文字高度的一半 + 其上边所有格子高度
Rect bounds = new Rect();
mPaint.getTextBounds(text, 0, text.length(), bounds);
int y = (int) (mCellHeight / 2.0f + bounds.height() / 2.0f + mCellHeight * i);
canvas.drawText(text, x, y, mPaint);
}
}

        这样一来, 字母就画出来了, 如果想要更自由一些的话, 可以使用自定义属性传入字体颜色. 

触摸事件和回调

        界面效果有了, 接下来就是处理触摸事件以及回调了, 处理触摸事件肯定是重写 onTouchEvent 方法了, 回调的话, 定义一个回调接口, 提供 get/set 方法, 在 onTouchEvent 相应的位置调用. onTouchEvent 代码如下:@Override
public boolean onTouchEvent(MotionEvent event) {
switch (MotionEventCompat.getActionMasked(event)) {
case MotionEvent.ACTION_DOWN:
// 根据y值获取当前触摸到的字母
float y = event.getY();
int index = (int) (y / mCellHeight);
// 如果字母索引发生变化
if(index != touchIndex){
if(index >= 0 && index < LETTERS.length){
Log.d(TAG, LETTERS[index]);
if(mLetterChangeListener != null){
// 执行回调
mLetterChangeListener.OnLetterChange(LETTERS[index]);
}
}
touchIndex = index;
}
break;
case MotionEvent.ACTION_MOVE:
// 根据y值获取当前触摸到的字母
int i = (int) (event.getY() / mCellHeight);
// 如果字母索引发生变化
if(i != touchIndex){
if(i >= 0 && i < LETTERS.length){
Log.d(TAG, LETTERS[i]);
if(mLetterChangeListener != null){
mLetterChangeListener.OnLetterChange(LETTERS[i]);
}
}
touchIndex = i;
}
break;
case MotionEvent.ACTION_UP:
// 恢复默认索引值
touchIndex = -1;
break;
default:
break;
}
invalidate();
return true;
}


回调接口:
public interface OnLetterChangeListener{
void OnLetterChange(String letter);
}
// 字母变化监听
private OnLetterChangeListener mLetterChangeListener;
public OnLetterChangeListener getLetterChangeListener() {
return mLetterChangeListener;
}
public void setLetterChangeListener(
OnLetterChangeListener mLetterChangeListener) {
this.mLetterChangeListener = mLetterChangeListener;
}


ListView 的处理


首先我们要获取一个所有名字的集合, 并且对它按照拼音顺序排序.
private void fillAndSort(ArrayList<Friend> names) {
for (int i = 0; i < NAMES.length; i++) {
names.add(new Friend(NAMES[i]));
}
Collections.sort(names);
}
Friend 类如下:
public class Friend implements Comparable<Friend>{
private String name;
private String pinyin;
public Friend(String name) {
super();
this.name = name;
// 获取拼音
pinyin = PinyinUtils.getPinyin(name);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPinyin() {
return pinyin;
}
public void setPinyin(String pinyin) {
this.pinyin = pinyin;
}
@Override
public int compareTo(Friend another) {
return pinyin.compareTo(another.getPinyin());
}
}
        那么接下来就是 ListView 的 Adapter 了, 这里要注意一点就是, 相同字母开头的名字, 只有第一个显示, 其他的不显示.
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if(convertView == null){
view = View.inflate(mContext, R.layout.item_list, null);
}
ViewHolder mViewHolder = ViewHolder.getHolder(view);
Friend friend = names.get(position);
// 跟上一个进行比较,如果不同,则显示。
String letter = null;
String currentLetter = friend.getPinyin().charAt(0) + "";
if(position == 0){
// 第一个人直接显示
letter = currentLetter;
}else {
// 获取上一个人的拼音
String preLetter = names.get(position - 1).getPinyin().charAt(0) + "";
if(!TextUtils.equals(preLetter, currentLetter)){
letter = currentLetter;
}
}
mViewHolder.mIndex.setVisibility(letter == null ? View.GONE : View.VISIBLE);
if(letter != null){
mViewHolder.mIndex.setText(letter);
}
mViewHolder.mName.setText(friend.getName());
return view;
}

每个 item 的布局如下:<?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="40dp"
android:background="#555555"
android:gravity="center_vertical"
android:paddingLeft="20dp"
android:visibility="gone"
android:text="A"
android:textColor="#ffffff"
android:textSize="20sp" />
<TextView
android:id="@+id/tv_name"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center_vertical"
android:paddingLeft="20dp"
android:text="宋江"
android:textColor="#000000"
android:textSize="22sp" />
</LinearLayout>        也就是说, 其实每个条目都是有个字母索引, 有个名字, 只是首字母相同的名字, 只有第一个显示索引。最后就是在索引条上滑动的时候移动到 ListView 相应的位置了, 这个就是实现它提供的回调:
QuickIndexBar mQuickIndexBar = (QuickIndexBar) findViewById(R.id.quickIndex);
mQuickIndexBar.setLetterChangeListener(new OnLetterChangeListener() {
@Override
public void OnLetterChange(String letter) {
Utils.showToast(getApplicationContext(), letter);
// 执行ListView的定位方法
for (int i = 0; i < names.size(); i++) {
Friend friend = names.get(i);
String l =friend.getPinyin().charAt(0) + "";
if(TextUtils.equals(letter, l)){
// 中断循环,快速定位
mListView.setSelection(i);
break;
}
}

}
});
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android 快速索引