android快速索引的实现

来源:互联网 发布:全自动挂机赚钱软件 编辑:程序博客网 时间:2024/06/07 00:09


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


画字母
        要实现这个效果, 先得把右侧的字母条画出来, 这里我们写个类, 继承自 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;                    }                }                            }        });

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 移植9天来月经怎么办 月经迟迟不来该怎么办 lol晋级赛输了怎么办 激素正常的多囊怎么办 右侧输卵管通而不畅怎么办 小该咳嗽老不好怎么办 孩子吓着了怎么办最快 2个月宝宝吓到了怎么办 3个月宝宝吓到了怎么办 宝宝吓着了发烧怎么办 好几个月不遗精怎么办 孕妇吃了黑橄榄怎么办 内膜4mm来月经了怎么办 吃了伟哥没效果怎么办 维a酸乳膏副作用怎么办 颈椎病引起的头晕恶心怎么办 经常头疼怎么办最快最有效 感昌了头晕乏力怎么办 来例假喝啤酒了怎么办 来月经喝啤酒了怎么办 吃的油腻长痘怎么办 兔子拉黑色稀便怎么办 宝宝补钙便秘了怎么办 吃了肾宝片上火怎么办 吃肾宝片就上火怎么办 吃肾宝片后上火怎么办 孕妇吃了扁桃仁怎么办 怀孕吃了扁桃仁怎么办 经期吃了阿胶糕怎么办 10儿童咳嗽有痰怎么办 6岁宝宝咳嗽有痰怎么办 儿童6岁咳嗽有痰怎么办 零号胶囊用多了怎么办 7岁半乳房发育,怎么办 妊娠斑怎么办,能去掉吗 跨域访问被拒绝怎么办 月子里半夜饿了怎么办 5岁儿童包茎该怎么办 6岁儿童包茎该怎么办 1岁半乳房发育,怎么办 4岁智力发育迟缓怎么办