您的位置:首页 > 移动开发 > Android开发

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

2016-11-10 18:44 1376 查看

一、效果图



二、简介

我在做项目时候添加的功能,网上看了一些别人的做法,觉得一般般,然后就自己花了一下午写了一个感觉还可以的。

列表用的是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);
}
}


五、使用

窗口打开现在加载中的dialog

开始请求获取json

解析json为对应的list

在子线程中进行排序

更新到适配器

实现字母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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐