带索引栏的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", "#" };/*** 绘制列表控件的方法* 将要绘制的字母以从上到下的顺序绘制在一个指定区域* 如果是进行选中的字母就进行高亮显示*/@Overrideprotected void onDraw(Canvas canvas) {// TODO Auto-generated method stubsuper.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中央*/@Overridepublic 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() {@Overridepublic 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);}}});
连篇累牍说了这么多,控件大功告成的效果为:
源代码地址为:
/s/1dDMDjhR