自定义控件的绘制:
package com.it.quickindex.ui;
import com.it.quickindex.util.Cheeses;
import com.it.quickindex.util.Utils;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
/**
* 快速索引条
* @author poplar
*
*/
public class QuickIndexBar extends View {
public 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 Paint paint;
private float cellHeight; // 单元格高度
private int cellWidth; // 单元格宽度
private OnLetterChangeListener mOnLetterChangeListener;
/**
* 字母更新监听
* @author poplar
*
*/
public interface OnLetterChangeListener{
void onLetterChange(String letter);
}
/**
* 设置监听器
* @param mOnLetterChangeListener
*/
public void setOnLetterChangeListener(OnLetterChangeListener mOnLetterChangeListener){
this.mOnLetterChangeListener = mOnLetterChangeListener;
}
/**
* 构造方法
* @param context
*/
public QuickIndexBar(Context context) {
this(context, null);
}
public QuickIndexBar(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public QuickIndexBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
//抗锯齿
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.WHITE);
paint.setTextSize(25);
//加粗
paint.setTypeface(Typeface.DEFAULT_BOLD);
}
/**
* 绘制索引字母表
*/
@Override
protected void onDraw(Canvas canvas) {
// 把所有字母画到画板上
for (int i = 0; i < LETTERS.length; i++) {
String letter = LETTERS[i];
// 计算水平坐标(字母控件左侧坐标)
int x = (int) (cellWidth * 0.5f - paint.measureText(letter) * 0.5f);
// 计算垂直坐标(左下角为textView的坐标)
// 将一个文本的指定区域放置到 bounds的矩形对象中,并将值封装给bound
Rect bounds = new Rect();
paint.getTextBounds(letter, 0, letter.length(), bounds);
int y = (int) (cellHeight * 0.5f + bounds.height() * 0.5f + cellHeight * i);
// 设置画笔颜色, 如果是被触摸的, 设置灰色
paint.setColor(i == currentIndex ? Color.GRAY : Color.WHITE);
// 绘制文本
canvas.drawText(letter, x, y, paint);
}
}
int currentIndex = -1;
@Override
public boolean onTouchEvent(MotionEvent event) {
int index;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// 根据当前的y值, 计算得到字母的索引
index = (int) (event.getY() / cellHeight);
if(index != currentIndex){
// 如果发生了变化, 才走到这里边
if(index >= 0 && index < LETTERS.length){
// 获取到手指按下的字母
System.out.println(LETTERS[index]);
if(mOnLetterChangeListener != null){
mOnLetterChangeListener.onLetterChange(LETTERS[index]);
}
}
currentIndex = index;
}
break;
case MotionEvent.ACTION_MOVE:
index = (int) (event.getY() / cellHeight);
if(index != currentIndex) {
// 如果发生了变化, 才走到这里边
if(index >= 0 && index < LETTERS.length){
// 获取到手指按下的字母
System.out.println(LETTERS[index]);
if(mOnLetterChangeListener != null){
mOnLetterChangeListener.onLetterChange(LETTERS[index]);
}
}
currentIndex = index;
}
break;
case MotionEvent.ACTION_UP:
currentIndex = -1;
break;
default:
break;
}
// 重绘界面
invalidate();
// 由本控件消费事件
return true;
}
/**
* 测量控件的尺寸
*/
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
cellWidth = getMeasuredWidth();
int mHeight = getMeasuredHeight();
cellHeight = mHeight * 1.0f / LETTERS.length;
}
}
主页布局文件:
<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=".MainActivity" >
<ListView
android:id="@+id/lv_haohan"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView>
<com.itheima57.quickindex.ui.QuickIndexBar
android:id="@+id/quickIndexBar"
android:layout_width="30dp"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:background="#FF0000" />
<TextView
android:id="@+id/tv_center"
android:visibility="gone"
android:layout_width="140dp"
android:layout_height="80dp"
android:layout_centerInParent="true"
android:background="@drawable/shape_bg_index"
android:gravity="center"
android:text="A"
android:textColor="#FFFFFF"
android:textSize="28sp" />
</RelativeLayout>
MainActivity:
package com.it.quickindex;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.text.TextUtils;
import android.view.View;
import android.view.Window;
import android.widget.ListView;
import android.widget.TextView;
import com.itheima57.quickindex.adapter.HaoHanAdapter;
import com.itheima57.quickindex.domain.HaoHan;
import com.itheima57.quickindex.ui.QuickIndexBar;
import com.itheima57.quickindex.ui.QuickIndexBar.OnLetterChangeListener;
import com.itheima57.quickindex.util.Cheeses;
public class MainActivity extends Activity {
private TextView tv_center;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
//获取索引弹窗控件
tv_center = (TextView) findViewById(R.id.tv_center);
//获取联系人列表ListView控件
final ListView lv_haohan = (ListView) findViewById(R.id.lv_haohan);
final List<HaoHan> persons = new ArrayList<HaoHan>();
// 填充并排序
fillAndSortData(persons);
lv_haohan.setAdapter(new HaoHanAdapter(this, persons));
QuickIndexBar quickIndexBar = (QuickIndexBar) findViewById(R.id.quickIndexBar);
// 给自定义索引设置监听(选择右侧索引,左侧listView跳转到相应的位置)
quickIndexBar.setOnLetterChangeListener(new OnLetterChangeListener() {
@Override
public void onLetterChange(String letter) {
// Utils.showToast(getApplicationContext(), "letter: " + letter);
showCenterLetter(letter);
// 将ListView调到 , 首次出现 letter 的条目
for (int i = 0; i < persons.size(); i++) {
String l = persons.get(i).getPinyin().charAt(0) + "";
if(TextUtils.equals(l, letter)){
// 找到了, 跳转到指定位置
lv_haohan.setSelection(i);
break;
}
}
}
});
}
private Handler mHandler = new Handler();
protected void showCenterLetter(String letter) {
tv_center.setText(letter);
tv_center.setVisibility(View.VISIBLE);
// 移除刚刚所有发出的消息(防止之前的消息还没显示结束再显示新消息出现闪屏)
mHandler.removeCallbacksAndMessages(null);
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
tv_center.setVisibility(View.GONE);
}
}, 1500);
}
/**
* 将数据封装进集合并且排序
* @param persons
*/
private void fillAndSortData(List<HaoHan> persons) {
HaoHan haoHan;
for (int i = 0; i < Cheeses.NAMES.length; i++) {
String name = Cheeses.NAMES[i];
haoHan = new HaoHan(name);
persons.add(haoHan);
}
// 排序
Collections.sort(persons);
}
}
haohanAdapter:
实现相同索引字母的时候只显示一个标题头。
package com.itheima57.quickindex.adapter;
import java.util.List;
import android.content.Context;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import com.itheima57.quickindex.R;
import com.itheima57.quickindex.domain.HaoHan;
public class HaoHanAdapter extends BaseAdapter {
private final List<HaoHan> persons;
private final Context context;
public HaoHanAdapter(Context context, List<HaoHan> persons) {
this.context = context;
this.persons = persons;
}
@Override
public int getCount() {
return persons.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) {
View view;
if(convertView == null){
view = View.inflate(context, R.layout.item_list_haohan, null);
}else {
view = convertView;
}
// 索引字母
TextView tv_index = (TextView) view.findViewById(R.id.tv_index);
// 名称
TextView tv_name = (TextView) view.findViewById(R.id.tv_name);
HaoHan haoHan = persons.get(position);
String currentLetter = haoHan.getPinyin().charAt(0) + "";
// 分组, 只显示首次出现新的字母的条目索引
String indexStr = null;
if(position == 0){
// 当前是第一个条目, 直接显示
indexStr = currentLetter;
}else {
// 不是第一个条目, 跟前一个比较
// 前一个拼音首字母
String previousLetter = persons.get(position - 1).getPinyin().charAt(0) + "";
if(!TextUtils.equals(previousLetter, currentLetter)){
// 不相同时, 显示当前的索引栏
indexStr = currentLetter;
}
}
tv_index.setVisibility(indexStr == null ? View.GONE : View.VISIBLE);
tv_index.setText(currentLetter);
tv_name.setText(haoHan.getName());
return view;
}
}