[Android开发] 在项目中快速实现 列表字母排序滑动索引 功能原理以及过程代码

来源:互联网 发布:人物识别软件 编辑:程序博客网 时间:2024/06/06 09:06

一、效果图

这里写图片描述

二、简介

我在做项目时候添加的功能,网上看了一些别人的做法,觉得一般般,然后就自己花了一下午写了一个感觉还可以的。
列表用的是listView,侧边字母栏是自定义了一个SideBar。
底部有完整的demo(包括json解析为对应的list bean)。

三、思路过程

1. 先确定服务端返回的json格式

2. 把服务器的数据解析为list bean

3. 根据list的bean里面的字符寸的第一个字母的拼音进行重新排序

4. 排序过程在bean添加首字母标识

5. 适配器进行数据填充到listView,根据bean里面的首字母标识进行显示隐藏字母

6. 封装SideBar字母侧边栏,滑动回调字母listView跳到指定的字母

四、详细过程

1. 知道接口数据格式

从后台开发者给的接口可以知道json的格式如下。

{    "desc":"查询成功",    "data":{        "diseaseList":[            {                "xmlName":"痴呆的评估",                "xmlId":"242",                "category":"symptom"            },            {                "xmlName":"非故意性体重减轻评估",                "xmlId":"548",                "category":"symptom"            }        ]    },    "action":null,    "code":"",    "type":"SUCCESS"}

2. 解析为对应的bean的list

我这里是利用上一篇文章的json解析类进行解析: http://blog.csdn.net/niubitianping/article/details/53117978

这里就解析成了List,DiseaseList里面是xmlName、xmlId、category,还有对应的get和set。

3. 重新排序

这是重点,首先用到一个库:pinyin4j来转换把中文转换为拼音。
(ps:还有jpinyin,chineseandpinyin这两个库也是可以转换的。jpinyin好像是pinyin4的优化版 具体我没用。chineseandpinyin我导入了跑起来报错JSONObject找不到,我把json包导入了之后也是一堆问题)。

(1) 导入pinyin4j的库

官网下载地址:http://sourceforge.net/project/showfiles.php?group_id=163377

好多年没更新了,最新是2.5,导入库这么简单就不说了。

(2) 编写比较类

利用java的Collections类进行排序,自己实现排序方法

//对list进行按照拼音排序Collections.sort(list, new PinYinComparator());

PinYinComparator.java比较类

/** * 作用:取第一个字的拼音进行比较排序 * * @author LITP * @date 2016/11/10 */public class PinYinComparator implements Comparator<DiseaseList> {    //已经存在的首字母列表    private SparseArray<Character> letters = new SparseArray<>();    @Override    public int compare(DiseaseList lhs, DiseaseList rhs) {        int c1 = PinYinUtils.getFirstPiniYin(lhs.getXmlName()).charAt(0);        int c2 = PinYinUtils.getFirstPiniYin(rhs.getXmlName()).charAt(0);        //判断是否已经存在了首字母了        if (letters.get(c1) == null) {            //判断是不是字母            if (Character.isLetter((char) c1)) {                letters.put(c1,(char) c1);                //重点,设置首字母标识                lhs.setLetter((char) c1 + "");            } else { //设置#标识                letters.put('#', (char) c1);                lhs.setLetter("#");            }        }        //c1 不为字母        if ((c1 < 65)) {            c1 += 90;   // 使其在后面        }        //c2 不为字母        if ((c2 < 65)) {            c2 += 90;   // 使其在后面        }        return c1 - c2;   //负数则第一个参数在前面,    }}

4. 编写适配器

列表的适配器,重点是 item的布局是包括的一行的字母的view,根据bean里面是否有字母而隐藏显示

BMJLetterListAdapter.java

/** * 作用: 字母排序列表的适配器 * * @author LITP * @date 2016/11/4 */public class BMJLetterListAdapter extends BaseAdapter {    private LayoutInflater mInflater;    private List<?> mDatas;    public BMJLetterListAdapter(Context context, List<?> datas){        mInflater = LayoutInflater.from(context);        mDatas = datas;    }    @Override    public int getCount() {        Log.e("tpnet","总数"+mDatas.size());        return mDatas.size();    }    @Override    public Object getItem(int arg0) {        return mDatas.get(arg0);    }    @Override    public long getItemId(int arg0) {        return arg0;    }    @Override    public View getView(int position, View convertView, ViewGroup arg2) {        MyViewHolder myViewHolder = null;        if(convertView == null){            myViewHolder = new MyViewHolder();            convertView = mInflater.inflate(R.layout.item_bmj_letter_list,arg2,false);            myViewHolder.letterText = (TextView) convertView.findViewById(R.id.bmj_tv_letter);            myViewHolder.contentText = (TextView) convertView.findViewById(R.id.bmj_tv_content);            convertView.setTag(myViewHolder);        }else{            myViewHolder = (MyViewHolder) convertView.getTag();        }        DiseaseList item = (DiseaseList) getItem(position);        if(item != null){            //如果有字母标识就显示 字母那一行            if(!item.getLetter().isEmpty()){                myViewHolder.letterText.setText(item.getLetter());                myViewHolder.letterText.setVisibility(View.VISIBLE);            }else{ //否则隐藏                myViewHolder.letterText.setVisibility(View.GONE);            }            myViewHolder.contentText.setText(item.getXmlName());        }        return convertView;    }    private class MyViewHolder{        private TextView letterText;        private TextView contentText;    }}

布局文件请看demo,代码太多就不贴了

5. 封装侧边字母栏

上面的排序和数据已经搞好了,接下来是侧边的字母索引。要实现的功能有点击其中的字母 listview跳到指定的位置,滑动时候也要跳到指定的位置。 这个很简单,100多行代码就可以了
SideBar.java

/** * 作用: 右边的字母View * * @author LITP * @date 2016/11/2 */public class SideBar extends View {    // 26个字母    public static String[] letters = {"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 choose = -1;  // 选中的字母的y坐标    //字母画笔    private Paint paint = new Paint();    private TextView mTextDialog;       //显示当前字母的文本框    private int singleHeight;   //一个字母的空间    Rect rect = new Rect();     //存放文字的高度    public SideBar(Context context, AttributeSet attrs) {        super(context, attrs);    }    @Override    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {        super.onLayout(changed, left, top, right, bottom);        paint.setAntiAlias(true); //设置抗锯齿        paint.setTextSize(DensityUtil.sp2px(12f)); //设置字母字体大小为12sp        //获取一个字母实际的宽高到rect        paint.getTextBounds("A", 0, 1, rect);        //获取一个字母的空间        singleHeight = (getHeight() - (getPaddingTop() + getPaddingBottom())) / 27;    }    /**     * 为SideBar设置显示字母的TextView     *     * @param mTextDialog 在activity传递过来的textView     */    public void setTextView(TextView mTextDialog) {        this.mTextDialog = mTextDialog;    }    /**     * 绘制     */    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        //循环绘制字母        for (int i = 0; i < letters.length; i++) {            //paint.setTypeface(Typeface.DEFAULT_BOLD); //设置默认字体加粗            // 选中的状态            if (i == choose) {                paint.setColor(getResources().getColor(R.color.light_color_blue)); //选中的字母改变颜色                paint.setFakeBoldText(true); //设置字体为粗体            } else {                paint.setColor(getResources().getColor(R.color.darkgray)); //设置字体颜色                paint.setFakeBoldText(false); //设置字体为正常            }            // x坐标等于中间-字符宽度的一半.            float xPos = getWidth() / 2 - paint.measureText(letters[i]) / 2;            //Y轴坐标            float yPos = getPaddingTop() + singleHeight * i + rect.height();            canvas.drawText(letters[i], xPos, yPos, paint); //绘制字母        }    }    /**     * 分发触摸事件     *     * @param event     * @return     */    @Override    public boolean dispatchTouchEvent(MotionEvent event) {        final int action = event.getAction();        final float y = event.getY();// 点击y坐标        final int oldChoose = choose;  //上一个选中的字母        // 点击y坐标所占总高度的比例  *   数组的长度就等于点击了 数组中的位置.        final int c = (int) (y  / (getHeight() - getPadddingTop() - getPaddingBottom()) * letters.length);        switch (action) {            case MotionEvent.ACTION_UP:                //抬起来的时候设置背景为透明                //setBackgroundDrawable(new ColorDrawable(0x00000000));                choose = -1;//                invalidate();                if (mTextDialog != null) {                    mTextDialog.setVisibility(View.INVISIBLE);                }                break;            default:                //按下,滑动的时候设置背景为灰色                //setBackgroundDrawable(new ColorDrawable(0x44000000));                //setBackgroundResource(R.drawable.sidebar_background);                if (oldChoose != c) { //判断选中字母是否发生改变                    if (c >= 0 && c < letters.length) {                        if (listener != null) {                            listener.onTouchLetterChanged(letters[c]);                        }                        if (mTextDialog != null) {                            mTextDialog.setText(letters[c]);                            mTextDialog.setVisibility(View.VISIBLE);                        }                        //设置选中字母在数组的位置                        choose = c;                        invalidate();                    }                }                break;        }        return true;    }    // 触摸回调接口    private OnTouchLetterChangedListener listener;    public void setOnTouchLetterChangedListener(            OnTouchLetterChangedListener onTouchLetterChangedListener) {        this.listener = onTouchLetterChangedListener;    }    public interface OnTouchLetterChangedListener {        /**         * 触摸字母回调         *         * @param s 触摸的字符         */        void onTouchLetterChanged(String s);    }}

五、使用

  1. 窗口打开现在加载中的dialog
  2. 开始请求获取json
  3. 解析json为对应的list
  4. 在子线程中进行排序
  5. 更新到适配器
  6. 实现字母view滑动接口,字母view滑动点击 listView跳到指定位置
    /**     * 点击或者滑动到当前的字母  listView跳到指定位置     *     * @param s 触摸的字符     */    @Override    public void onTouchLetterChanged(String s) {        for (DiseaseList item : list) {            if (item.getLetter().equals(s)) {                bmjLvLetter.setSelection(list.indexOf(item));                return;            }        }    }

完整demo下载: http://download.csdn.net/detail/niubitianping/9679329

2 0
原创粉丝点击