Android实现快速索引详解
来源:互联网 发布:dnf韩服武神改版数据 编辑:程序博客网 时间:2024/06/06 00:34
画字母
要实现这个效果, 先得把右侧的字母条画出来, 这里我们写个类, 继承自 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];
-
- int x = (int) (mCellWidth / 2.0f - mPaint.measureText(text) / 2.0f);
-
-
- 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:
-
- 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:
-
- 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);
-
- 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;
- }
- }
-
- }
- });