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); } } }