老猪带你玩转android自定义控件二——自定义索引栏listview

  带索引栏的listview,在android开发非常普遍,方便用户进行字母索引,就像微信通讯录这样:

 

  今天,我们就从零到一实现这个具有索引栏的listview.

  怎么实现这个控件了,我们应当梳理出一个思路。

  ①首先应当将字母的索引栏继承与一个控件,通过ondraw方法将字母画出来。

  ②然后我们应该监听这个字母控件的ontouch事件,来判断用户到底是按了那个字母。

  ③就是实现这个索引栏与listview的联动,就是将listview滑动到按下字母的位置。

  大体流程图如下:

 

  有了前面铺垫,我们引出本文重头戏——代码。

  首先,索引栏这个控件如何将字母绘制在控件上的代码:

    /**
     * 侧边栏显示字母
     */
    private String[] words = { "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", "#" };
    /**
     * 绘制列表控件的方法
     * 将要绘制的字母以从上到下的顺序绘制在一个指定区域
     * 如果是进行选中的字母就进行高亮显示
     */
    @Override
    protected void onDraw(Canvas canvas) {
        // TODO Auto-generated method stub
        super.onDraw(canvas);
        int height = getHeight();// 获取对应高度
        int width = getWidth(); // 获取对应宽度
        int singleHeight = height / words.length;// 获取每一个字母的高度

        for (int i = 0; i < words.length; i++) {
            paint.setColor(Color.rgb(33, 65, 98));
            // paint.setColor(Color.WHITE);
            paint.setTypeface(Typeface.DEFAULT_BOLD);
            paint.setAntiAlias(true);
            paint.setTextSize(20f);
            // 选中的状态
            if (isdown) {
                paint.setColor(Color.parseColor("#ffffff"));
                //paint.setFakeBoldText(true);
            }
            // x坐标等于中间-字符串宽度的一半.
            float xPos = width / 2 - paint.measureText(words[i]) / 2;
            float yPos = singleHeight * i + singleHeight;
            canvas.drawText(words[i], xPos, yPos, paint);
            paint.reset();// 重置画笔
        }
    }

  通过上述的代码,我们可以得出以下的结论:将要绘制的字母以从上到下的顺序绘制在一个指定区域,每个字母的x坐标是一样的,x坐标即为控件宽度一半。如果当前字母选中的话,就高亮显示。思路如图所示:

  紧接着,就来到第二步,确定用户到底点击是那个字母,代码如下:

/**
     * 处理触摸事件的方法
     * 用户按下时候,整个控件背景变化
     * 根据按下y坐标 判断究竟用户按下那个字母
     * 当前字母高亮显示 将其字母显示listview中央
     */
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        int action = event.getAction();
        final float y = event.getY();// 点击y坐标
        final int oldChoose = choose;
        final ITouchingLetterChangedListener listener = onTouchingLetterChangedListener;
        final int c = (int) (y / getHeight() * words.length);// 点击y坐标所占总高度的比例*b数组的长度就等于点击b中的个数.
        switch (action) {
        case MotionEvent.ACTION_UP:
            isdown=false;
            setBackgroundResource(android.R.color.transparent);
            choose = -1;//
            invalidate();
            if (textViewDialog != null) {
                textViewDialog.setVisibility(View.INVISIBLE);
            }
            break;

        default:
            isdown=true;
            setBackgroundResource(R.color.sidebar_bg_color);
            if (oldChoose != c) {
                if (c >= 0 && c < words.length) {
                    if (listener != null) {
                        listener.OnTouchingLetterChanged(words[c]);
                    }
                    if (textViewDialog != null) {
                        textViewDialog.setText(words[c]);
                        textViewDialog.setVisibility(View.VISIBLE);
                    }

                    choose = c;
                    invalidate();
                }
            }
            break;
        }
        return true;
    }

  通过上述的代码,我们可以这样总结:当用户按下的时候,整个控件背景发生变化,根据用户按下的y坐标来确定用户究竟是按下那个字母,并且将按下字母显示屏幕的中央,效果图如下:

  最终,将listview 移动到按下字母相应位置,代码如下:

/**
         * 根据用户点击那个字母将listview移动到相应位置
         */
        sidebar.setOnTouchingLetterChangedListener(new ITouchingLetterChangedListener() {

            @Override
            public void OnTouchingLetterChanged(String cString) {
                int position = -1;
                if (cString.length() > 0) {
                    position = myAdapter.getPositionForSection(cString
                            .charAt(0));
                }
                if (position != -1) {
                    listview.setSelection(position);
                } else if (cString.contains("#")) {
                    listview.setSelection(0);
                }
            }
        });

  连篇累牍说了这么多,控件大功告成的效果为:

  源代码地址为:

  http://pan.baidu.com/s/1dDMDjhR

原文地址:https://www.cnblogs.com/manuosex/p/5023791.html