手把手教你如何搭建一个自己的安卓快速开发框架之带你做自己的APP(四)

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/u012534831/article/details/70670170

点击查看上一篇文章:手把手教你如何搭建一个自己的安卓快速开发框架之带你做自己的APP(三)

继上一篇我们的开发,包含

  • BaseFragment
  • 精美的仿微信底部菜单栏
  • 网络请求失败时如何显示空View

那么,这一篇,我准备完成:

  • 精美的订单追踪页面
  • fragment+viewpage实现完整订单查看模块
  • baseAdapter+下拉刷新
  • litepal数据库操作

其实到上一篇为止,我们的快速开发框架已经基本完成了。所以呢,接下来我准备在此基础上开发我们的一款APP—–玩快递

上面所说的准备完成的4部分其实我已经做完了,代码在git上,所以这儿我只是带大家看一下,就不细说。

1、开门见山,看下什么是精美的订单追踪页面?

这里写图片描述

如上:我们使用 recycleview 来实现。

首先是一个自定义View,这个自定义 View 包含三部分,

  • beginline
  • mark
  • endline

这里写图片描述

代码在这里:
https://github.com/qht1003077897/AppFrame/blob/master/app/src/main/java/com/qht/blog2/View/TimeLineMarkerView.java

使用了自定义属性,以便在 adapter 中设置这三个位置的 drawable,比如图中的红点

  • 如果已经签收,setbeginline(null); setmark(color.red);
  • 如果在途中,则不用设置,使用 xml 中定义的即可。
  • 如果是第一条信息,即为开始派件,则 setendline(null);

然后 View 的左边是订单时间,右边是具体信息,下面加了一条 height=1px的 view 作为分割线,并且设置 recycleview 的分割线为 null。

接下来看下我们 recycleview 所使用的 Adapter,考虑到 recycleview 的通用性,以及我们的订单页面使用的也是 recycleview,所以我们需要一个 BaseAdapter。

在 github上找了一个,算是比较强大的,并且作者一直在维护:RecycleViewBaseAdapter

看下我们是怎么用的,

/**
 * Created by QHT on 2017-04-12.
 * 订单详情页面
 */
public class OrderDetail_RV_Adapter extends BaseQuickAdapter<OrderInfoDetailBean,BaseViewHolder> {

    private Context context;
    private TimeLineMarkerView timelineView;
    private String state;


    public OrderDetail_RV_Adapter(List<OrderInfoDetailBean> list,String state,Context context) {
        super(R.layout.activity_orderdetail_rv_item, list);
        this.context=context;
        this.state=state;
    }

    @Override
    protected void convert(BaseViewHolder helper, OrderInfoDetailBean item) {
        if(timelineView==null ) {
            timelineView = (TimeLineMarkerView) (helper.getView(R.id.tv_rv_activity_orderdetail_timelineview));
        }

        if(helper.getItemViewType()==OrderSite.BEGIN){
            timelineView.setBeginLine(null);
            helper.setTextColor(R.id.tv_rv_activity_orderdetail_time,context.getResources().getColor(R.color.red));
            helper.setTextColor(R.id.tv_rv_activity_orderdetail_content,context.getResources().getColor(R.color.red));
            timelineView.setMarkerDrawable(context.getResources().getDrawable(R.drawable.timeline_bg_red));
        } else if(helper.getItemViewType()==OrderSite.END){
            timelineView.setEndLine(null);
        }
            helper.setText(R.id.tv_rv_activity_orderdetail_content, item.getContext());
            //分两行显示
            helper.setText(R.id.tv_rv_activity_orderdetail_time,
                item.getTime().toString().substring(0,10)+"\n"+
                item.getTime().toString().substring(10));
    }

            @Override
            public int getItemViewType(int position) {
                if(position==0 && state.equals("3")){
                    return OrderSite.BEGIN;
                }else if(position==getItemCount()-1){
                    return OrderSite.END;
                }
                return  super.getItemViewType(position);
            }

}

我们在 getItemViewType 类里面判断 item 的类型,返回不同的 int 值:

  • OrderSite.BEGIN 代表订单已经签收。
  • OrderSite.END 代表订单开始派发。

然后在convert 方法中对 viewtype 进行判断,若为签收状态,则不显示 beginline,且 mark 为红色标示;若为派单状态,则 endline 不显示。


2、接下来我们需要花很多时间看这个地方–订单列表 ↓

这里写图片描述

看图,在这个页面中,包含了以下几个要点:

  • recycleview 的下拉刷新
  • recycleview 的右移动画
  • Activity 和 Fragment 积极通信
  • 单选、多选、全选删除动作
  • litepal 增删改查

你有没有注意到,在上个页面,我们的右下角有个浮动按钮,点击是这样的效果:

这里写图片描述

噢,是将这个订单标记为已签收或者未签收状态,所以,我们还用到了数据库。

这里写图片描述

头大,但是也得看下去!

首先,我们有这样一个model:

public class OrderInfoLitePal extends DataSupport {


    int     id;
    String  nu;
    String  com;
    String  state;
    String  time;
    boolean isselect;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    ............................

isselect 字段的目的是为了解决 checkbox 状态错乱的问题。

extends DataSupport 是 litepal 所需,id 是每条数据的 Id,后面会方便删除。

1. 先来看下拉刷新:

下拉刷新我们用到了这个库 pullrefreshlayout

用法如下:

swipeRefreshLayoutOrderall.setOnRefreshListener(new PullRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                swipeRefreshLayoutOrderall.post(new Runnable() {
                    @Override
                    public void run() {
                        QueryData();
                        notifydata();
                        swipeRefreshLayoutOrderall.setRefreshing(false);
                    }
                });
            }
        });

2. 衔接上,下面是数据库查询操作 :

使用 findAll 方法查一遍数据库,更新 list,再刷新视图即可。

/**
     * 避免调用notify失败
     */
    public void QueryData() {
      list.clear();
      List<OrderInfoLitePal> lists=new ArrayList<OrderInfoLitePal>();
      lists= DataSupport.findAll(OrderInfoLitePal.class);
      list.addAll(lists);
    }

为了避免调用 notifyDataSetChanged 失败,采用上面的办法。

 lists= DataSupport.findAll(OrderInfoLitePal.class);

这句代码即为查询数据库中 表名为 OrderInfoLitePal 的所有数据。

因为是全部订单,所以使用 findAll 。
如果是已签收订单(state为3代表已签收,其余状态各有意思): 则为:

lists=DataSupport.where("state=?","3").find(OrderInfoLitePal.class);

如果是未签收(state不等于3则为未签收),则为:

lists=DataSupport.where("state!=?","3").find(OrderInfoLitePal.class);

3个页面非业务功能一致,所有这儿只说所有订单页面。

3. 使用 EventBus 进行通信:

因为我们的结构是下面这样的:

这里写图片描述

toolbar 位于 MainActivity 上,如果点击 toolbar ,需要 AllOrderFragment做出动作,很明显我们需要使用 EventBus,并且还需要定制我们的 Event。

如果在上图中加上 EventBus ,则变成这样:

这里写图片描述

在 AllOrder 中我们接受一个 OrderEvent,如下:


public class OrderEvent extends Event {
    public int position;
    public String from;
    public  boolean needclose;
    public  boolean needselect;

    public OrderEvent(boolean needclose,boolean needselect, String from, int position, Object source) {
        super(source);
        this.needclose=needclose;
        this.needselect=needselect;
        this.from=from;
        this.position=position;
    }

position 表示是哪个 fragment 。
from 代表这条消息来自哪儿。
needclose 代表 Recycleview 的 Item 右移动画是否需要关闭。
needselet 代表 checkbox 是否需要被选择。

在 OnEvent 方法中 总共接受4种类型的消息

  • 第一种消息来自 MainActivity,代表点击了 toolbar 上面的 编辑/取消 按钮。

  • 第二种消息来自 FragmentSecond,表示当切换 fragment 时,关闭上个 fragment 的右移动画 ,并且置select 字段 false。

  • 第三种消息来自 MainActivity,表示点击了 全选/取消全选 按钮,并且置 select 字段 true/false。

  • 第四种消息来自 MainActivity,表示因为底部 fragment 切换需要关闭 item 的右移动画,并且置 select 字段false;

比如说,我们点击了全选按钮:

case R.id.toolbar_sub2title:
         if ("全选".equals(getSub2Title().getText().toString())) {
                getSub2Title().setText("取消全选");
               // To:FragmentOrder_***.onEvent()
               // false:不需要关闭动画
               // true: 需要选择
               // MainActivity_Allselect: 发送自 MainActivity
               // 参数-1无意义
               EventBusUtil.postSync(new       OrderEvent(false,true,"MainActivity_Allselect", -1, this));
      } 
    else if ("取消全选".equals(getSub2Title().getText().toString())) {
               getSub2Title().setText("全选");
               // To:FragmentOrder_Signed.onEvent()
               EventBusUtil.postSync(new OrderEvent(false,false, "MainActivity_Allselect", -1, this));
                }
                break;

当然,我们在 viewpage 切换的时候需要关闭上个 fragment 的右移动画和checkbox 的被选效果,则这样就可以:

        @Override
        public void onPageSelected(int position) {

            lastViewPageIndex=viewPagePosition;
            viewPagePosition=position;
            // To:FragmentOrder_Signed.onEvent()  切换,则恢复动画
            EventBusUtil.postSync(new OrderEvent(true,false,"FragmentSecond",lastViewPageIndex,this));
            // To:MainActivity.onEvent() 切换,则还原编辑字样
            EventBusUtil.postSync(new OrderEvent(true,false,"FragmentSecond",-1,this));
            }

position 发挥作用,表示上个 fragment 的位置,以明确到底是哪个 fragment接收。

4. 最后看一下单选、多选、全选,以及删除是怎么做的:

  • 单选
  list.get(response.position).setIsselect(response.checked);

设置 isselect 字段为 true 即可;

  • 多选、全选同理。

  • 删除

最后删除的时候,我们需要遍历 list,找到 isselect字段为 true 的数据,从list 中移除,且调用 notifyItemRemoved 方法更新列表视图,最后从数据库中根据我们 model 中的 id 字段删除这条数据即可。

@OnClick(R.id.btn_orderall_delete)
    public void onClick() {
        for (int i = 0; i < list.size(); i++) {
            if (list.get(i).isselect()) {
                int id = list.get(i).getId();
                list.remove(i);
                madapter.notifyItemRemoved(i);
                DataSupport.delete(OrderInfoLitePal.class, id);
            }
        }
    }

这篇就到这儿了,代码在 github 上。


下一篇,我们来完成个人中心模块,也许包括:

  • 侧滑抽屉布局
  • 第三方登录
  • 第三方分享

我的QQ: 1003077897
我的csdn:http://blog.csdn.net/u012534831
我的github:https://github.com/qht1003077897/AppFrame
我的个人博客:https://qht1003077897.github.io

欢迎交流。

猜你喜欢

转载自blog.csdn.net/u012534831/article/details/70670170