zoukankan      html  css  js  c++  java
  • 老猪带你玩转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

  • 相关阅读:
    poj_1084 剪枝-IDA*
    搜索算法
    poj_1475 BFS+BFS
    chrome浏览器经常无响应
    charles抓包工具的使用:手机抓包设置和安装证书
    charles抓包工具的使用:概述
    不同局域网如何利用charles对app进行抓包
    fiddler之使用教程(一)
    一点感触
    单元测试框架处理多组数据的另一种写法:基于构造函数和超继承
  • 原文地址:https://www.cnblogs.com/manuosex/p/5023791.html
Copyright © 2011-2022 走看看