自定义联系人快速索引栏

——每天做一点,温故而知新

看看效果吧
效果
额,我这个为了简单,简单的用了下toast,所以有三秒,有点长.没录到它消失的.大于两M.这不是重点,有兴趣的可以下载代码自己改.来看看这个索引栏栏怎么画的吧.相对于我们前面QQ消息拖动小球http://blog.csdn.net/z8z87878/article/details/51760032这个简单多了,我直接贴代码,看着代码说

/**
 * Created by Root on 2016/6/28.
 */
public class IndexView extends View {

    public static String indexStr[]={"*","#","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 int mHeight;                                  //控件高度
    private int mAvgHeight;                               //字母的平均高度
    private Paint mPaint;                                 //画笔
    private int mWidth;                                   //控件宽度
    private Rect bounds;                                  //字母所在的矩形
    private int mTextHeight;                              //字母高度
    private float mTextWidth;                             //字母宽度

    private int touchIndex = -1;                               //触摸位置

    public IndexView(Context context) {
        this(context,null);
    }

    public IndexView(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public IndexView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        mPaint = new Paint();
        mPaint.setAntiAlias(true);                        //抗锯齿
        mPaint.setDither(true);                           //防抖动
        mPaint.setColor(Color.GRAY);
        mPaint.setTextAlign(Paint.Align.CENTER);          //字坐标为字底部中间
        mPaint.setTypeface(Typeface.DEFAULT_BOLD);        //粗体
        mPaint.setTextSize(context.getResources().getDisplayMetrics().density * 13);
    }


    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) { //测量完成后会调用
        super.onSizeChanged(w, h, oldw, oldh);

        mHeight = getMeasuredHeight();//控件高度
        mWidth = getMeasuredWidth(); //控件宽度

        mAvgHeight = mHeight / indexStr.length ; //字母平均分到的高度

        mTextWidth = mPaint.measureText(indexStr[5]);
        Rect bounds = new Rect(); 
        mPaint.getTextBounds(indexStr[5],0,indexStr[5].length(),bounds);//
        mTextHeight = bounds.height();//假设字母都一样高吧,不要每个都去测量,也差不了多少

        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {


        for (int i = 0; i < indexStr.length; i++) {

            mPaint.setColor( touchIndex == i ? Color.RED : Color.GRAY); //触摸的画红色,默认灰色

            //这里画的x,y是相对于视图的坐标系的.上次自定义的QQ消息拖动小球也是,不过它的视图是手机屏幕,所以看上去相对于手机坐标
            canvas.drawText(indexStr[i],mWidth / 2.0f,mAvgHeight/2.0f + mTextHeight / 2.0f+ mAvgHeight * i,mPaint);
        }//参数1:字母  参数2:横坐标  参数3:纵坐标  参数4:画笔

    }


    private  int tempIndex = -1;
    @Override
    public boolean onTouchEvent(MotionEvent event) {

        switch (event.getAction()){

            case MotionEvent.ACTION_DOWN:

                tempIndex = (int) (event.getY() / mAvgHeight);   //event.getY()视图坐标系,event.getRawY()手机坐标系

                if (tempIndex != touchIndex){//有变化才回调

                    touchIndex = tempIndex;

                    if (mOnIndexChangeListener != null){       //索引栏选中改变接口回调
                        mOnIndexChangeListener.onChange(indexStr[touchIndex]);
                    }
                }

                break;

            case MotionEvent.ACTION_MOVE:

                tempIndex = (int) (event.getY() / mAvgHeight);
                if(tempIndex != touchIndex){
                    touchIndex = tempIndex;

                    if (mOnIndexChangeListener != null){       //索引栏选中改变接口回调
                        mOnIndexChangeListener.onChange(indexStr[touchIndex]);
                    }
                }

                break;

            case MotionEvent.ACTION_UP:

                if (mOnIndexChangeListener != null){
                    mOnIndexChangeListener.onStop();   //停止滑动了.通知listView,防止跟listView滑动冲突
                }
                break;

        }

        invalidate();    //重绘调用onDraw()
        return true;
    }


    public void setTouchIndex(int index){

        touchIndex = index;
        tempIndex = touchIndex;
        invalidate();
    }


    public interface OnIndexChangeListener{

        void  onChange(String str);
        void  onStop();
    }

    public OnIndexChangeListener mOnIndexChangeListener;

    public void setOnIndexChangeListener(OnIndexChangeListener listener){
        mOnIndexChangeListener = listener;

    }

}

注释还行是不是O(∩_∩)O~,说下流程吧,构造函数我们初始化一些参数,然后接着就是onSizeChange了,这里我们可以拿到我们想要的各种宽高度,是这样的view是要先测量,布局,然后再onDraw画的,所以我们可以准确的画出我们要画的东西.画的时候,我们主要就是注意画的字母的位置,然后画的坐标是相对于我们的控件的坐标系的!!所以注意不要乱给坐标值,超出范围就看不到了.确定字母坐标位置,这个画个图分析下就是把高度分成多少个字母份,然后每个字母的位置,静下心分析下很快就出来了吧,所以这个控件还是很好画的.我们来看看布局

<?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="horizontal">

    <ListView
        android:id="@+id/list"
        android:layout_weight="1"
        android:layout_width="0dp"
        android:layout_height="match_parent"/>

    <com.it.indexview.view.IndexView
        android:id="@+id/index"
        android:layout_width="30dp"
        android:layout_height="match_parent"
        android:background="#aaf76d03"/>
</LinearLayout>

然后来看看这样不加listView是什么样吧
效果

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initView();

       // initData();

        initListener();


    }



    private void initView() {
        mIndexView = (IndexView) findViewById(R.id.index);
        mListView = (ListView) findViewById(R.id.list);
        mToast = new Toast(this);
        mToast.setGravity(Gravity.CENTER, 0, 0);
        mToast.setDuration(Toast.LENGTH_SHORT);

        View view = View.inflate(this, R.layout.toast_layout, null);
        mTextView = (TextView) view.findViewById(R.id.text_toast);
        mToast.setView(view);           //自定义toast
    }




    private boolean isIndexViewScroll = false;
    private void initListener() {
        mIndexView.setOnIndexChangeListener(new IndexView.OnIndexChangeListener() {
            @Override
            public void onChange(String str) {

                isIndexViewScroll = true;
                showToast(str);


            }

            @Override
            public void onStop() {

                isIndexViewScroll = false;
            }
        });

    }

    private void  showToast(String str){

        mTextView.setText(str);
        mToast.show();
    }

嗯,要加listView之前,我们的联系人应该排序啊,我们的手机联系人,我知道的应该是数字排前面,还有根据拼音来的吧,这是我准备的数据

private static String name[] = {"哪一天", "女人", "南下", "噢噢噢", "欧阳", "藕断丝连",
            "哦吧", "怕怕", "魄力", "彭大头", "胖大海", "剖析", "钱多多", "恰恰恰", "雀巢", "企鹅", "权志龙",
            "日日日", "热热热", "容祖儿", "荣耀", "人生", "嘎嘎嘎", "龚大华", "化骨绵掌",
            "哈哈", "赫连霸", "嗨嗨嗨", "将军", "间不容发", "夹克", "邵亮", "少年", "扫把", "时间", "深圳", "沈万三",
            "团灭发动机", "坦荡荡", "潭水深千尺", "统一", "段子手", "独孤求败", "滴滴", "都敏俊", "都儿子", "鹅鹅鹅", "儿子",
            "胡一刀", "胡大海", "胡圆圆", "福贝勒", "福尔康", "高晓松", "郜大头", "劣化", "嘞嘞嘞", "莫莫莫", "头衔", "无名之辈", "吴三岁", "五元",
            "吴丽", "喂喂喂", "行行行", "咸鱼", "夏东海", "洗刷刷", "唐振浩", "1233123", "21312433212", "阿毛", "爱国", "阿达", "奥特曼", "步惊云",
            "不哭死神",
            "布衣", "卜算子",
            "陈友谅", "程大宝", "趁早", "辰小二", "西门吹雪", "显卡", "赵无极", "赵日天",
            "曾小强", "朱元璋", "中神通", "钟灵儿", "钟无艳", "炸了", "木子", "穆桂英",
            "莫大头", "马自达", "码头", "能子", "农牧", "煎饼", "接口", "卡卡卡", "孔乙己", "孔夫子",
            "空山鸟语", "流言蜚语", "刘尧儿子", "刘邦", "累累累", "渣渣渣"};

我们给ListView这些数据前,我们应该对他们进行排序,这里介绍个包可以把汉语转换成拼音pinyin4j-2.5.6.jar

图片
一般用法

/**
 * Created by Root on 2016/6/28.
 */
public class PinYinUtil {

    public  static String getPinying(String hanyu){

        StringBuilder sb = new StringBuilder();

        HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();  //拼音格式
        format.setCaseType(HanyuPinyinCaseType.UPPERCASE);  //大写
        format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);  //不要声调

        char[] chars = hanyu.toCharArray();

        for (int i = 0; i < chars.length; i++) {

            char ch = chars[i];

            if (Character.isSpaceChar(ch)){  //如果是空格,跳过
                continue;
            }

            if (ch >= -127 && ch < 128){ //如果不是汉字,是数字,键盘上的字符不进行汉字转拼音
                sb.append(ch);
            }else {

                String s ="";
                try {      //多音字返回多个字母,这里只取第一个音,有一些生僻字字识别不了,抛异常
                    s = PinyinHelper.toHanyuPinyinStringArray(ch, format)[0];
                    sb.append(s);
                } catch (BadHanyuPinyinOutputFormatCombination badHanyuPinyinOutputFormatCombination) {
                    badHanyuPinyinOutputFormatCombination.printStackTrace();
                    sb.append(s);
                }
            }


        }
        return sb.toString();
    }
}

这样我们就可以把汉字转化成拼音了,这就可以进行比较了.我们初始化数据

 private void initData() {
        mPersonList = new ArrayList<Person>();
        for (int i = 0; i < name.length; i++) {

            mPersonList.add(new Person(name[i]));
        }

        Collections.sort(mPersonList);  //排序,person要实现Comparable<T>接口

//        for (Person p : mPersonList) {
//            Log.d("MainActivity", p.toString());
//        }


        mListView.setAdapter(new PerAdapt(this,mPersonList));

        selectIndex(-1);

    }

peison类实现Comparable接口

/**
 * Created by Root on 2016/6/28.
 */
public class Person implements Comparable<Person>{

    public String name;
    public String piny;

    public Person(String name){
        this.name = name;
        this.piny = PinYinUtil.getPinying(name);
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", piny='" + piny + '\'' +
                '}';
    }

    @Override
    public int compareTo(Person another) {           //根据字符串比较
        return this.piny.compareTo(another.piny);
    }
}

这样我们的ListView就有序的展示数据了,接下来就是最后的监听了,listview滑动的时候要监听位置,索引栏滑动也要监听位置变化做出相应操作/这也是体力话.贴下代码吧.

 private int selectIndex(int index) {//返回索引栏字母对应的下标
        char ch;
        if (index < 0){

             ch= mPersonList.get(mListView.getFirstVisiblePosition()).piny.charAt(0);  //第一个可见条目对应的拼音首字母
        }else {
            ch = mPersonList.get(index).piny.charAt(0);
        }
        if (ch >= 48 && ch <= 57){  //0~9对应的ascll码值
            mIndexView.setTouchIndex(1);
            return 1;

        }else {//前两个,第一个我也不知道是撒,虽然手机联系人那有....第二个是数字,所以跳过从第三个开始循环

            for (int i = 2; i < IndexView.indexStr.length; i++) {

                if(IndexView.indexStr[i].equals(String.valueOf(ch))){
                    mIndexView.setTouchIndex(i);
                    return i;
                }
            }
        }
        return 0; 
    }


    private boolean isIndexViewScroll = false;
    private void initListener() {
        mIndexView.setOnIndexChangeListener(new IndexView.OnIndexChangeListener() {
            @Override
            public void onChange(String str) {

                isIndexViewScroll = true;//索引栏在滑动,通知listview不要影响我
                showToast(str);
                if ("#".equals(str)){
                    mListView.smoothScrollToPosition(0);  //数字都是在最上面吧
                    return;
                }
                for (int i = 0; i < mPersonList.size(); i++) {

                    char c = mPersonList.get(i).piny.charAt(0);
                    if (str.equals(String.valueOf(c))){

                        mListView.setSelection(i);  //滑到第一个找到的姓氏
                        break;
                    }

                }

            }

            @Override
            public void onStop() {

                isIndexViewScroll = false;
            }
        });

        mListView.setOnScrollListener(new AbsListView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {

            }

            int tempIndex = -1;

            int index = -1;

            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

                if (!isIndexViewScroll){ //索引栏不滑我才处理索引栏

                   tempIndex  = selectIndex(firstVisibleItem);

                    if (tempIndex != index){  //防止重复显示

                        index = tempIndex;
                        showToast(IndexView.indexStr[index]);
                    }

                }

            }
        });
    }

嗯,就到这里吧,有兴趣向下完整代码看的话,资源审核通过后,我会在评论那里提供链接

<script type="text/javascript"> $(function () { $('pre.prettyprint code').each(function () { var lines = $(this).text().split('\n').length; var $numbering = $('<ul/>').addClass('pre-numbering').hide(); $(this).addClass('has-numbering').parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($('<li/>').text(i)); }; $numbering.fadeIn(1700); }); }); </script>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值