1.布局
一个ListView,联系人的信息
一个TextView,显示字母
一个自定义的IndexView,在布局的右边,填充字母
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.quickindex.MainActivity">
<ListView
android:id="@+id/lv"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<TextView
android:visibility="gone"
android:layout_centerInParent="true"
android:id="@+id/tv_word"
android:text="A"
android:textSize="40sp"
android:background="#44000000"
android:layout_width="80dp"
android:layout_height="80dp"
android:gravity="center"
android:textColor="#000000"
/>
<com.example.quickindex.IndexView
android:id="@+id/iv_words"
android:layout_width="30dp"
android:background="#ff0000"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
/>
</RelativeLayout>
2.绘制字母的位置
//1.把26个字母放入数组
//2.在onDraw计算每条的高itemHeight 和 宽itemWidth
//3.在ondraw计算wordWidth,wordHeight,wordX,wordY
已知:
itemWidth = viewWidth;
itemHeight = viewHeight / 26;
String word = words[i];//A
Rect rect = new Rect();
paint.getTextBounds(word,0,1,rect);
//字母的高和宽
wordWidth = rect.width();
wordHeight = rect.height();
//计算每个字母在视图上的坐标
wordX=itemWidth/2 - wordWidth/2;
wordY=itemHeight/2+wordHeight/2+ (i*itemHeight);
Canvas.drawText(word,wordX,wordY,paint);
public class IndexView extends View {
private Paint paint;
private String[] words={"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 int itemWidth;
private int itemHeight;
public IndexView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.WHITE);
paint.setTypeface(Typeface.DEFAULT_BOLD);//设置粗体字
paint.setTextSize(45);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
itemWidth = getMeasuredWidth();
itemHeight = getMeasuredHeight() / words.length;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for(int i = 0;i < words.length;i++){
String word = words[i];//A
Rect rect = new Rect();
//画笔
//0,1的取一个字母
paint.getTextBounds(word,0,1,rect);
//字母的高和宽
int wordWidth = rect.width();
int wordHeight = rect.height();
//计算每个字母在视图上的坐标
float wordX=itemWidth/2 - wordWidth/2;
float wordY=itemHeight/2+wordHeight/2+ (i*itemHeight);
canvas.drawText(word,wordX,wordY,paint);
}
}
}
3.设置手指按下字母变颜色
* 1.重写onTouchEvent(),返回true,在down.move的过程中计算 * int touchIndex = getY() / itemHeight;强制绘制
* 2.在onDraw()对应的下标设置画笔变色
* 3.在up的时候 * touchIndex = -1; * 强制绘制
if(touchIndex == i){
//设置灰色
paint.setColor(Color.GRAY);
}else {
//设置白色
paint.setColor(Color.WHITE);
}
//字母的下标位置
private int touchIndex = -1;
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
float Y = event.getY();
int index = (int)(Y / itemHeight);
if(index != touchIndex){
touchIndex = index;
invalidate();//强制绘制onDraw()
}
break;
case MotionEvent.ACTION_UP:
touchIndex = -1;
invalidate();//强制绘制onDraw()
break;
}
return true;
}
4.设置手指按下字母的同时显示TextView
调用接口
什么时候用接口:有变化,并且要把变化告诉外界的情况下
/**
* 字母下标索引变化的监听器
*/
public interface OnIndexChangeListener{
/**
* 当字母下标位置发生变化的时候回调
* @param word 字母
*/
void onIndexChange(String word);
}
private OnIndexChangeListener onIndexChangeListener;
/**
* 设置字母下标索引变化的监听
* @param onIndexChangeListener
*/
public void setOnIndexChangeListener(OnIndexChangeListener onIndexChangeListener){
this.onIndexChangeListener = onIndexChangeListener;
}
在onTouchEvent里面
if(onIndexChangeListener !=null && touchIndex< words.length){
onIndexChangeListener.onIndexChange(words[touchIndex]);
}
MainActivity.java
//设置监听字母下标索引的变化
iv_words.setOnIndexChangeListener(new IndexView.OnIndexChangeListener() {
/**
*
* @param word 字母
*/
@Override
public void onIndexChange(String word) {
updateWord(word);
}
});
private void updateWord(String word) {
//显示
tv_word.setVisibility(View.VISIBLE);
tv_word.setText(word);
}
利用Handler使TextView显示几秒后消失
private Handler handler = new Handler();
handler.removeCallbacksAndMessages(null);
handler.postDelayed(new Runnable() {
@Override
public void run() {
//也是运行主线程
tv_word.setVisibility(View.GONE);
}
},2000);
5.根据字母索引到名字
隐藏相同的字母:
if(position == 0){
viewHolder.tv_word.setVisibility(View.VISIBLE);
}else {
//得到前一个位置对应的字母,如果当前字母和上一个字母相同,隐藏。
String preword = persons.get(position-1).getPinyin().substring(0,1);
if(word.equals(preword)){
viewHolder.tv_word.setVisibility(View.GONE);
}else {
viewHolder.tv_word.setVisibility(View.VISIBLE);
}
}
根据字母找到对应的名字:
private void updateListView(String word) {
for(int i = 0;i<persons.size();i++){
String listWord = persons.get(i).getPinyin().substring(0,1);
if(word.equals(listWord)){
//i是Listview钟的位置
lv.setSelection(i);//定位到ListView钟的某个位置
return;
}
}
}
源码:
MainActivity
public class MainActivity extends Activity {
private ListView lv;
private TextView tv_word;
private IndexView iv_words;
private Handler handler = new Handler();
private ArrayList<Person> persons;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lv = (ListView) findViewById(R.id.lv);
tv_word=(TextView)findViewById(R.id.tv_word);
iv_words=(IndexView)findViewById(R.id.iv_words);
//准备数据
initData();
//设置适配器
lv.setAdapter(new IndexAdpater());
//设置监听字母下标索引的变化
iv_words.setOnIndexChangeListener(new IndexView.OnIndexChangeListener() {
/**
*
* @param word 字母
*/
@Override
public void onIndexChange(String word) {
updateWord(word);
updateListView(word);
}
});
}
private void updateListView(String word) {
for(int i = 0;i<persons.size();i++){
String listWord = persons.get(i).getPinyin().substring(0,1);
if(word.equals(listWord)){
//i是Listview钟的位置
lv.setSelection(i);//定位到ListView钟的某个位置
return;
}
}
}
private void updateWord(String word) {
//显示
tv_word.setVisibility(View.VISIBLE);
tv_word.setText(word);
handler.removeCallbacksAndMessages(null);
handler.postDelayed(new Runnable() {
@Override
public void run() {
//也是运行主线程
tv_word.setVisibility(View.GONE);
}
},2000);
}
class IndexAdpater extends BaseAdapter {
@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) {
ViewHolder viewHolder;
if(convertView == null){
convertView = View.inflate(MainActivity.this,R.layout.item_main,null);
viewHolder = new ViewHolder();
viewHolder.tv_word = (TextView)convertView.findViewById(R.id.tv_word);
viewHolder.tv_name = (TextView)convertView.findViewById(R.id.tv_name);
convertView.setTag(viewHolder);
}else {
viewHolder = (ViewHolder)convertView.getTag();
}
String name = persons.get(position).getName();
String word = persons.get(position).getPinyin().substring(0,1);
viewHolder.tv_word.setText(word);
viewHolder.tv_name.setText(name);
if(position == 0){
viewHolder.tv_word.setVisibility(View.VISIBLE);
}else {
//得到前一个位置对应的字母,如果当前字母和上一个字母相同,隐藏。
String preword = persons.get(position-1).getPinyin().substring(0,1);
if(word.equals(preword)){
viewHolder.tv_word.setVisibility(View.GONE);
}else {
viewHolder.tv_word.setVisibility(View.VISIBLE);
}
}
return convertView;
}
}
static class ViewHolder{
TextView tv_word;
TextView tv_name;
}
private void initData(){
persons = new ArrayList<>();
persons.add(new Person("张三"));
persons.add(new Person("胡三"));
persons.add(new Person("杨三"));
persons.add(new Person("刘三"));
persons.add(new Person("钟三"));
persons.add(new Person("尹三"));
persons.add(new Person("安三"));
persons.add(new Person("张三三"));
persons.add(new Person("温三"));
persons.add(new Person("李三三"));
persons.add(new Person("刘三三"));
persons.add(new Person("娄三"));
persons.add(new Person("张四三"));
persons.add(new Person("王三"));
persons.add(new Person("李五三"));
persons.add(new Person("孙三"));
persons.add(new Person("唐三"));
persons.add(new Person("牛三"));
persons.add(new Person("姜三"));
persons.add(new Person("刘五三"));
persons.add(new Person("侯三"));
persons.add(new Person("乔三"));
persons.add(new Person("徐三"));
persons.add(new Person("吴三"));
persons.add(new Person("啊三"));
//排序
Collections.sort(persons, new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return o1.getPinyin().compareTo(o2.getPinyin());
}
});
}
}
Person
public class Person {
public Person(String name){
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;
}
private String name;
private String pinyin;
}
IndexView
public class IndexView extends View {
private Paint paint;
private String[] words={"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 int itemWidth;
private int itemHeight;
public IndexView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.WHITE);
paint.setTypeface(Typeface.DEFAULT_BOLD);//设置粗体字
paint.setTextSize(45);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
itemWidth = getMeasuredWidth();
itemHeight = getMeasuredHeight() / words.length;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for(int i = 0;i < words.length;i++){
if(touchIndex == i){
//设置灰色
paint.setColor(Color.GRAY);
}else {
//设置白色
paint.setColor(Color.WHITE);
}
String word = words[i];//A
Rect rect = new Rect();
//画笔
//0,1的取一个字母
paint.getTextBounds(word,0,1,rect);
//字母的高和宽
int wordWidth = rect.width();
int wordHeight = rect.height();
//计算每个字母在视图上的坐标
float wordX=itemWidth/2 - wordWidth/2;
float wordY=itemHeight/2+wordHeight/2+ (i*itemHeight);
canvas.drawText(word,wordX,wordY,paint);
}
}
/**
* 手指按下文字变色
* 1.重写onTouchEvent(),返回true,在down.move的过程中计算
* int touchIndex = getY() / itemHeight;强制绘制
*
* 2.在onDraw()对应的下标设置画笔变色
*
* 3.在up的时候
* touchIndex = -1;
* 强制绘制
*/
//字母的下标位置
private int touchIndex = -1;
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
float Y = event.getY();
int index = (int)(Y / itemHeight);
if(index != touchIndex){
touchIndex = index;
invalidate();//强制绘制onDraw()
if(onIndexChangeListener !=null && touchIndex< words.length){
onIndexChangeListener.onIndexChange(words[touchIndex]);
}
}
break;
case MotionEvent.ACTION_UP:
touchIndex = -1;
invalidate();
break;
}
return true;
}
/**
* 字母下标索引变化的监听器
*/
public interface OnIndexChangeListener{
/**
* 当字母下标位置发生变化的时候回调
* @param word 字母
*/
void onIndexChange(String word);
}
private OnIndexChangeListener onIndexChangeListener;
/**
* 设置字母下标索引变化的监听
* @param onIndexChangeListener
*/
public void setOnIndexChangeListener(OnIndexChangeListener onIndexChangeListener){
this.onIndexChangeListener = onIndexChangeListener;
}
}
item_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/tv_word"
android:textSize="25sp"
android:text="A"
android:textColor="#000000"
android:background="#44000000"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/tv_name"
android:textSize="25sp"
android:text="张三"
android:textColor="#000000"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.quickindex.MainActivity">
<ListView
android:id="@+id/lv"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<TextView
android:visibility="gone"
android:layout_centerInParent="true"
android:id="@+id/tv_word"
android:text="A"
android:textSize="40sp"
android:background="#44000000"
android:layout_width="80dp"
android:layout_height="80dp"
android:gravity="center"
android:textColor="#000000"
/>
<com.example.quickindex.IndexView
android:id="@+id/iv_words"
android:layout_width="30dp"
android:background="#ff0000"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
/>
</RelativeLayout>