快速索引 (对View的自定义)
* 应用场景: 微信好友列表, 联系人通讯录, 应用管理, 文件管理
* 功能实现:
1. A-Z索引的绘制. OK
2. 处理Touch事件. OK3. 提供使用监听\回调. OK
4. 汉字转换成拼音. OK
5. 进行排序展示. OK6. 进行分组. OK
7. 将自定义控件和ListView合体. OK
1.自定义view Myindex 类
//自定义一个view,自己画一个索引bar出来
public class Myindex extends View {
private Paint paint;
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" };
private float measuredHeight;
private float measuredWidth;
private float aveHeight;
private OntextChangeListener listener;
//定义接口,设置监听,当按下的时候就将按下的那个字母返回给监听方
public interface OntextChangeListener{
void getText(String letters);
}
public void setOntextChangeListener(OntextChangeListener listener){
this.listener = listener;
}
public Myindex(Context context) {
super(context);
init();
}
public Myindex(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public Myindex(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
//设置画笔的属性
paint = new Paint(Paint.ANTI_ALIAS_FLAG);//去掉锯齿
paint.setColor(Color.WHITE);//白色
paint.setTextSize(30);//大小
paint.setTypeface(Typeface.DEFAULT_BOLD);//加粗
}
//重新ondraw方法,设置画布,宽高在xml中定义了
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (int i = 0; i < LETTERS.length; i++) {
String text = LETTERS[i];
//文字的x轴坐标 = 宽度的一半-文字的一半
float x = measuredWidth / 2.0f - paint.measureText(text) / 2;
//通过矩形获取文字的高度
Rect bounds = new Rect();
paint.getTextBounds(text, 0, text.length(), bounds);
int textHeight = bounds.height();
//文字的y坐标
float y = aveHeight / 2.0f + textHeight / 2.0f + i * aveHeight;
//设置按下的画笔描绘颜色
paint.setColor(i==preindex?Color.GRAY:Color.WHITE);
canvas.drawText(text, x, y, paint);
}
}
private int preindex = -1;
@Override
public boolean onTouchEvent(MotionEvent event) {
int index = -1;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
index = (int) (event.getY() / aveHeight);
//如果点击的字母和上一个字母不同则让执行监听(没有必要一直执行,因为按的是同一个)
if (index != preindex) {
if(listener!=null){
listener.getText(LETTERS[index]);
}
preindex = index;
}
break;
case MotionEvent.ACTION_MOVE:
//移动和按下一样
index = (int) (event.getY() / aveHeight);
if (index != preindex) {
if(listener!=null){
listener.getText(LETTERS[index]);
}
preindex = index;
}
break;
case MotionEvent.ACTION_UP:
break;
default:
break;
}
invalidate();//保存一下改变的状态
return true;//可以一直接收移动的变化
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 拿到view的宽高
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
measuredHeight = getMeasuredHeight();
measuredWidth = getMeasuredWidth();
//计算一个字母的高(总共26个字母)
aveHeight = measuredHeight / LETTERS.length;
}
}
2.MainActivity类,实现监听,点击跳转到相应联系人
//快速索引
public class MainActivity extends Activity {
private ArrayList<Person> arrayList;
private ListView listView;
private TextView tv_center;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Myindex myindex = (Myindex) findViewById(R.id.index);
listView = (ListView)findViewById(R.id.lv_main);
tv_center = (TextView)findViewById(R.id.tv_center);
//给自定义的view设置监听,这样就可以自定义的view独立存在
myindex.setOntextChangeListener(new OntextChangeListener() {
@Override
public void getText(String letters) {
//ToastUtil.showToast(MainActivity.this, letters);
//展示大字母显示
setLocationShow(letters);
//将索引和listview结合
for(int i=0;i<arrayList.size();i++){
String pinyin = arrayList.get(i).getPinyin().charAt(0)+"";
if(TextUtils.equals(letters, pinyin)){//如果索引的字母和集合中的首字母一样,则跳到该位置
listView.setSelection(i);
break;//不加break,则会持续跳转到,该字母组中的最后一个
}
}
}
});
arrayList = new ArrayList<Person>();
fillData(arrayList);
listView.setAdapter(new haohanAdapter(MainActivity.this,arrayList));
}
Handler handler = new Handler(){
public void handleMessage(android.os.Message msg) {
if(msg.what==0){
tv_center.setVisibility(View.GONE);
}
};
};
protected void setLocationShow(String letters) {
tv_center.setText(letters);
tv_center.setVisibility(View.VISIBLE);
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
handler.sendEmptyMessage(0);
}
}, 1000);
}
//填充数据到集合中
private void fillData(ArrayList<Person> arrayList) {
for(int i=0;i<Cheeses.NAMES.length;i++){
arrayList.add(new Person(Cheeses.NAMES[i]));
}
Collections.sort(arrayList);
}
}
3.适配器
public class haohanAdapter extends BaseAdapter{
private Context context;
private ArrayList<Person> arrayList;
private Viewholder viewholder;
public haohanAdapter(Context context, ArrayList<Person> arrayList) {
this.context = context;
this.arrayList = arrayList;
}
@Override
public int getCount() {
return arrayList.size();
}
@Override
public Object getItem(int position) {
return arrayList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view;
if(convertView == null){
viewholder = new Viewholder();
view = View.inflate(context, R.layout.item_list, null);
viewholder.head = (TextView) view.findViewById(R.id.tv_index);
viewholder.content = (TextView) view.findViewById(R.id.tv_name);
view.setTag(viewholder);
}else{
view = convertView;
viewholder = (Viewholder) view.getTag();
}
Person person = arrayList.get(position);
String letter = person.getPinyin().charAt(0)+"";
if(position==0){
viewholder.head.setVisibility(View.VISIBLE);//如果位置为0,显示首字母
}else{
String preletter = arrayList.get(position-1).getPinyin().charAt(0)+"";
if(TextUtils.equals(letter, preletter)){//如果上一个和下一个相同,下一个的首字母不显示
viewholder.head.setVisibility(View.GONE);
}else{
viewholder.head.setVisibility(View.VISIBLE);
}
}
viewholder.head.setText(letter);
viewholder.content.setText(person.getName());
return view;
}
static class Viewholder{
TextView head;
TextView content;
}
}
4.文字转换成拼音
public class PinyinUtils {
/**
* 根据传入的字符串(包含汉字),得到拼音
* 罗大爷 -> LUODAYE
* 罗 大爷*& -> LUODAYE
* 罗 大爷f5 -> LUODAYE
* @param str 字符串
* @return
*/
public static String getPinyin(String str) {
HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
format.setCaseType(HanyuPinyinCaseType.UPPERCASE);
format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
StringBuilder sb = new StringBuilder();
char[] charArray = str.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.Person类,实现了接口,设置排序
public class Person implements Comparable<Person>{
private String name;
private String pinyin;
public Person(String name) {
super();
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(Person another) {
return this.pinyin.compareTo(another.getPinyin());
}
}