Listview右侧 IndexBar
qq 好友聊天界面,右侧 IndexBar A B C D ,点击跳转到相应的联系人名字
import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; public class QuickIndexBar extends View { private String[] letterArr = {"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"}; public QuickIndexBar(Context context) { this(context, null); } public QuickIndexBar(Context context, AttributeSet attrs) { this(context, attrs, 0); } Paint paint; int ColorDefault = Color.WHITE; int ColorPressed = Color.BLACK; public QuickIndexBar(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); paint = new Paint(Paint.ANTI_ALIAS_FLAG);//设置抗锯齿 paint.setColor(ColorDefault); int size = getResources().getDimensionPixelSize(R.dimen.paint_size); paint.setTextSize(size); //文字绘制的起点默认是左下角,设置起点为文字底边的中心,baseline基准线 paint.setTextAlign(Paint.Align.CENTER); } float cellHeight;//一个格子的高 float x; @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); cellHeight = getMeasuredHeight() * 1f / letterArr.length; x = getMeasuredWidth() / 2; } @Override protected void onDraw(Canvas canvas) { //遍历26个字母,对每个字母进行绘制 for (int i = 0; i < letterArr.length; i++) { String text = letterArr[i]; //算法:格子高的一半 + 文字高的一半 + i*格子的高 float y = cellHeight / 2 + getTextHeight(text) / 2 + i * cellHeight; //更改颜色 paint.setColor(i==index?ColorPressed:ColorDefault); canvas.drawText(text, x, y, paint); } } int index = -1; @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_MOVE: int tempIndex = (int) (event.getY() / cellHeight); if(tempIndex!=index){ index = tempIndex; //对index进行合法性的判断 if(index>=0 && index<letterArr.length){ String letter = letterArr[index]; if(listener!=null){ listener.onLetterChange(letter); } } } break; case MotionEvent.ACTION_UP: //重置为-1 index = -1; if(listener!=null){ listener.onRelease(); } break; } //重绘 invalidate(); return true; } /** * 获取文字的高度 * * @param text * @return */ private int getTextHeight(String text) { Rect bounds = new Rect(); //当下面的方法执行完,bounds就有值了 paint.getTextBounds(text, 0, text.length(), bounds); return bounds.height(); } private OnLetterChangeListener listener; public void setOnLetterChangeListener(OnLetterChangeListener listener){ this.listener = listener; } public interface OnLetterChangeListener{ void onLetterChange(String letter); /** * 抬起的时候执行 */ void onRelease(); } }
Activity :
import android.os.Handler; import android.support.v4.view.ViewCompat; import android.support.v4.view.ViewPropertyAnimatorListenerAdapter; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.view.animation.OvershootInterpolator; import android.widget.ListView; import android.widget.TextView; import java.util.ArrayList; import java.util.Collections; import java.util.logging.Logger; public class MainActivity extends AppCompatActivity implements QuickIndexBar.OnLetterChangeListener { private QuickIndexBar quickIndex; ListView listview; ArrayList<Friend> friends = new ArrayList<>(); TextView tv_word; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); quickIndex = (QuickIndexBar) findViewById(R.id.quickIndex); listview = (ListView) findViewById(R.id.listview); tv_word = (TextView) findViewById(R.id.tv_word); quickIndex.setOnLetterChangeListener(this); //填充数据 prepareData(); //排序 Collections.sort(friends); listview.setAdapter(new FriendAdapter(friends)); // Log.e("tag",PinYinUtil.getPinYin("刘 德 华 "));//LIUDEHUA // Log.e("tag",PinYinUtil.getPinYin("a刘a德华a"));//aLIUaDEHUAa // Log.e("tag",PinYinUtil.getPinYin("刘德华,。"));//LIUDEHUA } @Override public void onLetterChange(String letter) { //根据当前触摸的字母去集合中查找首字母和触摸字母相同的条目,然后置顶 for (int i = 0; i < friends.size(); i++) { String word = friends.get(i).pinyin.substring(0, 1); if (word.equals(letter)) { //说明找到了,那么就置顶 listview.setSelection(i); break;//找到就立即中断 } } //显示当前的字母 showCurrentWord(letter); } @Override public void onRelease() { // tv_word.setVisibility(View.GONE); new Handler().postDelayed( new Runnable() { @Override public void run() { ViewCompat.animate(tv_word).scaleX(0f).scaleY(0f) .setDuration(500).start(); } }, 500); } boolean isRunAnim = false; /** * 显示当前的字母 * * @param letter */ private void showCurrentWord(String letter) { tv_word.setText(letter); // tv_word.setVisibility(View.VISIBLE); if (isRunAnim) { //如果正在执行放大动画,那么就不要执行了 return; } ViewCompat.animate(tv_word).scaleX(1f).scaleY(1f) .setInterpolator(new OvershootInterpolator(3)) .setListener(new ViewPropertyAnimatorListenerAdapter() { @Override public void onAnimationStart(View view) { isRunAnim = true; } @Override public void onAnimationEnd(View view) { isRunAnim = false; } }) .setDuration(500).start(); } // 虚拟数据 private void prepareData() { friends.add(new Friend("李伟")); friends.add(new Friend("张三")); friends.add(new Friend("阿三")); friends.add(new Friend("阿四")); friends.add(new Friend("段誉")); friends.add(new Friend("段正淳")); friends.add(new Friend("张三丰")); friends.add(new Friend("陈坤")); friends.add(new Friend("林俊杰1")); friends.add(new Friend("陈坤2")); friends.add(new Friend("王二a")); friends.add(new Friend("林俊杰a")); friends.add(new Friend("张四")); friends.add(new Friend("林俊杰")); friends.add(new Friend("王二")); friends.add(new Friend("王二b")); friends.add(new Friend("赵四")); friends.add(new Friend("杨坤")); friends.add(new Friend("赵子龙")); friends.add(new Friend("杨坤1")); friends.add(new Friend("李伟1")); friends.add(new Friend("宋江")); friends.add(new Friend("宋江1")); friends.add(new Friend("李伟3")); } }
import android.support.annotation.Nullable; import android.text.TextUtils; import net.sourceforge.pinyin4j.PinyinHelper; import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType; import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat; import net.sourceforge.pinyin4j.format.HanyuPinyinToneType; import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination; public class PinYinUtil { /** * 获取汉字的拼音 * @param chinese * @return */ public static String getPinYin(String chinese){ if(TextUtils.isEmpty(chinese))return null; //拼音转换的格式化,主要控制字母的大小写,以及是否需要声调 HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat(); format.setCaseType(HanyuPinyinCaseType.UPPERCASE);//设置大写字母 format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);//不需要声调 //ps:由于不支持对多个汉字进行获取,所以要将字符串转为字符数组,对单个汉字进行获取 //最后,将每个字的拼音拼接起来,就是所有汉字的拼音 StringBuilder builder = new StringBuilder(); char[] chars = chinese.toCharArray(); for (int i = 0; i < chars.length; i++) { char c = chars[i]; //1.要进行过滤空格,选择忽略 if(Character.isWhitespace(c)){ continue; } //2.要判断是否是中文,粗略的判断一下:由于一个汉字2个字节, //一个字节范围是-128~127,因此汉字肯定大于127 if(c > 127){ //有可能是汉字,就利用pinyin4j进行获取 try { //由于多音字的存在,所以返回的是数组,比如单:[chan, dan, shan] String[] arr = PinyinHelper.toHanyuPinyinStringArray(c, format); if(arr!=null){ //此处只能用第0个,原因: //1.首先大部分汉字只有一个读音,多音字属于少数 //2.其次,我们也确实无能为力去判断应该用哪个,要判断一个汉字在一串文字 //中的精确读音,至少需要几个技术:a.分词算法 b.非常庞大的分词数据库 builder.append(arr[0]); } } catch (Exception e) { e.printStackTrace(); //说明不是正确的汉字,选择忽略 } }else { //肯定不是汉字,一般是ASCII码表中的字母,对于这个情况,我们选择 //直接拼接 builder.append(c); } } return builder.toString(); } }
import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; import java.util.ArrayList; import butterknife.Bind; import butterknife.ButterKnife; public class FriendAdapter extends BaseAdapter { ArrayList<Friend> list; public FriendAdapter(ArrayList<Friend> list) { this.list = list; } @Override public int getCount() { return list.size(); } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = null; if(convertView==null){ convertView = View.inflate(parent.getContext(), R.layout.adapter_friend, null); holder = new ViewHolder(convertView); convertView.setTag(holder); }else { holder = (ViewHolder) convertView.getTag(); } //绑定数据 Friend friend = list.get(position); String letter = friend.pinyin.substring(0, 1); if(position>0){ //获取上一个条目的首字母 String last = list.get(position - 1).pinyin.substring(0, 1); if(letter.equals(last)){ //说明需要隐藏当前的 holder.tvLetter.setVisibility(View.GONE); }else { //说明不一样,需要显示 holder.tvLetter.setVisibility(View.VISIBLE); holder.tvLetter.setText(letter); } }else { //说明是=0,就是第一天 holder.tvLetter.setVisibility(View.VISIBLE); holder.tvLetter.setText(letter); } holder.tvName.setText(friend.name); return convertView; } static class ViewHolder { @Bind(R.id.tv_letter) TextView tvLetter; @Bind(R.id.tv_name) TextView tvName; ViewHolder(View view) { ButterKnife.bind(this, view); } } }
Listview右侧 IndexBar的更多相关文章
- [Android分享] 【转帖】Android ListView的A-Z字母排序和过滤搜索功能
感谢eoe社区的分享 最近看关于Android实现ListView的功能问题,一直都是小伙伴们关心探讨的Android开发问题之一,今天看到有关ListView实现A-Z字母排序和过滤搜索功能 ...
- Android 实现ListView的A-Z字母排序和过滤搜索功能,实现汉字转成拼音
转载:http://blog.csdn.net/xiaanming/article/details/12684155 转载请注明出处:http://blog.csdn.net/xiaanming/ar ...
- Android开源项目发现---ListView篇(持续更新)
资料转载地址:https://github.com/Trinea/android-open-project 1. android-pulltorefresh 一个强大的拉动刷新开源项目,支持各种控件下 ...
- 【转】Android开源项目发现---ListView篇(持续更新)
原文网址:http://blog.csdn.net/krislight/article/details/20211045 资料转载地址:https://github.com/Trinea/androi ...
- Android ListView滚动条配置完全解析
滚动条的相关显示效果 先来看下ListView的滚动条有哪些显示效果. 滚动条自身的外观 这点不用说,就是滚动条自身的颜色,形状等. Track的外观 默认的ListView是没有设置Track的.为 ...
- ListView 字母导航排序
一.概述 ListView字母导航排序,网上已经有很多代码和博客了, 这篇博文也是照搬网上的. 之所以写到这里,不是为了说明什么,只是为了以后自己查阅方便.本来公司要求实现expandablelis ...
- Android高手速成--第一部分 个性化控件(View)
第一部分 个性化控件(View) 主要介绍那些不错个性化的View,包括ListView.ActionBar.Menu.ViewPager.Gallery.GridView.ImageView.Pro ...
- 据说年薪30万的Android程序员必须知道的帖子
Android中国开发精英 目前包括: Android开源项目第一篇--个性化控件(View)篇 包括ListView.ActionBar.Menu.ViewPager.Gallery.G ...
- Android开源项目分类汇总
目前包括: Android开源项目第一篇——个性化控件(View)篇 包括ListView.ActionBar.Menu.ViewPager.Gallery.GridView.ImageView. ...
随机推荐
- dbcp的配置
tomcat的 配置,进入conf->context.xml <Resource name="mysql" auth="Container" ...
- 基于AngularJS的前端云组件最佳实践
AngularJS是google设计和开发的一套前端开发框架,他能帮助开发人员更便捷地进行前端开发.AngularJS是为了克服HTML在构建应用上的不足而设计的,它非常全面且简单易学习,因此Angu ...
- 在现有代码中通过async/await实现并行
在现有代码中通过async/await实现并行 一项新技术或者一个新特性,只有你用它解决实际问题后,才能真正体会到它的魅力,真正理解它.也期待大家能够多分享解一些解决实际问题的内容. 在我们遭遇“黑色 ...
- wcf跨机器访问的问题
wcf跨机器访问的问题 在wcf跨机器的访问中遇到了各种无法访问的问题,本人也是在通过个人解决问题的基础上发表一下自己的经验,如果还有其他方面可能影响wcf跨机器的问题,还希望大家多多发言! 好了废话 ...
- Web Api的安全性
Web Api的安全性 系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 这一篇文章我们主要来探讨一下Web Api的安全性,到目前为止所有的 ...
- 【IOS开发】SimPholders的使用
推荐一个Xocde开发工具 “SimPholders”,能够快速访问到你的模拟器文件夹,最重要的是完全免费! 官方地址
- ASP.NET虚拟路径小结
一.虚拟路径的概念 “虚拟路径”是指请求 URL 中跟在服务器标识符后面的部分举例. 如绝对路径:http://www.mysite.com/MyApp/Default.aspx,其对应的虚拟路径为: ...
- SSRS 系列 - 使用带参数的 MDX 查询实现一个分组聚合功能的报表
SSRS 系列 - 使用带参数的 MDX 查询实现一个分组聚合功能的报表 SSRS 系列 - 使用带参数的 MDX 查询实现一个分组聚合功能的报表 2013-10-09 23:09 by BI Wor ...
- Web API 入门指南
Web API 入门指南 - 闲话安全2013-09-21 18:56 by 微软互联网开发支持, 231 阅读, 3 评论, 收藏, 编辑 Web API入门指南有些朋友回复问了些安全方面的问题,安 ...
- wcf传输Dataset大数据量 -压缩(一)
wcf传输Dataset大数据量 -压缩(一) 由于WCF不能传输DataTable(不能序列化),所以更多项目中都会使用DataSet作为查询集合的首选返回类型,但是由于DataSet会生成很多的状 ...