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. ...
随机推荐
- Redis简介与简单安装
Redis简介与简单安装 一.NoSQL的风生水起 1.1 后Web2.0时代的发展要求 随着互联网Web2.0网站的兴起,传统的关系数据库在应付Web2.0网站,特别是超大规模和高并发的SNS类 ...
- Web缓存(Varnish方案)
Web缓存(Varnish方案) 转载 http://www.s135.com/post/313/ arnish是一款高性能的开源HTTP加速器,挪威最大的在线报纸 Verdens Gang (htt ...
- 玩转python之字符串逐个字符或逐词反转
众所周知,python中的字符串是无法改变的,反转一个字符串自然要创建一个拷贝:最简单的方法,当然是步长为“-1”的切片: result = astring[::-1] 如果要是按单词来反转,需要三步 ...
- 浅谈DevExpress<五>:TreeList简单的美化——自定义单元格,加注释以及行序号
今天就以昨天的列表为例,实现以下效果:预算大于110万的单元格突出显示,加上行序号以及注释,如下图:
- Socket一些常用的方法封装
public class SocketHelper { /// <summary> /// 功能描述:得到一个实例对象 /// </summary> /// <retur ...
- sprinfmvc学习--01
springmvc框架是一个基于请求驱动的web框架,使用了前端控制器模式来设计.根据请求映射规则分发给相应的页面控制器进行处理. 1. 首先用户发送请求-->DispatcherServle ...
- jQuery Validation让验证变得如此容易(二)
上一个例子我们是统一引用jquery.validate.js这样所有必填字段的提示信息都将是This field is required. 现在要改成动态提示,比如姓名如果为空则提示姓名不能为空,密码 ...
- Redis系统学习 三、使用数据结构
前言:上一章,简单介绍了5种数据结构,并给出了一些用例.现在是时候来看看一些高级的,但依然很常见的主题和设计模式 一.大O表示法(Big O Notation ) 常用时间复杂度O(1)被认为是最快速 ...
- 鸟哥的LINUX私房菜基础篇第三版 阅读笔记 三 Linux磁盘与文件系统管理
一.认识EXT2文件系统: a.硬盘的组成:转动小马达+存储的磁盘+读写的机械臂 b.磁盘的一些概念 扇区为最小的物理储存单位,每个扇区为512B ...
- kivy create a package for Android
Now that you've successfully coded an app. Now you want to deploy it to Android. So now we would nee ...