实现的原理就是解决两个问题:
1)数据主关键字按拼音间分组排序。
2)基于ExpandableListView控件实现内容展示。
例子代码:http://download.youkuaiyun.com/detail/topwangpeng/8104735
(一)数据主关键字按拼音间分组排序
首先把主关键字列表的首字按拼音排序,首字的拼音首字母相同的为一组,这里关键是得到主关键字字符串首字的拼音首字符。使用pinyin4j库可以解决此问题。
public String getFirstChar(String value) {
char firstChar = value.charAt(0); // 首字符
String first = null; // 首字母分类
String[] print = PinyinHelper.toHanyuPinyinStringArray(firstChar); // 是否是非汉字
if (print == null) { //非中文
// 将小写字母改成大写
if ((firstChar >= 97 && firstChar <= 122)) {
firstChar -= 32;
}
if (firstChar >= 65 && firstChar <= 90) {
first = String.valueOf((char) firstChar);
} else {
// 认为首字符为数字或者特殊字符
first = "#";
}
} else {
// 如果是中文,分类大写字母
first = String.valueOf((char)(print[0].charAt(0) -32));
}
if (first == null) {
first = "?";
}
return first;
}
汉字按拼音排序也是通过pinyin4j库实现的。
class LanguageComparator_CN implements Comparator<String> {
public int compare(String ostr1, String ostr2) {
for (int i = 0; i < ostr1.length() && i < ostr2.length(); i++) {
int codePoint1 = ostr1.charAt(i);
int codePoint2 = ostr2.charAt(i);
if (Character.isSupplementaryCodePoint(codePoint1) ||
Character.isSupplementaryCodePoint(codePoint2)) {
i++;
}
if (codePoint1 != codePoint2) {
if (Character.isSupplementaryCodePoint(codePoint1) ||
Character.isSupplementaryCodePoint(codePoint2)) {
return codePoint1 - codePoint2;
}
String pinyin1 = pinyin((char) codePoint1);
String pinyin2 = pinyin((char) codePoint2);
if (pinyin1 != null && pinyin2 != null) { // 两个字符都是汉字
if (!pinyin1.equals(pinyin2)) {
return pinyin1.compareTo(pinyin2);
}
} else {
return codePoint1 - codePoint2;
}
}
}
return ostr1.length() - ostr2.length();
}
// 获得汉字拼音的首字符
private String pinyin(char c) {
String[] pinyins = PinyinHelper.toHanyuPinyinStringArray(c);
if (pinyins == null) {
return null;
}
return pinyins[0];
}
}
使用示例:
List<String> names=new ArrayList<String>();
names.add("天龙八部");
names.add("笑傲江湖");
names.add("书剑恩仇录");
names.add("雪山飞狐");
names.add("神雕侠吕");
names.add("射雕英雄传");
names.add("八仙过海");
names.add("西游记");
names.add("红楼梦");
names.add("三国演义");
names.add("水浒传");
names.add("Java");
names.add("C++");
names.add("C#");
names.add("Object C");
names.add("Javascript");
Collections.sort(names, new LanguageComparator_CN());
(二)内容展示
1)使用ExpandableListView控件,关于此控件的使用baidu一下就知道了,其实很简单,重写BaseExpandableListAdapter抽象类中的方法后,调用ExpandableListView.setAdapter就可以展示其基本特性了。
2)设置ExpandableListView控件的groupIndicator为空。
<ExpandableListView
android:id="@+id/expand_listview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:groupIndicator="@null"
/>
3)默认展开所有分组。
mExpandableListView = (ExpandableListView)findViewById(R.id.expand_listview);
List<String> names=new ArrayList<String>();
names.add("天龙八部");
names.add("笑傲江湖");
names.add("书剑恩仇录");
names.add("雪山飞狐");
names.add("神雕侠吕");
names.add("射雕英雄传");
names.add("八仙过海");
names.add("西游记");
names.add("红楼梦");
names.add("三国演义");
names.add("水浒传");
names.add("Java");
names.add("C++");
names.add("C#");
names.add("Object C");
names.add("Javascript");
PinyinAdapter adapter = new PinyinAdapter(this,names);
mExpandableListView.setAdapter(adapter);
for (int i = 0, length = adapter.getGroupCount(); i < length; i++) {
mExpandableListView.expandGroup(i);
}
4)实现右则的字母导航示图。
a)实现一个自定义View。
b)在OnDraw中自绘所有字母。
c)重写dispatchTouchEvent事件,根据点击的位置定位哪个分类被选中。
public class AssortView extends Button {
public interface OnTouchAssortListener {
public void onTouchAssortListener(String s);
public void onTouchAssortUP();
}
// 分类
private static final String[] ASSORT_TEXT = { "?", "#", "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 = new Paint();
private int mSelectIndex = -1;
private OnTouchAssortListener mListener = null;
public AssortView(Context context) {
super(context);
}
public AssortView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AssortView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void setOnTouchAssortListener(OnTouchAssortListener listener) {
this.mListener = listener;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int nHeight = getHeight();
int hWidth = getWidth();
int nAssortCount = ASSORT_TEXT.length;
int nInterval = nHeight / nAssortCount;
for (int i = 0; i < nAssortCount; i++) {
mPaint.setAntiAlias(true); // 抗锯齿
mPaint.setTypeface(Typeface.DEFAULT_BOLD); // 默认粗体
mPaint.setColor(Color.WHITE); // 白色
if (i == mSelectIndex) {
// 被选择的字母改变颜色和粗体
mPaint.setColor(Color.parseColor("#3399ff"));
mPaint.setFakeBoldText(true);
mPaint.setTextSize(30);
}
float xPos = hWidth / 2 - mPaint.measureText(ASSORT_TEXT[i]) / 2; // 计算字母的X坐标
float yPos = nInterval * i + nInterval; // 计算字母的Y坐标
canvas.drawText(ASSORT_TEXT[i], xPos, yPos, mPaint);
mPaint.reset();
}
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
int nIndex = (int) (event.getY() / getHeight() * ASSORT_TEXT.length);
if (nIndex >= 0 && nIndex < ASSORT_TEXT.length) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
// 如果滑动改变
if (mSelectIndex != nIndex) {
mSelectIndex = nIndex;
if (mListener != null) {
mListener.onTouchAssortListener(ASSORT_TEXT[mSelectIndex]);
}
}
break;
case MotionEvent.ACTION_DOWN:
mSelectIndex = nIndex;
if (mListener != null) {
mListener.onTouchAssortListener(ASSORT_TEXT[mSelectIndex]);
}
break;
case MotionEvent.ACTION_UP:
if (mListener != null) {
mListener.onTouchAssortUP();
}
mSelectIndex = -1;
break;
}
} else {
mSelectIndex = -1;
if (mListener != null) {
mListener.onTouchAssortUP();
}
}
invalidate();
return true;
}
}