您的位置:首页 > 产品设计 > UI/UE

自定义控件之A-Z快速检索QuickIndexBar

2016-06-23 14:34 375 查看
---------快速检索--------------

1.应用场景:联系人,好友列表,商品等列表的快速定位和搜索

2.实现逻辑:
a.右边是自定义QuickIndexBar,它能获取触摸它的时候当前所触摸到的字母;
 绘制文本x坐标: width/2;
 绘制文本y坐标: 格子高度的一半 + 文本高度的一半 + position*格子高度
 计算触摸点对应的字母:根据触摸点的y坐标除以cellHeight,得到的值就是字母对应的索引;
 
b.左边是listview,它根据当前触摸的字母,去自己列表找首字母和触摸字母相同的那个
item,然后让item放置到屏幕顶端(setSelection(position));

c.需要用到获取汉字的拼音,借助类库pinyin4j.jar实现;

QuickIndexBar:

/*
*  @Copyright (c) tianchenglin
*  @Author TCL
*  @Date 2016.6.22
*/

package com.study.tcl.quickindex.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

/**
* Created by TCL on 2016/6/22.
*/
public class QuickIndexBar extends View {
private String[] indexArr = {"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 Paint mPaint;
private int mWidth;
private int mHeight;
float mSingleLetterHeight;

private onTouchLetterListener mOnTouchLetterListener;//按住哪个字符的监听

private int mLastLetterIndex = -1;//最后一次按住的字符

public QuickIndexBar(Context context) {
super(context);
init();

}

public QuickIndexBar(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}

public QuickIndexBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}

public void setOnTouchLetterListener(onTouchLetterListener onTouchLetterListener) {
mOnTouchLetterListener = onTouchLetterListener;
}

private void init() {
mPaint = new Paint();
mPaint.setAntiAlias(true);//抗锯齿
mPaint.setTextSize(20);
mPaint.setTextAlign(Paint.Align.CENTER);//设置文本的起点是文字边框底边的中心
}

@Override
protected void onDraw(Canvas canvas) {
for (int i = 0; i < indexArr.length; i++) {
float xPosition = mWidth / 2;//要画的x坐标
//            float yPosition = mSingleLetterHeight * i + mSingleLetterHeight;//要画的y坐标
//y坐标 = 单个字符高度/2+文本高度/2+第几个字符
float yPosition = mSingleLetterHeight / 2 + mPaint.measureText(indexArr[i], 0, 1) / 2 + i *
mSingleLetterHeight;

//            //字符按下变色
//            if (i == mLastLetterIndex) {
//                mPaint.setColor(Color.TRANSPARENT);
//                canvas.drawText(indexArr[i], xPosition, yPosition, mPaint);
//            }
mPaint.setColor(i == mLastLetterIndex ? Color.WHITE : Color.RED);
canvas.drawText(indexArr[i], xPosition, yPosition, mPaint);
}
super.onDraw(canvas);
}

@Override
public boolean onTouchEvent(MotionEvent event) {

switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_DOWN:
this.setBackgroundColor(Color.BLUE);

float y = event.getY();
int index = (int) (y / mSingleLetterHeight);//得到字符对应的索引
if (mLastLetterIndex != index) {
//安全性检查
if (index >= 0 && index < indexArr.length) {
if (mOnTouchLetterListener != null) {
mOnTouchLetterListener.onTouchLetter(indexArr[index]);
}
}
Log.i("index", index + "");
Log.i("letter", indexArr[index]);
}
mLastLetterIndex = index;
break;
case MotionEvent.ACTION_UP:
this.setBackgroundColor(Color.WHITE);

//重置
mLastLetterIndex = -1;
break;
}
invalidate();//引起重绘
return true;//自己处理
}

public interface onTouchLetterListener {
void onTouchLetter(String letter);
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mWidth = getMeasuredWidth();//获取QuickIndexBar宽度
mHeight = getMeasuredHeight();//获取QuickIndexBar高度
mSingleLetterHeight = getMeasuredHeight() * 1f / indexArr.length;//获取一个字符所占高度
}
}


MainActivity:

/*
*  @Copyright (c) tianchenglin
*  @Author TCL
*  @Date 2016.6.22
*/

package com.study.tcl.quickindex;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.widget.ListView;
import android.widget.TextView;

import com.study.tcl.quickindex.adapter.MyListAdapter;
import com.study.tcl.quickindex.domain.Friend;
import com.study.tcl.quickindex.utils.PinYinUtils;
import com.study.tcl.quickindex.view.QuickIndexBar;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class MainActivity extends Activity {

private QuickIndexBar mQuickIndexBar;
private ListView mListView;
private List<Friend> friends;
private TextView mCurrentLetter;

private Handler mHandler = new Handler();

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);

mQuickIndexBar = (QuickIndexBar) findViewById(R.id.quickIndexBar);
mListView = (ListView) findViewById(R.id.listView);
mCurrentLetter = (TextView) findViewById(R.id.currentLetter);

//1.准备数据
fillList();
//2.对集合进行排序
Collections.sort(friends);

//3.设置adapter
mListView.setAdapter(new MyListAdapter(this, friends));

mQuickIndexBar.setOnTouchLetterListener(new QuickIndexBar.onTouchLetterListener() {
@Override
public void onTouchLetter(String letter) {
//                Log.e("letter", letter);
//根据当前触摸的字母,去集合中找哪个item

for (int i = 0; i < friends.size(); i++) {
String firstLetter = friends.get(i).getPinyin().charAt(0) + "";
if (letter.equals(firstLetter)) {
//将当前item放到屏幕顶端
mListView.setSelection(i);
break;//找到第一个就行了
}
}

//显示当前显示的字母
mCurrentLetter.setVisibility(View.VISIBLE);
mCurrentLetter.setText(letter);

//先移除之前的任务
mHandler.removeCallbacksAndMessages(null);
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
mCurrentLetter.setVisibility(View.GONE);
}
}, 1500);
}
});

Log.e("pinyin", PinYinUtils.getPinYin("田成琳"));

}

private void fillList() {
friends = new ArrayList<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("陈坤"));
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"));
}
}


MyListAdapter:

/*
*  @Copyright (c) tianchenglin
*  @Author TCL
*  @Date 2016.6.23
*/

package com.study.tcl.quickindex.adapter;

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import com.study.tcl.quickindex.R;
import com.study.tcl.quickindex.domain.Friend;
import com.study.tcl.quickindex.utils.PinYinUtils;

import java.util.List;

/**
* Created by TCL on 2016/6/23.
*/
public class MyListAdapter extends BaseAdapter {
private List<Friend> mFriends;
private Context mContext;

public MyListAdapter(Context context, List<Friend> friends) {
mFriends = friends;
mContext = context;
}

@Override
public int getCount() {
return mFriends.size();
}

@Override
public Object getItem(int position) {
return mFriends.get(position);
}

@Override
public long getItemId(int position) {
return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = View.inflate(mContext, R.layout.adapter_friend, null);
holder = new ViewHolder();
holder.tv_letter = (TextView) convertView.findViewById(R.id.tv_letter);
holder.tv_name = (TextView) convertView.findViewById(R.id.tv_name);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}

Friend friend = mFriends.get(position);
String currentWord = PinYinUtils.getPinYin(friend.getName()).charAt(0) + "";//此处注意异常
if (position > 0) {
//获取上一个item首字母
String lastWord = mFriends.get(position - 1).getPinyin().charAt(0) + "";
//拿当前的首字母和上一个比较
if (currentWord.equals(lastWord)) {
//说明首字母相同
holder.tv_letter.setVisibility(View.GONE);
} else {
holder.tv_letter.setVisibility(View.VISIBLE);
holder.tv_letter.setText(currentWord);
}
} else {
holder.tv_letter.setVisibility(View.VISIBLE);
holder.tv_letter.setText(currentWord);
}
holder.tv_name.setText(friend.getName());
return convertView;
}

static class ViewHolder {
TextView tv_letter;
TextView tv_name;
}
}
PinyinUtils:

/*
*  @Copyright (c) tianchenglin
*  @Author TCL
*  @Date 2016.6.23
*/

package com.study.tcl.quickindex.utils;

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;

/**
* Created by TCL on 2016/6/23.
*/
public class PinYinUtils {

/**
* 获取文字拼音,会消耗一定资源,不应该被频繁调用
*
* @param chinese
* @return
*/
public static String getPinYin(String chinese) {
if (!TextUtils.isEmpty(chinese)) {
//1.由于只能对单个汉子进行转化,所以需要将字符串转化成字符数组,然后对每个字符进行转化,最后拼接
char[] chars = chinese.toCharArray();
StringBuilder sb = new StringBuilder();
HanyuPinyinOutputFormat hanyuPinyinOutputFormat = new HanyuPinyinOutputFormat();
hanyuPinyinOutputFormat.setCaseType(HanyuPinyinCaseType.UPPERCASE);//设置转化的拼音是大写字母
hanyuPinyinOutputFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);//没有声调
//            hanyuPinyinOutputFormat.setVCharType();

for (int i = 0; i < chars.length; i++) {
//2.过滤空格
if (Character.isSpaceChar(chars[i])) {
continue;
}
//3.判断是否是汉字,汉字占两个字节,一个字节范围是-128~127
if (chars[i] > 127) {
//可能是汉字
try {
String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(chars[i], hanyuPinyinOutputFormat);
if (pinyinArray != null) {
sb.append(pinyinArray[0]);//取第0个
} else {
//没有找到拼音,可能不是汉字,则忽略
}
} catch (BadHanyuPinyinOutputFormatCombination badHanyuPinyinOutputFormatCombination) {
badHanyuPinyinOutputFormatCombination.printStackTrace();
//说明转化失败,不是汉字,则忽略
}
} else {
//这些字符能排序,不能获取拼音
sb.append(chars[i]);
}
}
return sb.toString();
}
return null;
}
}


Bean(Friend):

/*
*  @Copyright (c) tianchenglin
*  @Author TCL
*  @Date 2016.6.23
*/

package com.study.tcl.quickindex.domain;

import com.study.tcl.quickindex.utils.PinYinUtils;

/**
* Created by TCL on 2016/6/23.
*/
public class Friend implements Comparable<Friend> {
private String name;
private String pinyin;

public Friend(String name) {
this.name = name;

//一开始就设置好拼音
setPinyin(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(Friend another) {
return getPinyin().compareTo(another.getPinyin());
}
}


activity_main:

<?xml version="1.0" encoding="utf-8"?>
<!--
~  @Copyright (c) tianchenglin
~  @Author TCL
~  @Date 2016.6.22
-->

<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.study.tcl.quickindex.MainActivity">

<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent">

</ListView>

<!--android:background="#B51421"-->
<com.study.tcl.quickindex.view.QuickIndexBar
android:id="@+id/quickIndexBar"
android:layout_width="30dp"
android:layout_height="match_parent"
android:layout_alignParentRight="true">
</com.study.tcl.quickindex.view.QuickIndexBar>

<TextView
android:id="@+id/currentLetter"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_centerInParent="true"
android:background="@drawable/bg"
android:gravity="center"
android:textColor="#ffffff"
android:visibility="gone"
android:textSize="50dp"/>

</RelativeLayout>


运行结果:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: