自定义联系人快速索引栏

Posted z8z87878

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自定义联系人快速索引栏相关的知识,希望对你有一定的参考价值。

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

看看效果吧

额,我这个为了简单,简单的用了下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]);
                    

                

            
        );
    

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

以上是关于自定义联系人快速索引栏的主要内容,如果未能解决你的问题,请参考以下文章

如何在qqis中快速利用自定义坐标定位,进行准确测量

Vant中 索引栏(IndexBar)自定义使用

安卓自定义边栏英文索引控件

快速设置状态栏的自定义颜色?

如何快速在自定义导航栏顶部制作一半的 ImageView

自定义控件三部曲视图篇——测量与布局