Android分类列表之ListView-ViewType实现

        • 一、分析实现
        • 二、编码
        • 三、测试效果

前两天无意间看到朋友的一个功能要实现分类列表,也就互相简单的聊了一下,在此感觉还是挺有意思又加上有段时间没写这个了,就想着用自己的方法实现一下,下面是UI效果图

一、分析实现

其实可以直接使用ExpandableListView(从出来工作写代码开始算起我用到ExpandableListView的次数不超过一个巴掌,以下就全当我不会使用这个控件吧!),不会使用这个控件而且我又只会ListView咋办呢,别急,先观察一下UI效果和数据。

{"msg":"可用优惠券列表获取成功","code":"100","data":[{"isUse":"1","useConditions":50.00,"couponUserId":2237,"couponName":"满50减15","validityDate":"2019-06-26至2019-07-31","couponUseExplain":"优选商城通用,团购/抢购不可用","denominationShow":"15","useConditionsDesc":"满50.00可用","couponId":362,"useConditionsShow":"50","denomination":15.00},{"isUse":"1","useConditions":10.00,"couponUserId":2236,"couponName":"满10减5","validityDate":"2019-06-26至2019-07-31","couponUseExplain":"优选商城通用,团购/抢购不可用","denominationShow":"5","useConditionsDesc":"满10.00可用","couponId":361,"useConditionsShow":"10","denomination":5.00},{"isUse":"1","useConditions":5.00,"couponUserId":2235,"couponName":"满5减2元","validityDate":"2019-06-26至2019-07-31","couponUseExplain":"优选商城通用,团购/抢购不可用","denominationShow":"2","useConditionsDesc":"满5.00可用","couponId":360,"useConditionsShow":"5","denomination":2.00},{"isUse":"2","useConditions":200.00,"couponUserId":2238,"couponName":"满200减70","validityDate":"2019-06-26至2019-07-31","couponUseExplain":"优选商城通用,团购/抢购不可用","denominationShow":"70","useConditionsDesc":"满200.00可用","couponId":363,"useConditionsShow":"200","denomination":70.00}],"success":true,"now":11111111111}

  1. 数据分类,从数据中可以看出,主要分为两类数据:
    1)isUse=1是当前可用
    2)isUse=2是不满足条件
  2. 对应数据分类,使用ViewType来区分为两种item视图进行绘制:
    1)优惠券的视图;
    2)分类title的视图;
  3. 视图绘制,大家都知道使用ViewType都是用来显示参差不齐的数据显示(也就是无序),而我们是要分类有序的显示,所以我们对数据根据isUse排序分类显示,但是在每个分类的前都是title类,所以只要我们的分类Title排序后正好在每个对应类型的前面就行了;至此麻烦来了,在数据里是没有关于title的数据,所以我们还要添加对应分类Title假数据在对其进行排序,由于两类数据都是根据isUse来分类的且值分别为1、2,我们可以创建两个对应的假数据将其isUser设置为0、1.5然后在用Float.compare()实现来对应进行排序,在对其进行适配绘制就完成了。

二、编码

上面对其进行里简单的分析,下面开始进行愉快的编码吧

  1. 解析数据
    分析完数据我们就开始创建对应的实体类:
    1)响应基类BaseResponse让其实现序列化接口Serializable,赋予范型T成为范型类,T可以对应我们任何类型的响应数据,可以是ListObject

    public class BaseResponse implements Serializable {    /**     * msg : 可用优惠券列表获取成功     * code : 100     * data : items     * success : true     * now : 1561625083199     */    private String msg;    private String code;    private boolean success;    private long now;    private T data;    public String getMsg() {        return msg;    }    public void setMsg(String msg) {        this.msg = msg;    }    public String getCode() {        return code;    }    public void setCode(String code) {        this.code = code;    }    public boolean isSuccess() {        return success;    }    public void setSuccess(boolean success) {        this.success = success;    }    public long getNow() {        return now;    }    public void setNow(long now) {        this.now = now;    }    public T getData() {        return data;    }    public void setData(T data) {        this.data = data;    }}

    2)对此次数据类型模型应该是BaseRespons>,所以我们接下来创建我们Item类-CouponBean且实现序列化接口Serializable,最终需要解析的数据模型为:BaseRespons>

    public class CouponBean implements Serializable {    /**     * isUse : 1     * useConditions : 50.0     * couponUserId : 2237     * couponName : 满50减15     * validityDate : 2019-06-26至2019-07-31     * couponUseExplain : 优选商城通用,团购/抢购不可用     * denominationShow : 15     * useConditionsDesc : 满50.00可用     * couponId : 362     * useConditionsShow : 50     * denomination : 15.0     */    private String isUse;    private double useConditions;    private int couponUserId;    private String couponName;    private String validityDate;    private String couponUseExplain;    private String denominationShow;    private String useConditionsDesc;    private int couponId;    private String useConditionsShow;    private double denomination;    public String getIsUse() {        return isUse;    }    public void setIsUse(String isUse) {        this.isUse = isUse;    }    public double getUseConditions() {        return useConditions;    }    public void setUseConditions(double useConditions) {        this.useConditions = useConditions;    }    public int getCouponUserId() {        return couponUserId;    }    public void setCouponUserId(int couponUserId) {        this.couponUserId = couponUserId;    }    public String getCouponName() {        return couponName;    }    public void setCouponName(String couponName) {        this.couponName = couponName;    }    public String getValidityDate() {        return validityDate;    }    public void setValidityDate(String validityDate) {        this.validityDate = validityDate;    }    public String getCouponUseExplain() {        return couponUseExplain;    }    public void setCouponUseExplain(String couponUseExplain) {        this.couponUseExplain = couponUseExplain;    }    public String getDenominationShow() {        return denominationShow;    }    public void setDenominationShow(String denominationShow) {        this.denominationShow = denominationShow;    }    public String getUseConditionsDesc() {        return useConditionsDesc;    }    public void setUseConditionsDesc(String useConditionsDesc) {        this.useConditionsDesc = useConditionsDesc;    }    public int getCouponId() {        return couponId;    }    public void setCouponId(int couponId) {        this.couponId = couponId;    }    public String getUseConditionsShow() {        return useConditionsShow;    }    public void setUseConditionsShow(String useConditionsShow) {        this.useConditionsShow = useConditionsShow;    }    public double getDenomination() {        return denomination;    }    public void setDenomination(double denomination) {        this.denomination = denomination;    }}
  2. 处理数据,之前分析我们不仅要添加对应的类型假数据,还需要根据isUse对数据进行类别的排序,这样我们才能保证ListView绘制出来是有效有序的分类列表。
    1)利用gson解析json数据,首先获取对应类型type:
    Type type = new TypeToken>>() { }.getType();
    再者根据gson提供的api:public T fromJson(String json, Type typeOfT)对其进行解析:BaseResponse> baseResponse = new Gson().fromJson(json_data, type),这样就得到我们要的数据,然后是添加类别假数据在进行排序,在上面我们已经分析了如何进行排序,就是创建两个对应假数据CouponBean分别将其isUse设置为0、1.5,利用它的couponName属性来存储我们的分类title:当前可用、不满足条件,在用利用Collections.sort(Float.compare())对其进行排序为Collections.sort(data, (o1, o2) -> Float.valueOf(o1.getIsUse()).compareTo(Float.valueOf(o2.getIsUse()))),在此为了更优雅,我们模拟远程服务器(不模拟延时)创建本地服务类:LocalDataServer如下:

    public final class LocalDataServer {    static final String json_data = "{\"msg\":\"可用优惠券列表获取成功\",\"code\":\"100\",\"data\":[" +            "{\"isUse\":\"1\",\"useConditions\":50.00,\"couponUserId\":2237,\"couponName\":\"满50减15\",\"validityDate\":\"2019-06-26至2019-07-31\",\"couponUseExplain\":\"优选商城通用,团购/抢购不可用\",\"denominationShow\":\"15\",\"useConditionsDesc\":\"满50.00可用\",\"couponId\":362,\"useConditionsShow\":\"50\",\"denomination\":15.00}," +            "{\"isUse\":\"1\",\"useConditions\":10.00,\"couponUserId\":2236,\"couponName\":\"满10减5\",\"validityDate\":\"2019-06-26至2019-07-31\",\"couponUseExplain\":\"优选商城通用,团购/抢购不可用\",\"denominationShow\":\"5\",\"useConditionsDesc\":\"满10.00可用\",\"couponId\":361,\"useConditionsShow\":\"10\",\"denomination\":5.00}," +            "{\"isUse\":\"1\",\"useConditions\":5.00,\"couponUserId\":2235,\"couponName\":\"满5减2元\",\"validityDate\":\"2019-06-26至2019-07-31\",\"couponUseExplain\":\"优选商城通用,团购/抢购不可用\",\"denominationShow\":\"2\",\"useConditionsDesc\":\"满5.00可用\",\"couponId\":360,\"useConditionsShow\":\"5\",\"denomination\":2.00}," +            "{\"isUse\":\"2\",\"useConditions\":200.00,\"couponUserId\":2238,\"couponName\":\"满200减70\",\"validityDate\":\"2019-06-26至2019-07-31\",\"couponUseExplain\":\"优选商城通用,团购/抢购不可用\",\"denominationShow\":\"70\",\"useConditionsDesc\":\"满200.00可用\",\"couponId\":363,\"useConditionsShow\":\"200\",\"denomination\":70.00}]," +            "\"success\":true,\"now\":1561625083199}";    /**     * 获取根据ViewType分类显示的数据     *     * @return     */    public static List requestDateFromServerByViewType() {        BaseResponse> baseResponse = new Gson().fromJson(json_data, new TypeToken>>() {        }.getType());        List data = baseResponse.getData();        CouponBean couponBean = new CouponBean();        couponBean.setIsUse("0");        couponBean.setCouponName("当前可用");        data.add(couponBean);        couponBean = new CouponBean();        couponBean.setIsUse("1.5");        couponBean.setCouponName("当前不满足条件");        data.add(couponBean);        Collections.sort(data, (o1, o2) -> Float.valueOf(o1.getIsUse()).compareTo(Float.valueOf(o2.getIsUse())));        return data;    }
  3. 布局文件(没啥好说的直接贴吧)
    1)activity布局文件:

    <?xml version="1.0" encoding="utf-8"?>    

    2)title分类item布局文件(因为和我讨论哥们叫云飞所以加了个云飞?):

    <?xml version="1.0" encoding="utf-8"?>

    3)coupon分类item布局文件:

    <?xml version="1.0" encoding="utf-8"?>                                                                                                                                                                                                            

    此分类在AndroidStudio显示效果为(因为是白色为了显示CardView,加了个绿背景色,并没有照UI图全部搭建效果,我们主要目的还是实现分类显示):

  4. 编码适配器ListViewAdapter
    1)创建ListViewAdapter继承BaseAdapter,添加List mCouponBeanListContext mContext属性,创建这两个参数的构造方法,先重写public int getCount()public Object getItem(int position)public long getItemId(int position)方法为:

    public class ListViewAdapter extends BaseAdapter {    private List mCouponBeanList;    private Context mContext;    public ListViewAdapter(List couponBeanList, Context context) {        mCouponBeanList = couponBeanList;        mContext = context;    }    @Override    public int getCount() {        if (mCouponBeanList != null) {            return mCouponBeanList.size();        }        return 0;    }    @Override    public Object getItem(int position) {        return mCouponBeanList.get(position);    }    @Override    public long getItemId(int position) {        return position;    }    @Override    public View getView(int position, View convertView, ViewGroup parent) {        return null;    }

    2)因为我们是根据ViewType来进行分类显示的,所以我们重写方法public int getViewTypeCount()public int getItemViewType(int position),由于我们只有两个类型所以ViewTypeCount()要返回2注意:确定返回类型数量n后,getItemViewType返回的值必须在区间[0,n-1]之间,也就是说getItemViewType只能返回0或者1,我将isUse=0或isUse=1.5的分为第一类其值返回0getItemViewType=0isUse=1或isUse=2为第二类其值返回1getItemViewType=1在这里插入代码片代码如下:

    @Override    public int getViewTypeCount() {        return 2;    }    @Override    public int getItemViewType(int position) {        String isUse = mCouponBeanList.get(position).getIsUse();        return ("0".equals(isUse) || "1.5".equals(isUse)) ? 0 : 1;    }

    3)创建视图View,根据ViewType我们有两个分类,所以需要创建填充两个视图,ViewType=0的对应title分类标题视图ViewType=1的对应coupon优惠券视图,出于对内存等性能考虑,我们需要进行View的复用,所以我们还需要创建两个ViewHolder,其分别对应两个不同ViewType:创建分类标题ViewHolder:TitleViewHolder对应标题布局文件ViewType=0,解析数据映射到对应的控件上代码为:

    static class TitleViewHolder {        private TextView title;        TitleViewHolder(View itemView) {            title = itemView.findViewById(R.id.yunfei_title);        }        void bindData(CouponBean couponBean) {            title.setText(couponBean.getCouponName());        }    }

    创建分类标题CouponViewHolder:CouponViewHolder对应优惠券布局文件ViewType=1,解析数据映射到对应的控件上代码为:

    static class CouponViewHolder {        private TextView couponDescription, couponMoney, indate, useCondition;        CouponViewHolder(View itemView) {            couponDescription = itemView.findViewById(R.id.couponDescription);            couponMoney = itemView.findViewById(R.id.couponMoney);            useCondition = itemView.findViewById(R.id.useCondition);            indate = itemView.findViewById(R.id.indate);        }        void bindData(CouponBean couponBean) {            couponDescription.setText(couponBean.getCouponUseExplain());            couponMoney.setText(couponBean.getDenominationShow());            useCondition.setText(couponBean.getUseConditionsDesc());            indate.setText(couponBean.getValidityDate());        }    }

    最后重写我们的public View getView(int position, View convertView, ViewGroup parent)方法获视图:

     @Override    public View getView(int position, View convertView, ViewGroup parent) {        return getItemViewType(position) == 0 ? getTitleView(position, convertView, parent) : getCouponView(position, convertView, parent);    }

三、测试效果

  1. 在Activity中给ListView设置适配器:
    List couponBeans = LocalDataServer.requestDateFromServerByViewType();ListViewAdapter listViewAdapter = new ListViewAdapter(couponBeans, this);listView.setAdapter(listViewAdapter);
  2. 运行效果为:

至此我们使用ListView-ViewType来实现分类显示就完成了,下二篇,我们将继续实现此功能,不过使用分别是RecyclerView-ViewTypeRecyclerView-ItemDecoration来实现。如果本篇文章有什么技术上问题还请留言讨论共同进步谢谢!
`

更多相关文章

  1. “罗永浩抖音首秀”销售数据的可视化大屏是怎么做出来的呢?
  2. Nginx系列教程(三)| 一文带你读懂Nginx的负载均衡
  3. 不吹不黑!GitHub 上帮助人们学习编码的 12 个资源,错过血亏...
  4. Android——ECG心电图的绘制实现(二)
  5. Android(安卓)Handler的详细介绍
  6. unity调用android语音识别
  7. android 加密 SQLCipher和Conceal
  8. 第一篇博客——从《第一行代码》学习笔记开始
  9. Android中的搜索(search)概述

随机推荐

  1. Android开发优秀博文收录
  2. Android中设置控件可见与不可见详解
  3. Android图文详解属性动画
  4. android蓝牙BLE(三) —— 广播
  5. Android快速开发架构PlanA(四),网络请求篇,划
  6. Android——OOM以及内存优化
  7. Android和Linux kernel发展史
  8. Android进程与线程基本知识
  9. RadioButton 选择框的位置
  10. Android(安卓)Binder入门指南之defaultSe