标签:
在玩即时通讯app比如微信的联系人列表的时候,发现联系人列表的右侧有个竖排的字母索引,点击字母,可以快速索引到相应的联系人。本篇就是实现这个功能。
View
public class QuickIndexBar extends View
|
并提供构造器方法,在构造器中完成相应的初始化工作:
private String[] indexArr; public QuickIndexBar(Context context) { this(context, null); } public QuickIndexBar(Context context, AttributeSet attrs) { this(context, attrs, 0); } public QuickIndexBar(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { indexArr = 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"}; paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setColor(Color.DKGRAY); paint.setTextAlign(Paint.Align.CENTER); paint.setTextSize(20); } |
下面开始画:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float center = getWidth() / 2;
height = getHeight() / indexArr.length;
for (int i = indexArr.length - 1; i > -1; i--) {
canvas.drawText(indexArr[i], center, height * (i + 1), paint);
}
}
|
此时运行,发现字母索引在屏幕的中间位置。好的,这是第一步。其中,索引的每个字母都是通过drawText(...)
方法画上去的,每个字母的x坐标不变,y坐标进行相应的变化(不难理解),需要知道的是:屏幕的坐标是这样的,左上角是坐标原点,向右是x正轴,向下是y轴正轴。
我们看到联系人列表的每个Item包括一个图标和名字,还有相应的TAG,新建实体类People
,这里为了能够对最后的联系人排序,我们实现了Comparable<T>
接口,并实现了接口的compareTo(...)
方法,这里用到了工具类HanziToPinyin.java
,这个工具类是我从Android 4.2源代码中抽出来的,当然,如果你没有源码,也可以去github上找一个。
package com.dystu.quickindexbar; /** * Created by Administrator on 2015/5/6. */ public class People implements Comparable<People> { private String name; private int imageId; private String header; public People() { } public People(String name, int imageId) { this.name = name; this.imageId = imageId; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getImageId() { return imageId; } public void setImageId(int imageId) { this.imageId = imageId; } public String getHeader() { return header; } public void setHeader(String header) { this.header = header; } @Override public int compareTo(People another) { return (HanziToPinyin.getInstance() .get(this.getName().substring(0, 1)).get(0).target.substring(0, 1).toUpperCase()) .compareTo(HanziToPinyin.getInstance() .get(another.getName().substring(0, 1)).get(0).target.substring(0, 1).toUpperCase()); } } |
新建PeopleAdapter
继承自ArrayAdapter<T>
,这里我们知道,联系人列表根据首字母有个相应的TAG,那么这个TAG如何处理,这个先放放。
核心代码如下:
public PeopleAdapter(Context context, int textViewResourceId, List<People> objects) { super(context, textViewResourceId, objects); resourceId = textViewResourceId; } @Override public View getView(int position, View convertView, ViewGroup parent) { View view; ViewHolder viewHolder; if (convertView == null) { view = LayoutInflater.from(getContext()).inflate(resourceId, null); viewHolder = new ViewHolder(); viewHolder.peopleImage = (ImageView) view.findViewById(R.id.people_image); viewHolder.peopleName = (TextView) view.findViewById(R.id.people_name); viewHolder.tvHeader = (TextView) view.findViewById(R.id.header); view.setTag(viewHolder); } else { view = convertView; viewHolder = (ViewHolder) view.getTag(); } People people = getItem(position); String header = people.getHeader(); if (position == 0||header != null && !header.equals(getItem(position-1).getHeader())) { if ("".equals(header)) { viewHolder.tvHeader.setVisibility(View.GONE); } else { viewHolder.tvHeader.setVisibility(View.VISIBLE); viewHolder.tvHeader.setText(header); } } else { viewHolder.tvHeader.setVisibility(View.GONE); } viewHolder.peopleName.setText(people.getName()); viewHolder.peopleImage.setImageResource(people.getImageId()); return view; } @Override public People getItem(int position) { return super.getItem(position); } @Override public int getCount() { return super.getCount(); } |
在Activity
中,初始化ListView的数据,还是先看下Activity
的布局:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <RelativeLayout android:id="@+id/rl_list" android:layout_width="match_parent" android:layout_height="match_parent"> <ListView android:id="@+id/list" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/transparent" android:cacheColorHint="#00000000" android:descendantFocusability="afterDescendants" android:divider="@color/divider_list" android:dividerHeight="1px" android:fastScrollEnabled="false" /> <com.dystu.quickindexbar.QuickIndexBar android:id="@+id/sidebar" android:layout_width="25dp" android:layout_height="match_parent" android:layout_alignParentRight="true" android:background="@android:color/transparent" android:clickable="true" /> <TextView android:id="@+id/floating_header" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:background="@drawable/show_head_toast_bg" android:gravity="center" android:paddingLeft="25dp" android:paddingRight="25dp" android:textColor="@android:color/white" android:textSize="40sp" android:visibility="invisible" /> </RelativeLayout> </FrameLayout> |
如果你用的是Android Studio的话,那么你可以看到效果了,索引列表已经显示在ListView之上了,那么TextView是手指按下哪个字母进行提示的,手指抬起,他就消失。
package com.dystu.quickindexbar; import android.app.Activity; import android.os.Bundle; import android.widget.ListView; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; public class MainActivity extends Activity { private List<People> peopleList; private PeopleAdapter adapter; private ListView list; private QuickIndexBar sideBar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); peopleList = new ArrayList<>(); peopleList.clear(); initPeople(); list = (ListView) findViewById(R.id.list); sideBar = (QuickIndexBar) findViewById(R.id.sidebar); adapter = new PeopleAdapter(MainActivity.this, R.layout.people_item, peopleList); list.setAdapter(adapter); sideBar.setListView(list); for (int i = 0; i < peopleList.size(); i++) { People people = peopleList.get(i); String userName = people.getName(); people.setName(userName); setUserHeader(userName, people); } } private void setUserHeader(String userName, People people) { String headerName = null; headerName = people.getName(); System.out.println("headerName:" + headerName); if (Character.isDigit(headerName.charAt(0))) { people.setHeader("#"); } else { people.setHeader(HanziToPinyin.getInstance().get(headerName.substring(0, 1)).get(0).target.substring(0, 1).toUpperCase()); char header = people.getHeader().toLowerCase().charAt(0); if (header < ‘a‘ || header > ‘z‘) { people.setHeader("#"); } } } private void initPeople() { People people00 = new People("123d",R.mipmap.ic_launcher); peopleList.add(people00); People people0 = new People("阿多", R.mipmap.ic_launcher); peopleList.add(people0); People people1 = new People("阿杜", R.mipmap.ic_launcher); peopleList.add(people1); People people2 = new People("白云", R.mipmap.ic_launcher); peopleList.add(people2); People people3 = new People("白百何", R.mipmap.ic_launcher); peopleList.add(people3); People people4 = new People("白衣天使", R.mipmap.ic_launcher); peopleList.add(people4); People people5 = new People("陈超", R.mipmap.ic_launcher); peopleList.add(people5); People people6 = new People("杜小丽", R.mipmap.ic_launcher); peopleList.add(people6); People people7 = new People("宋娟", R.mipmap.ic_launcher); peopleList.add(people7); People people8 = new People("贾忆", R.mipmap.ic_launcher); peopleList.add(people8); People people9 = new People("张大炮", R.mipmap.ic_launcher); peopleList.add(people9); People people10 = new People("张伟", R.mipmap.ic_launcher); peopleList.add(people10); People people11 = new People("吕子乔", R.mipmap.ic_launcher); peopleList.add(people11); People people12 = new People("曾小贤", R.mipmap.ic_launcher); peopleList.add(people12); People people13 = new People("关谷", R.mipmap.ic_launcher); peopleList.add(people13); People people14 = new People("胡一菲", R.mipmap.ic_launcher); peopleList.add(people14); People people15 = new People("罗兰", R.mipmap.ic_launcher); peopleList.add(people15); People people16 = new People("美嘉", R.mipmap.ic_launcher); peopleList.add(people16); People people17 = new People("陆展博", R.mipmap.ic_launcher); peopleList.add(people17); /* Collections.sort(peopleList, new Comparator<People>() { @Override public int compare(People lhs, People rhs) { return lhs.getName().compareTo(rhs.getName()); } });*/ Collections.sort(peopleList); } } |
TAG处理我们放在Adapter
中处理,让其实现SectionIndexer
接口,并实现该接口的三个方法。
@Override public Object[] getSections() { positionOfSection = new SparseIntArray(); sectionOfPosition = new SparseIntArray(); int count = getCount(); list = new ArrayList<>(); list.add("搜"); positionOfSection.put(0, 0); sectionOfPosition.put(0, 0); for (int i = 1; i < count; i++) { String letter = getItem(i).getHeader(); int section = list.size() - 1; if (list.get(section) != null && !list.get(section).equals(letter)) { list.add(letter); section++; positionOfSection.put(section, i); } sectionOfPosition.put(i, section); } return list.toArray(new String[list.size()]); } @Override public int getPositionForSection(int sectionIndex) { return positionOfSection.get(sectionIndex); } @Override public int getSectionForPosition(int position) { return sectionOfPosition.get(position); } |
ok,那么这三个方法是干嘛的?还有SparseIntArray
是什么鸟玩意,老子怎么不知道这些!?
SectionIndexer的使用
private int sectionForPoint(float y) { int index = (int) (y / height); if (index < 0) { index = 0; } if (index > indexArr.length - 1) { index = indexArr.length - 1; } return index; } private void setHeaderTextAndScroll(MotionEvent event){ if (mListView == null){ return; } String headString= indexArr[sectionForPoint(event.getY())]; header.setText(headString); PeopleAdapter adapter = (PeopleAdapter) mListView.getAdapter(); String[] adapterSections = (String[]) adapter.getSections(); for (int i = adapterSections.length -1;i>-1;i--){ if (adapterSections[i].equals(headString)){ mListView.setSelection(adapter.getPositionForSection(i)); break; } } } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: if (header == null){ header = (TextView)((View)getParent()).findViewById(R.id.floating_header); } setHeaderTextAndScroll(event); header.setVisibility(View.VISIBLE); setBackgroundResource(R.drawable.sidebar_background_pressed); return true; case MotionEvent.ACTION_MOVE: setHeaderTextAndScroll(event); return true; case MotionEvent.ACTION_UP: header.setVisibility(View.INVISIBLE); setBackgroundColor(Color.TRANSPARENT); return true; case MotionEvent.ACTION_CANCEL: header.setVisibility(View.INVISIBLE); setBackgroundColor(Color.TRANSPARENT); return true; } return super.onTouchEvent(event); } |
源代码下载链接:源码
http://chenfuduo.me/2015/05/06/quick-index-listview/
标签:
原文地址:http://blog.csdn.net/chenfuduo_loveit/article/details/45576261