Android自定义类似联系人列表的 快速索引控件
2015-12-14 21:55
483 查看
效果图
思考
将字母 A - Z 画出来处理字母的触摸事件
提供使用的回调
联系人汉字转成拼音
按拼音排序
分组(同一个拼音开头的为一组)
将自定义的view和ListView绑定
实现
1. 绘制A-Z
准备好A-Z 26个字母在onDraw方法里面计算每个字母的位置并绘制
private static final String[] LETTERS = new String[]{ "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) { super.onDraw(canvas); //绘制A-Z for (int i = 0; i < LETTERS.length; i++) { // int width = (int) (screenWidth * 1.0 / 2 - paint.measureText(LETTERS[i]) * 1.0 / 2); Rect rect = new Rect(); paint.getTextBounds(LETTERS[i], 0, 1, rect); int width = (int) (screenWidth * 1.0 / 2 - rect.width() * 1.0 / 2); int height = (int) (cellHeight * 1.0 / 2 + rect.height() * 1.0 / 2 + i * cellHeight); canvas.drawText(LETTERS[i], width, height, paint); } } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); screenWidth = getMeasuredWidth(); screenHeight = getMeasuredHeight(); cellHeight = screenHeight * 1.0 / LETTERS.length; }
2. 处理onTouchEvent事件
int touchIndex = -1; @Override public boolean onTouchEvent(MotionEvent event) { int y; switch (event.getAction()) { case MotionEvent.ACTION_DOWN: y = (int) event.getY(); for (int i = 0; i < LETTERS.length; i++) { if (y > i * cellHeight && y < (i + 1) * cellHeight) { if (touchIndex != i) { Log.e(TAG, LETTERS[i]); Toast.makeText(getContext(), LETTERS[i], 0).show(); touchIndex = i; } break; } } break; case MotionEvent.ACTION_MOVE: y = (int) event.getY(); for (int i = 0; i < LETTERS.length; i++) { if (y > i * cellHeight && y < (i + 1) * cellHeight) { if (touchIndex != i) { Log.e(TAG, LETTERS[i]); Toast.makeText(getContext(), LETTERS[i], 0).show(); touchIndex = i; } break; } } break; case MotionEvent.ACTION_UP: break; } return true; }
3. 提供回调方法
private OnIndexChangedListener listener; public void setOnIndexChangedListener(OnIndexChangedListener listener) { this.listener = listener; } public interface OnIndexChangedListener { void onIndexChanged(String index); } //触摸事件的操作通过接口让调用者去实现 @Override public final boolean onTouchEvent(MotionEvent event) { int y; switch (event.getAction()) { case MotionEvent.ACTION_DOWN: y = (int) event.getY(); for (int i = 0; i < LETTERS.length; i++) { if (y > i * cellHeight && y < (i + 1) * cellHeight) { if (touchIndex != i) { if (listener != null) { listener.onIndexChanged(LETTERS[i]); } touchIndex = i; } break; } } break; case MotionEvent.ACTION_MOVE: y = (int) event.getY(); for (int i = 0; i < LETTERS.length; i++) { if (y > i * cellHeight && y < (i + 1) * cellHeight) { if (touchIndex != i) { if (listener != null) { listener.onIndexChanged(LETTERS[i]); } touchIndex = i; } break; } } break; case MotionEvent.ACTION_UP: break; } return true; }
4. 汉字转拼音
需要添加 pinyin4j-2.5.0.jar/** * 描述:汉字转拼音的工具类 * 作者 mjd * 日期:2015/12/10 12:50 */ public class PinYinUtils { public static String getPinYin(String hanZi) { HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat(); format.setCaseType(HanyuPinyinCaseType.UPPERCASE); format.setToneType(HanyuPinyinToneType.WITH_TONE_NUMBER); StringBuilder sb = new StringBuilder(); char[] charArray = hanZi.toCharArray(); for (int i = 0; i < charArray.length; i++) { char c = charArray[i]; // 如果是空格, 跳过 if (Character.isWhitespace(c)) { continue; } if (c >= -127 && c < 128) { // 肯定不是汉字 sb.append(c); } else { String s = ""; try { // 通过char得到拼音集合. 单 -> dan, shan s = PinyinHelper.toHanyuPinyinStringArray(c, format)[0]; sb.append(s); } catch (BadHanyuPinyinOutputFormatCombination e) { e.printStackTrace(); sb.append(s); } } } return sb.toString(); } }
5. 汉字按拼音排序
//让联系人自身具备比较性(按照拼音) /** * 描述: * 作者 mjd * 日期:2015/12/10 13:01 */ public class Person implements Comparable<Person> { private String name; private String pinyin; public Person(String name) { this.name = name; this.pinyin = PinYinUtils.getPinYin(name); } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPinyin() { return pinyin; } public void setPinyin(String pinyin) { this.pinyin = pinyin; } @Override public int compareTo(@NonNull Person another) { return this.pinyin.compareTo(another.getPinyin()); } } //主页面(Cheeses.NAMES 是准备好的一百零八位好汉的名字) /** * 描述: * 作者 mjd * 日期:2015/12/9 21:43 */ public class MainActivity extends AppCompatActivity { private FastIndexBar fastIndexBar; private RecyclerView recyclerView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); fastIndexBar = (FastIndexBar) findViewById(R.id.fast_index_bar); recyclerView = (RecyclerView) findViewById(R.id.recycler_view); fastIndexBar.setOnIndexChangedListener(new FastIndexBar.OnIndexChangedListener() { @Override public void onIndexChanged(String index) { Toast.makeText(MainActivity.this, index, 0).show(); } }); ContactAdapter adapter = new ContactAdapter(getContacts()); recyclerView.setAdapter(adapter); RecyclerView.LayoutManager manager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false); recyclerView.setLayoutManager(manager); } private List<Person> getContacts() { List<Person> list = new ArrayList<>(); String[] names = Cheeses.NAMES; for (int i = 0; i < names.length; i++) { list.add(new Person(names[i])); } Collections.sort(list); return list; } } //联系人的适配器 /** * 描述: * 作者 mjd * 日期:2015/12/10 13:08 */ public class ContactAdapter extends RecyclerView.Adapter<MyViewHolder> { private List<Person> personList; public ContactAdapter(List<Person> personList) { this.personList = personList; } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = View.inflate(parent.getContext(), R.layout.item_contact, null); view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); return new MyViewHolder(view); } @Override public void onBindViewHolder(MyViewHolder holder, int position) { Person person = personList.get(position); holder.tvIndex.setText(String.valueOf(person.getPinyin().charAt(0))); holder.tvName.setText(person.getName()); } @Override public int getItemCount() { return personList.size(); } } class MyViewHolder extends RecyclerView.ViewHolder { TextView tvIndex; TextView tvName; public MyViewHolder(View itemView) { super(itemView); tvIndex = (TextView) itemView.findViewById(R.id.tv_index); tvName = (TextView) itemView.findViewById(R.id.tv_name); } }
6. 汉字按拼音分组
//在适配器的onBindViewHolder方法中判断 @Override public void onBindViewHolder(MyViewHolder holder, int position) { Person person = personList.get(position); String currentIndex = String.valueOf(person.getPinyin().charAt(0)); String str = null; if (position == 0) { str = currentIndex; } else { String preIndex = String.valueOf(personList.get(position - 1).getPinyin().charAt(0)); if (!currentIndex.equals(preIndex)) { str = currentIndex; } } holder.tvIndex.setVisibility(str == null ? View.GONE : View.VISIBLE); holder.tvIndex.setText(currentIndex); holder.tvName.setText(person.getName()); }
7. 将快速索引控件与RecyclerView绑定
fastIndexBar.setOnIndexChangedListener(new FastIndexBar.OnIndexChangedListener() { @Override public void onIndexChanged(String index) { //显示居中的字母提醒 showIndex(index); //找到personList中第一个以index为拼音首字母的对象,得到索引 for (int i = 0; i < personList.size(); i++) { String currentIndex = String.valueOf(personList.get(i).getPinyin().charAt(0)); if (currentIndex.equals(index)) {//匹配成功 recyclerView.scrollToPosition(i); break; } } } }); private Handler handler = new Handler(); private void showIndex(String index) { tvCenter.setVisibility(View.VISIBLE); tvCenter.setText(index); handler.removeCallbacksAndMessages(null); handler.postDelayed(new Runnable() { @Override public void run() { tvCenter.setVisibility(View.GONE); } }, 2000); }
相关文章推荐
- Android开发相关的Blog推荐——跟随大神的脚步才能成长为大神
- android布局
- [Android][Button]Button注册点击事件的4种方法
- 关于Android自定义相机进行拍照(小米手机出现异常的原因)
- Android(二) activity和四个基本控件
- android重难点解析
- Android:AsyncTask 随记
- android.content.res.Resources$NotFoundException:
- Android内存泄露总结(一)
- Android:ListView 多布局,加头部,尾部
- Android 中加密的String:让我们做出更少的失误
- 【Android 疑难杂症1】android.content.ActivityNotFoundException: Unable to find explicit activity class
- Android 设置ListView不可滚动 及在ScrollView中不可滚动的设置
- Android:AutoCompleteTextView 随记
- Android Studio——Uri、UriMatcher、ContentUris详解
- Android:shape:表示一张图片
- Android:SystemClock 随记
- android手机命令行下不能使用sqlite3命令查看*.db数据库文件解决办法
- Android:怎么样通过资源的名字获取资源的id?
- android中invalidate()的自动清屏含义以及屏幕刷新