带索引栏的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