自定义控件之A-Z快速检索QuickIndexBar

来源:互联网 发布:商城建站java 编辑:程序博客网 时间:2024/05/01 12:36

---------快速检索--------------
1.应用场景:联系人,好友列表,商品等列表的快速定位和搜索
2.实现逻辑:
a.右边是自定义QuickIndexBar,它能获取触摸它的时候当前所触摸到的字母;
 绘制文本x坐标: width/2;
 绘制文本y坐标: 格子高度的一半 + 文本高度的一半 + position*格子高度
 计算触摸点对应的字母:根据触摸点的y坐标除以cellHeight,得到的值就是字母对应的索引;
 
b.左边是listview,它根据当前触摸的字母,去自己列表找首字母和触摸字母相同的那个
item,然后让item放置到屏幕顶端(setSelection(position));

c.需要用到获取汉字的拼音,借助类库pinyin4j.jar实现;

QuickIndexBar:

/* *  @Copyright (c) tianchenglin *  @Author TCL *  @Date 2016.6.22 */package com.study.tcl.quickindex.view;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.view.View;/** * Created by TCL on 2016/6/22. */public class QuickIndexBar extends View {    private String[] indexArr = {"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;    private int mWidth;    private int mHeight;    float mSingleLetterHeight;    private onTouchLetterListener mOnTouchLetterListener;//按住哪个字符的监听    private int mLastLetterIndex = -1;//最后一次按住的字符    public QuickIndexBar(Context context) {        super(context);        init();    }    public QuickIndexBar(Context context, AttributeSet attrs) {        super(context, attrs);        init();    }    public QuickIndexBar(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        init();    }    public void setOnTouchLetterListener(onTouchLetterListener onTouchLetterListener) {        mOnTouchLetterListener = onTouchLetterListener;    }    private void init() {        mPaint = new Paint();        mPaint.setAntiAlias(true);//抗锯齿        mPaint.setTextSize(20);        mPaint.setTextAlign(Paint.Align.CENTER);//设置文本的起点是文字边框底边的中心    }    @Override    protected void onDraw(Canvas canvas) {        for (int i = 0; i < indexArr.length; i++) {            float xPosition = mWidth / 2;//要画的x坐标//            float yPosition = mSingleLetterHeight * i + mSingleLetterHeight;//要画的y坐标            //y坐标 = 单个字符高度/2+文本高度/2+第几个字符            float yPosition = mSingleLetterHeight / 2 + mPaint.measureText(indexArr[i], 0, 1) / 2 + i *                    mSingleLetterHeight;//            //字符按下变色//            if (i == mLastLetterIndex) {//                mPaint.setColor(Color.TRANSPARENT);//                canvas.drawText(indexArr[i], xPosition, yPosition, mPaint);//            }            mPaint.setColor(i == mLastLetterIndex ? Color.WHITE : Color.RED);            canvas.drawText(indexArr[i], xPosition, yPosition, mPaint);        }        super.onDraw(canvas);    }    @Override    public boolean onTouchEvent(MotionEvent event) {        switch (event.getAction()) {            case MotionEvent.ACTION_MOVE:            case MotionEvent.ACTION_DOWN:                this.setBackgroundColor(Color.BLUE);                float y = event.getY();                int index = (int) (y / mSingleLetterHeight);//得到字符对应的索引                if (mLastLetterIndex != index) {                    //安全性检查                    if (index >= 0 && index < indexArr.length) {                        if (mOnTouchLetterListener != null) {                            mOnTouchLetterListener.onTouchLetter(indexArr[index]);                        }                    }                    Log.i("index", index + "");                    Log.i("letter", indexArr[index]);                }                mLastLetterIndex = index;                break;            case MotionEvent.ACTION_UP:                this.setBackgroundColor(Color.WHITE);                //重置                mLastLetterIndex = -1;                break;        }        invalidate();//引起重绘        return true;//自己处理    }    public interface onTouchLetterListener {        void onTouchLetter(String letter);    }    @Override    protected void onSizeChanged(int w, int h, int oldw, int oldh) {        super.onSizeChanged(w, h, oldw, oldh);        mWidth = getMeasuredWidth();//获取QuickIndexBar宽度        mHeight = getMeasuredHeight();//获取QuickIndexBar高度        mSingleLetterHeight = getMeasuredHeight() * 1f / indexArr.length;//获取一个字符所占高度    }}

MainActivity:

/* *  @Copyright (c) tianchenglin *  @Author TCL *  @Date 2016.6.22 */package com.study.tcl.quickindex;import android.app.Activity;import android.os.Bundle;import android.os.Handler;import android.util.Log;import android.view.View;import android.view.Window;import android.widget.ListView;import android.widget.TextView;import com.study.tcl.quickindex.adapter.MyListAdapter;import com.study.tcl.quickindex.domain.Friend;import com.study.tcl.quickindex.utils.PinYinUtils;import com.study.tcl.quickindex.view.QuickIndexBar;import java.util.ArrayList;import java.util.Collections;import java.util.List;public class MainActivity extends Activity {    private QuickIndexBar mQuickIndexBar;    private ListView mListView;    private List<Friend> friends;    private TextView mCurrentLetter;    private Handler mHandler = new Handler();    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        requestWindowFeature(Window.FEATURE_NO_TITLE);        setContentView(R.layout.activity_main);        mQuickIndexBar = (QuickIndexBar) findViewById(R.id.quickIndexBar);        mListView = (ListView) findViewById(R.id.listView);        mCurrentLetter = (TextView) findViewById(R.id.currentLetter);        //1.准备数据        fillList();        //2.对集合进行排序        Collections.sort(friends);        //3.设置adapter        mListView.setAdapter(new MyListAdapter(this, friends));        mQuickIndexBar.setOnTouchLetterListener(new QuickIndexBar.onTouchLetterListener() {            @Override            public void onTouchLetter(String letter) {//                Log.e("letter", letter);                //根据当前触摸的字母,去集合中找哪个item                for (int i = 0; i < friends.size(); i++) {                    String firstLetter = friends.get(i).getPinyin().charAt(0) + "";                    if (letter.equals(firstLetter)) {                        //将当前item放到屏幕顶端                        mListView.setSelection(i);                        break;//找到第一个就行了                    }                }                //显示当前显示的字母                mCurrentLetter.setVisibility(View.VISIBLE);                mCurrentLetter.setText(letter);                //先移除之前的任务                mHandler.removeCallbacksAndMessages(null);                mHandler.postDelayed(new Runnable() {                    @Override                    public void run() {                        mCurrentLetter.setVisibility(View.GONE);                    }                }, 1500);            }        });        Log.e("pinyin", PinYinUtils.getPinYin("田成琳"));    }    private void fillList() {        friends = new ArrayList<Friend>();        // 虚拟数据        friends.add(new Friend("李伟"));        friends.add(new Friend("张三"));        friends.add(new Friend("阿三"));        friends.add(new Friend("阿四"));        friends.add(new Friend("段誉"));        friends.add(new Friend("段正淳"));        friends.add(new Friend("张三丰"));        friends.add(new Friend("陈坤"));        friends.add(new Friend("林俊杰1"));        friends.add(new Friend("陈坤2"));        friends.add(new Friend("王二a"));        friends.add(new Friend("林俊杰a"));        friends.add(new Friend("张四"));        friends.add(new Friend("林俊杰"));        friends.add(new Friend("王二"));        friends.add(new Friend("王二b"));        friends.add(new Friend("赵四"));        friends.add(new Friend("杨坤"));        friends.add(new Friend("赵子龙"));        friends.add(new Friend("杨坤1"));        friends.add(new Friend("李伟1"));        friends.add(new Friend("宋江"));        friends.add(new Friend("宋江1"));        friends.add(new Friend("李伟3"));    }}

MyListAdapter:

/* *  @Copyright (c) tianchenglin *  @Author TCL *  @Date 2016.6.23 */package com.study.tcl.quickindex.adapter;import android.content.Context;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.TextView;import com.study.tcl.quickindex.R;import com.study.tcl.quickindex.domain.Friend;import com.study.tcl.quickindex.utils.PinYinUtils;import java.util.List;/** * Created by TCL on 2016/6/23. */public class MyListAdapter extends BaseAdapter {    private List<Friend> mFriends;    private Context mContext;    public MyListAdapter(Context context, List<Friend> friends) {        mFriends = friends;        mContext = context;    }    @Override    public int getCount() {        return mFriends.size();    }    @Override    public Object getItem(int position) {        return mFriends.get(position);    }    @Override    public long getItemId(int position) {        return position;    }    @Override    public View getView(int position, View convertView, ViewGroup parent) {        ViewHolder holder;        if (convertView == null) {            convertView = View.inflate(mContext, R.layout.adapter_friend, null);            holder = new ViewHolder();            holder.tv_letter = (TextView) convertView.findViewById(R.id.tv_letter);            holder.tv_name = (TextView) convertView.findViewById(R.id.tv_name);            convertView.setTag(holder);        } else {            holder = (ViewHolder) convertView.getTag();        }        Friend friend = mFriends.get(position);        String currentWord = PinYinUtils.getPinYin(friend.getName()).charAt(0) + "";//此处注意异常        if (position > 0) {            //获取上一个item首字母            String lastWord = mFriends.get(position - 1).getPinyin().charAt(0) + "";            //拿当前的首字母和上一个比较            if (currentWord.equals(lastWord)) {                //说明首字母相同                holder.tv_letter.setVisibility(View.GONE);            } else {                holder.tv_letter.setVisibility(View.VISIBLE);                holder.tv_letter.setText(currentWord);            }        } else {            holder.tv_letter.setVisibility(View.VISIBLE);            holder.tv_letter.setText(currentWord);        }        holder.tv_name.setText(friend.getName());        return convertView;    }    static class ViewHolder {        TextView tv_letter;        TextView tv_name;    }}
PinyinUtils:

/* *  @Copyright (c) tianchenglin *  @Author TCL *  @Date 2016.6.23 */package com.study.tcl.quickindex.utils;import android.text.TextUtils;import net.sourceforge.pinyin4j.PinyinHelper;import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;/** * Created by TCL on 2016/6/23. */public class PinYinUtils {    /**     * 获取文字拼音,会消耗一定资源,不应该被频繁调用     *     * @param chinese     * @return     */    public static String getPinYin(String chinese) {        if (!TextUtils.isEmpty(chinese)) {            //1.由于只能对单个汉子进行转化,所以需要将字符串转化成字符数组,然后对每个字符进行转化,最后拼接            char[] chars = chinese.toCharArray();            StringBuilder sb = new StringBuilder();            HanyuPinyinOutputFormat hanyuPinyinOutputFormat = new HanyuPinyinOutputFormat();            hanyuPinyinOutputFormat.setCaseType(HanyuPinyinCaseType.UPPERCASE);//设置转化的拼音是大写字母            hanyuPinyinOutputFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);//没有声调//            hanyuPinyinOutputFormat.setVCharType();            for (int i = 0; i < chars.length; i++) {                //2.过滤空格                if (Character.isSpaceChar(chars[i])) {                    continue;                }                //3.判断是否是汉字,汉字占两个字节,一个字节范围是-128~127                if (chars[i] > 127) {                    //可能是汉字                    try {                        String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(chars[i], hanyuPinyinOutputFormat);                        if (pinyinArray != null) {                            sb.append(pinyinArray[0]);//取第0个                        } else {                            //没有找到拼音,可能不是汉字,则忽略                        }                    } catch (BadHanyuPinyinOutputFormatCombination badHanyuPinyinOutputFormatCombination) {                        badHanyuPinyinOutputFormatCombination.printStackTrace();                        //说明转化失败,不是汉字,则忽略                    }                } else {                    //这些字符能排序,不能获取拼音                    sb.append(chars[i]);                }            }            return sb.toString();        }        return null;    }}

Bean(Friend):

/* *  @Copyright (c) tianchenglin *  @Author TCL *  @Date 2016.6.23 */package com.study.tcl.quickindex.domain;import com.study.tcl.quickindex.utils.PinYinUtils;/** * Created by TCL on 2016/6/23. */public class Friend implements Comparable<Friend> {    private String name;    private String pinyin;    public Friend(String name) {        this.name = name;        //一开始就设置好拼音        setPinyin(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 getPinyin().compareTo(another.getPinyin());    }}

activity_main:

<?xml version="1.0" encoding="utf-8"?><!--  ~  @Copyright (c) tianchenglin  ~  @Author TCL  ~  @Date 2016.6.22  --><RelativeLayout    xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context="com.study.tcl.quickindex.MainActivity">    <ListView        android:id="@+id/listView"        android:layout_width="match_parent"        android:layout_height="match_parent">    </ListView>    <!--android:background="#B51421"-->    <com.study.tcl.quickindex.view.QuickIndexBar        android:id="@+id/quickIndexBar"        android:layout_width="30dp"        android:layout_height="match_parent"        android:layout_alignParentRight="true">    </com.study.tcl.quickindex.view.QuickIndexBar>    <TextView        android:id="@+id/currentLetter"        android:layout_width="100dp"        android:layout_height="100dp"        android:layout_centerInParent="true"        android:background="@drawable/bg"        android:gravity="center"        android:textColor="#ffffff"        android:visibility="gone"        android:textSize="50dp"/></RelativeLayout>

运行结果:





0 0
原创粉丝点击