字母A-Z的快速定位滑块的学习研究
来源:互联网 发布:苹果电脑清理垃圾软件 编辑:程序博客网 时间:2024/04/28 14:57
实习时遇到这么一个需求的更改,把一个带字母快速定位的滑块的listview,将其中的滑块显示全部字母a-z改成listview中数据有哪些,就只显示有数据的字母。在网上搜索了一下这个自定义view的实现,发现和项目中实现的代码基本一致,好吧,原来也是从网上百度到直接复制下来的,汗~
结合项目中的代码和网上的资料,我自己学习分析了一下这个自定义sidebar的实现。先贴上源码,源码参考自:
http://blog.csdn.net/woaieillen/article/details/12712137
public class SideBar extends View { // 触摸事件 private OnTouchingLetterChangedListener onTouchingLetterChangedListener; // 26个字母 public static String[] b = { "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 choose = -1;// 选中 private Paint paint = new Paint(); private TextView mTextDialog; public void setTextView(TextView mTextDialog) { this.mTextDialog = mTextDialog; } public SideBar(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public SideBar(Context context, AttributeSet attrs) { super(context, attrs); } public SideBar(Context context) { super(context); } /** * 重写这个方法 */ protected void onDraw(Canvas canvas) { super.onDraw(canvas); // 获取焦点改变背景颜色. int height = getHeight();// 获取对应高度 int width = getWidth(); // 获取对应宽度 int singleHeight = height / b.length;// 获取每一个字母的高度 for (int i = 0; i < b.length; i++) { paint.setColor(Color.rgb(33, 65, 98)); // paint.setColor(Color.WHITE); paint.setTypeface(Typeface.DEFAULT_BOLD); paint.setAntiAlias(true); paint.setTextSize(20); // 选中的状态 if (i == choose) { paint.setColor(Color.parseColor("#3399ff")); paint.setFakeBoldText(true); } // x坐标等于中间-字符串宽度的一半. float xPos = width / 2 - paint.measureText(b[i]) / 2; float yPos = singleHeight * i + singleHeight; canvas.drawText(b[i], xPos, yPos, paint); paint.reset();// 重置画笔 } } @Override public boolean dispatchTouchEvent(MotionEvent event) { final int action = event.getAction(); final float y = event.getY();// 点击y坐标 final int oldChoose = choose; final OnTouchingLetterChangedListener listener = onTouchingLetterChangedListener; final int c = (int) (y / getHeight() * b.length);// 点击y坐标所占总高度的比例*b数组的长度就等于点击b中的个数. switch (action) { case MotionEvent.ACTION_UP: setBackgroundDrawable(new ColorDrawable(0x00000000)); choose = -1;// invalidate(); if (mTextDialog != null) { mTextDialog.setVisibility(View.INVISIBLE); } break; default: setBackgroundResource(R.drawable.sidebar_background); if (oldChoose != c) { if (c >= 0 && c < b.length) { if (listener != null) { listener.onTouchingLetterChanged(b[c]); } if (mTextDialog != null) { mTextDialog.setText(b[c]); mTextDialog.setVisibility(View.VISIBLE); } choose = c; invalidate(); } } break; } return true; } /** * 向外公开的方法 * * @param onTouchingLetterChangedListener */ public void setOnTouchingLetterChangedListener( OnTouchingLetterChangedListener onTouchingLetterChangedListener) { this.onTouchingLetterChangedListener = onTouchingLetterChangedListener; } /** * 接口 * * @author coder * */ public interface OnTouchingLetterChangedListener { public void onTouchingLetterChanged(String s); }}
很容易看出这个自定义重写了onDraw方法,在方法里绘制了定义好的包含a-z的字母数组。我要完成我的需求,只需要获取到listview里包含的所有item的字母数据,然后做一下去除相同字母的过滤,把得到的字母传给sidebar然后再重新绘制一下就可以了。所以我在其中添加了一个方法setLetters(String[] letters)传入一个String数组,然后将传入的数组赋给绘制的数组,调用invalidate()方法重新绘制就可以了。
在完成任务之后,我继续研究了下这个自定义的view的具体绘制过程和事件的处理。正好复习下之前看的《Android群英传》里讲的事件传递机制和view绘制过程原理。
在onDraw()方法里先获取到控件的宽度和高度,然后根据需要绘制的字母个数获得每个字母的高度,初始化画笔paint设置画笔相关参数,计算绘制的x,y坐标的位置,循环字母数组绘制每个字母,如果是处于choose状态,修改画笔颜色并加粗。
关于事件的处理,在事件拦截方法dispatchTouchEvent中,获取到事件,并根据触摸的位置坐标计算出是哪一个字母位置,在根据事件类型ACTION_UP,触摸离开时,修改view的背景资源为透明,调用invalidate重新绘制,将中间的TextDialog设置为不可见。其他时候修改背景资源,再根据触摸选中的位置设置TextDialog的文字内容和可见,完成监听回调,重新绘制view。
看都看到这里了就把这个Demo看完吧,到MainActivity.java中,看看这个带特殊的listview是怎么实现的。
在initView()方法里,首先实例化了一个汉字转化拼音的类对象和一个按照拼音排序的比较器。
//实例化汉字转拼音类 characterParser = CharacterParser.getInstance(); //比较器 pinyinComparator = new PinyinComparator();
然后设置sidebar的触摸监听事件,根据触摸的字母位置快速定位到listview中该字母首次出现的位置。
//设置右侧触摸监听 sideBar.setOnTouchingLetterChangedListener(new OnTouchingLetterChangedListener() { @Override public void onTouchingLetterChanged(String s) { //该字母首次出现的位置 int position = adapter.getPositionForSection(s.charAt(0)); if(position != -1){ sortListView.setSelection(position); } } });
接下来listview的监听很简单,就是弹出一个吐司,filledData()方法是从资源文件里读取填充listview的数据,其中用到了characterParser,把数据封装成SortModel对象,存储到一个SourceDateList集合中,并用pinyinComparator进行排序后,初始化了一个SortAdapter,为这个listview设置适配器和数据。最后就是对上方搜索框的设置,初始化mClearEditText后,设置addTextChangedListener监听,根据输入内容调用filterData()方法,过滤数据并更新ListView。
//根据输入框输入值的改变来过滤搜索 mClearEditText.addTextChangedListener(new TextWatcher() { @Override public void onTextChanged(CharSequence s, int start, int before, int count) { //当输入框里面的值为空,更新为原来的列表,否则为过滤数据列表 filterData(s.toString()); } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void afterTextChanged(Editable s) { } });private void filterData(String filterStr){ List<SortModel> filterDateList = new ArrayList<SortModel>(); if(TextUtils.isEmpty(filterStr)){ filterDateList = SourceDateList; }else{ filterDateList.clear(); for(SortModel sortModel : SourceDateList){ String name = sortModel.getName(); if(name.indexOf(filterStr.toString()) != -1 || characterParser.getSelling(name).startsWith(filterStr.toString())){ filterDateList.add(sortModel); } } } // 根据a-z进行排序 Collections.sort(filterDateList, pinyinComparator); adapter.updateListView(filterDateList); }
至此看来,想知道listview的实现,就得去看SortAdapter里是怎么设置数据item的了。在getView()方法里对每个item进行设置,调用getSectionForPosition()和getPositionForSection()这两个方法来获取某个字母第一次出现位置来控制tvLetter就是那个显示字母的TextView显示或隐藏。关于getSectionForPosition()和getPositionForSection()这两个方法,是因为SortAdaoter继承了SectionIndexer接口必须实现的,getSectionForPosition()通过该项的位置,获得所在分类组的索引号,getPositionForSection() 根据分类列的索引号获得该序列的首个位置,这两个方法这里http://blog.csdn.net/jack_l1/article/details/14165291写的很清楚了,一看就懂。
/** * 根据ListView的当前位置获取分类的首字母的Char ascii值 */ public int getSectionForPosition(int position) { return list.get(position).getSortLetters().charAt(0); } /** * 根据分类的首字母的Char ascii值获取其第一次出现该首字母的位置 */ public int getPositionForSection(int section) { for (int i = 0; i < getCount(); i++) { String sortStr = list.get(i).getSortLetters(); char firstChar = sortStr.toUpperCase().charAt(0); if (firstChar == section) { return i; } } return -1; }
知道这两个方法后,再看getView里的代码就很清晰了,每次先获取当前位置的selection值,根据selection值获取这个值第一次出现的位置,如果和当前位置一样就显示tvLetter可见并设置tvLetter上的字母,如果不是第一次就把tvLetter隐藏。
public View getView(final int position, View view, ViewGroup arg2) { ViewHolder viewHolder = null; final SortModel mContent = list.get(position); if (view == null) { viewHolder = new ViewHolder(); view = LayoutInflater.from(mContext).inflate(R.layout.item, null); viewHolder.tvTitle = (TextView) view.findViewById(R.id.title); viewHolder.tvLetter = (TextView) view.findViewById(R.id.catalog); view.setTag(viewHolder); } else { viewHolder = (ViewHolder) view.getTag(); } //根据position获取分类的首字母的Char ascii值 int section = getSectionForPosition(position); //如果当前位置等于该分类首字母的Char的位置 ,则认为是第一次出现 if(position == getPositionForSection(section)){ viewHolder.tvLetter.setVisibility(View.VISIBLE); viewHolder.tvLetter.setText(mContent.getSortLetters()); }else{ viewHolder.tvLetter.setVisibility(View.GONE); } viewHolder.tvTitle.setText(this.list.get(position).getName()); return view; } final static class ViewHolder { TextView tvLetter; TextView tvTitle; }
- 字母A-Z的快速定位滑块的学习研究
- listview按字母A-Z快速定位
- Android UI - 右侧滑动实现A-Z的快速定位
- 快速集成android实现listview的字母A-Z排序,界面侧边字母索引
- 快速集成android实现listview的字母A-Z排序,界面侧边字母索引
- 随机生成A~Z的字母CharDemo
- Android 实现A-Z字母排序的ListView的检索
- 含有大小写字母的字符串按照a-zA-Z排序
- 仿美团炫酷动画效果的A-Z字母排序侧边库
- 右面有A- Z的实现点击改变字母颜色
- 类似通讯录的A-Z字母分组实现
- Android开发--根据字母快速定位的侧边栏实现
- 数字 & 字母的研究
- 长为10000的字符串,由a-z及A-Z组成,统计出其中出现频率最高的字母
- 仿Android联系人SideBar排序,根据拼音A-Z字母快速导航联系人姓名,以及输入搜索条件过滤,显示姓名的文字图片
- 仿Android联系人SideBar排序,根据拼音A-Z字母快速导航联系人姓名,以及输入搜索条件过滤,显示姓名的文字图片,添加挤压动画
- JAVA中 就字母由 A=>Z 递增 和 Z=>A 递减的输出问题
- 自定义View的尝试-A到Z快速搜索sideBar
- struts2中配置拦截器、拦截器栈和默认拦截器
- BestCoder Round #80(A)模拟
- java虚拟机Class类文件的结构
- Android Studio实现代码混淆
- php中需要注意的问题
- 字母A-Z的快速定位滑块的学习研究
- 设计模式-可复用面向对象软件的基础 [读书笔记]
- web.xml详解
- java.sql.SQLException: Value'0000-00-00'错误解决方法
- BestCoder Round #80(B)高精度
- Android控件架构与自定义控件(一)
- 《JS权威指南》学习笔记(三):表达式和运算符
- 国内从事机器视觉领域的公司(转)
- c++搜索二叉树的基本操作