Android实现类似微信联系人中的分组列表

本文介绍了一种基于拼音的排序方法及如何使用ExpandableListView控件实现分组展示的技术方案。具体包括如何获取字符串首字的拼音首字母进行排序,并结合实例展示了如何设置ExpandableListView来展示排序后的数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

实现的原理就是解决两个问题:

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;  
    } 
}  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值