仿电商App:笔记(十一):购物车,订单,支付功能开发(包含支付宝支付)(一)

购物车,订单,支付功能开发(包含支付宝支付和微信支付)(一)

1、购物车UI编写

1.1 购物车根布局

1.2 购物车根页面效果图

1.3 购物车中每条数据效果图

2、购物车数据结构分析、解析与转化

2.1 购物车每个item的数据解析类

2.2 item的数据与视图绑定

2.3 购物车根布局

2.4 效果图

3、购物车事件逻辑梳理与实现-1

3.1 处理购物车中点击事件

3.3 根布局处理全选点击事件

3.4 效果图

4、删除、清空键的事件处理

4.1 数据转换类中,更新删除后的item位置

4.2 效果图

5、购物车价格计算逻辑梳理,排坑与实现

5.1 当购物车为空时,占位view

5.2 左右加减,使得总数值改变

1、购物车UI编写

1.1 购物车根布局

位于latte-ec模块main->cart包下的ShopCartDelegate。

主要作用:购物车页面的根fragment。

public class ShopCartDelegate extends BottomItemDelegate {
    @Override
    public Object setLayout() {
        return R.layout.delegate_shop_cart;
    }
    @Override
    public void onBindView(@Nullable Bundle savedInstanceState, View rootView) {
    }
}

1.2 购物车根页面效果图

仿电商App:笔记(十一):购物车,订单,支付功能开发(包含支付宝支付)(一)_第1张图片

1.3 购物车中每条数据效果图

仿电商App:笔记(十一):购物车,订单,支付功能开发(包含支付宝支付)(一)_第2张图片

2、购物车数据结构分析、解析与转化

2.1 购物车每个item的数据解析类

位于latte-ec模块main->cart包下的ShopCartDataConverter。

主要作用:购物车页面中每个item的解析类。

public class ShopCartDataConverter extends DataConverter {

    @Override
    public ArrayList convert() {
        ArrayList dataList = new ArrayList<>();
        JSONArray dataArray = JSON.parseObject(getJsonData()).getJSONArray("data");

        final int size = dataArray.size();
        for (int i=0;i

2.2 item的数据与视图绑定

位于latte-ec模块main->cart包下的ShopCartAdapter。

主要作用:购物车页面中每个item的转换类,购物车的数据适配器,将json数据与视图绑定。

public class ShopCartAdapter extends MultipleRecyclerAdapter {

    private static final RequestOptions OPTIONS = new RequestOptions()//图片加载库
            .diskCacheStrategy(DiskCacheStrategy.ALL)
            .centerCrop()
            .dontAnimate();

    protected ShopCartAdapter(List data) {
        super(data);
        //添加购物车item布局
        addItemType(ShopCartItemType.SHOP_CART_ITEM, R.layout.item_shop_cart);
    }

    @Override
    protected void convert(MultipleViewHolder holder, MultipleItemEntity entity) {
        super.convert(holder, entity);
        switch (holder.getItemViewType()) {
            case ShopCartItemType.SHOP_CART_ITEM:
                //先取出所有值
                final int id = entity.getFiled(MultipleFields.ID);
                final String thumb = entity.getFiled(MultipleFields.IMAGE_URL);
                final String title = entity.getFiled(ShopCartItemFields.TITLE);
                final String desc = entity.getFiled(ShopCartItemFields.DESC);
                final int count = entity.getFiled(ShopCartItemFields.COUNT);
                final double price = entity.getFiled(ShopCartItemFields.PRICE);
                //取出所有控件
                final AppCompatImageView imageThumb = holder.getView(R.id.image_item_shop_cart);
                final AppCompatTextView tvTitle = holder.getView(R.id.tv_item_shop_cart_title);
                final AppCompatTextView tvDesc = holder.getView(R.id.tv_item_shop_cart_desc);
                final AppCompatTextView tvPrice = holder.getView(R.id.tv_item_shop_cart_price);
                final IconTextView iconMinus = holder.getView(R.id.icon_item_minus);
                final IconTextView iconPlus = holder.getView(R.id.icon_item_plus);
                final AppCompatTextView tvCount = holder.getView(R.id.tv_item_shop_cart_count);
                //赋值(json数据与视图绑定)
                tvTitle.setText(title);
                tvDesc.setText(desc);
                tvPrice.setText(String.valueOf(price));
                tvCount.setText(String.valueOf(count));
                Glide.with(mContext)
                        .load(thumb)
                        .into(imageThumb);
                break;
            default:
                break;
        }
    }
}

2.3 购物车根布局

位于latte-ec模块main->cart包下的ShopCartDelegate。

主要作用:购物车页面的根fragment。

public class ShopCartDelegate extends BottomItemDelegate implements ISuccess {

    @BindView(R2.id.rv_shop_cart)//rebuild project
    RecyclerView mRecyclerView = null;

    ShopCartAdapter mAdapter = null;
......
    @Override
    public void onSuccess(String response) {
        final ArrayList data =
                new ShopCartDataConverter()
                        .setJsonData(response)
                        .convert();
        mAdapter = new ShopCartAdapter(data);
        final LinearLayoutManager manager = new LinearLayoutManager(getContext());
        mRecyclerView.setLayoutManager(manager);//控制其显示的方式,请通过布局管理器LayoutManager
        mRecyclerView.setAdapter(mAdapter);//将视图与适配器绑定,转换数据
    }
}

2.4 效果图

仿电商App:笔记(十一):购物车,订单,支付功能开发(包含支付宝支付)(一)_第3张图片

3、购物车事件逻辑梳理与实现-1

3.1 处理购物车中点击事件

逻辑:设置每个item的初始标记位为false,给每个item的选择框添加点击事件,点击事件前需要获取最新状态的item状态,再根据item状态进行更改;全选:在ShopCartDelegate中通过全选View内置的tag,判断是否全选,然后变换状态,将状态通过Adapter的setIsSelectedAll(boolean isSelectedAll)方法传入item的标志位中,再每个item的点击事件前判断标志位。

位于latte-ec模块main->cart包下的ShopCartAdapter。

主要作用:购物车页面中每个item的转换类,购物车的数据适配器,将json数据与视图绑定。处理item按钮的点击事件和根据根布局中全选状态改变item的状态。

public class ShopCartAdapter extends MultipleRecyclerAdapter {
......
    @Override
    protected void convert(MultipleViewHolder holder, final MultipleItemEntity entity) {
        .......
**             final IconTextView iconIsSelected = holder.getView(R.id.icon_item_shop_cart);
                //赋值
                tvTitle.setText(title);
                tvDesc.setText(desc);
                tvPrice.setText(String.valueOf(price));
                tvCount.setText(String.valueOf(count));
                Glide.with(mContext)
                        .load(thumb)
                        .into(imageThumb);

**              //在左侧勾勾渲染之前改变全选与否状态
                entity.setField(ShopCartItemFields.IS_SELECTED, mIsSelectedAll);
                final boolean isSelected = entity.getFiled(ShopCartItemFields.IS_SELECTED);;

**              //根据数据状态显示左侧勾勾
                if (isSelected){//可根据2、中,先根据是否全选初始化item的状态,因此需要这步初始化状态
                    iconIsSelected.setTextColor
                            (ContextCompat.getColor(Latte.getApplicationContext(),R.color.app_main));
                }else {
                    iconIsSelected.setTextColor(Color.GRAY);
                }
**              //添加左侧勾勾点击事件
                iconIsSelected.setOnClickListener(new View.OnClickListener() {//不要在类上implement(在类上不会对应到每个上面),这里是根据每个item来new不同的实例
                    @Override
                    public void onClick(View v) {
                        final boolean currentSelected = entity.getFiled(ShopCartItemFields.IS_SELECTED);//每次需要动态取状态
                        if (currentSelected){
                            iconIsSelected.setTextColor(Color.GRAY);
                            entity.setField(ShopCartItemFields.IS_SELECTED,false);
                        }else{
                            iconIsSelected.setTextColor
                                    (ContextCompat.getColor(Latte.getApplicationContext(),R.color.app_main));
                            entity.setField(ShopCartItemFields.IS_SELECTED,true);
                        }
                    }
                });
                break;
            default:
                break;
        }
    }
    public void setIsSelectedAll(boolean isSelectedAll) {
        this.mIsSelectedAll = isSelectedAll;
    }
}

3.3 根布局处理全选点击事件

位于latte-ec模块main->cart包下的ShopCartDelegate。

主要作用:购物车页面的根fragment,通过标志位处理全选点击,更改所有item的按钮状态。

public class ShopCartDelegate extends BottomItemDelegate implements ISuccess {

    ......
    @BindView(R2.id.icon_shop_cart_select_all)//用view自带的Tag(唯一数量)记录是否选中状态
    IconTextView mIconSelectAll = null;

    @OnClick(R2.id.icon_shop_cart_select_all)//为全选按钮添加点击事件
    void onClickSelectAll(){
        final int tag = (int) mIconSelectAll.getTag();
        if(tag==0){//没选中
            mIconSelectAll.setTextColor
                    (ContextCompat.getColor(Latte.getApplicationContext(),R.color.app_main));//变为橙色
            mIconSelectAll.setTag(1);//已经选择了
            mAdapter.setIsSelectedAll(true);//在Adapter中记录被选择的状态,
            //更新RecyclerView的显示状态
            mAdapter.notifyItemRangeChanged(0,mAdapter.getItemCount());
        }else {
            mIconSelectAll.setTextColor(Color.GRAY);
            mIconSelectAll.setTag(0);
            mAdapter.setIsSelectedAll(false);
            mAdapter.notifyItemRangeChanged(0,mAdapter.getItemCount());
        }
    }

    .......
    @Override
    public void onBindView(@Nullable Bundle savedInstanceState, View rootView) {
        mIconSelectAll.setTag(0);//默认初始化
    }
......
}

3.4 效果图

仿电商App:笔记(十一):购物车,订单,支付功能开发(包含支付宝支付)(一)_第4张图片

4、删除、清空键的事件处理

逻辑:根据item状态,将选中的加入到待删除的集合中,遍历待删除的集合,获取当前item的position,如果position>0,就更改item位置标志,从adapter中删除;调用adapter中的updateItemRangeFieldPosition(int positionStart)方法,从position头开始变更每个留下的position标志。

位于latte-ec模块main->cart包下的ShopCartDelegate。

主要作用:购物车页面的根fragment,通过选中个数进行删除,删除后更改每个item的位置。

public class ShopCartDelegate extends BottomItemDelegate implements ISuccess {

    private ShopCartAdapter mAdapter = null;
    //购物车数量标记
    private int mCurrentCount = 0;//当前点中要删除的item的数量
    private int mTotalCount = 0;//总共item的数量

    @BindView(R2.id.rv_shop_cart)
    RecyclerView mRecyclerView = null;
    @BindView(R2.id.icon_shop_cart_select_all)
    IconTextView mIconSelectAll = null;
......
    @OnClick(R2.id.tv_top_shop_cart_remove_selected)
    void onClickRemoveSelectedItem() {
        final List data = mAdapter.getData();
        //要删除的数据
        List deleteEntities = new ArrayList<>();
        for (MultipleItemEntity entity : data) {
            final boolean isSelected = entity.getFiled(ShopCartItemFields.IS_SELECTED);
            if (isSelected) {//被选中的就是要删除的
                deleteEntities.add(entity);
            }
        }
        int size = deleteEntities.size();
        int entityPosition = 0;
        for(int i=size-1;i>=0;i--){//取出要删除的entity
            entityPosition = deleteEntities.get(i).getFiled(ShopCartItemFields.POSITION);
            if(entityPosition<=mAdapter.getItemCount()){//防止item被删除,防止位置越界,防止超出数组上线
                mAdapter.remove(entityPosition);//删除数据
            }
        }
        //更新数据
        mAdapter.updateItemRangeFieldPosition(entityPosition);//4、传入小更新的item的POSITION
    }

    @OnClick(R2.id.tv_top_shop_cart_clear)
    void onClickClear() {//清空所有数据
        mAdapter.getData().clear();
        mAdapter.notifyDataSetChanged();
    }
......
}

4.1 数据转换类中,更新删除后的item位置

位于latte-ec模块main->cart包下的ShopCartAdapter。

主要作用:购物车页面中每个item的转换类,购物车的数据适配器,将json数据与视图绑定。通过传入的最小position,更新删除后的item位置。

public class ShopCartAdapter extends MultipleRecyclerAdapter {

    private boolean mIsSelectedAll = false;
    private int mCheckCount = 0;
......
    //删除position位置的item后要更新该位置后面所有item的 POSITION 和 IS_SELECTED , checkCount 要记得--
    public final void updateItemRangeFieldPosition(int positionStart){
        int size = this.getData().size();
        for(int i=positionStart;i

4.2 效果图

仿电商App:笔记(十一):购物车,订单,支付功能开发(包含支付宝支付)(一)_第5张图片  仿电商App:笔记(十一):购物车,订单,支付功能开发(包含支付宝支付)(一)_第6张图片

5、购物车价格计算逻辑梳理,排坑与实现

5.1 当购物车为空时,占位view

逻辑:在购物车根布局页面购物车item部分采用stubView进行占位,布局文件中关联占位布局;当点击全选后/获取数据成功后,需要检查item数量,为0:显示占位布局,部位0:显示RecycleView布局。

latte-ec模块res->layout包,更改delegate_shop_cart.xml文件,(购物车fragment的布局文件)


latte-ec模块res->layout包,stub_shop_cart_no_item.xml文件(购物车中每item的占位的布局文件)




    


位于latte-ec模块main->cart包下的ShopCartDelegate。

主要作用:购物车页面的根fragment,通过选中个数进行删除,删除后更改每个item的位置。

public class ShopCartDelegate extends BottomItemDelegate implements ISuccess {
......
    @BindView(R2.id.stub_no_item)
    ViewStubCompat mStubNoItem = null;//原
......
    @OnClick(R2.id.tv_top_shop_cart_remove_selected)
    void onClickRemoveSelectedItem() {
        ......
        checkItemCount();//检查item数量
    }

    @OnClick(R2.id.tv_top_shop_cart_clear)
    void onClickClear() {
        ......
        checkItemCount();
    }

    void checkItemCount(){//检测recycleView中的item的个数
        final int count = mAdapter.getItemCount();
        if(count==0){//没有item
            final View stubView = mStubNoItem.inflate();//stubView减少View渲染空间,对原来的占位View根据内部layout进行填充
            final AppCompatTextView tvToBuy = stubView.findViewById(R.id.tv_stub_to_buy);//取出文字部分
            tvToBuy.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(getContext(),"你该购物啦!",Toast.LENGTH_SHORT).show();
                }
            });
            mRecyclerView.setVisibility(View.GONE);
        }else {
            mRecyclerView.setVisibility(View.VISIBLE);
        }
    }
......
    @Override
    public void onSuccess(String response) {
......        
        checkItemCount();
    }
}

仿电商App:笔记(十一):购物车,订单,支付功能开发(包含支付宝支付)(一)_第7张图片

5.2 左右加减,使得总数值改变

逻辑:当点击‘-’,‘-’个数>1时,item的数量变化,计算变更后的总价,通过接口回调;购物车根布局实现接口中方法,因为item的总价变化,通过接口中的方法进入到跟布局中,获取总价,进行显示。

位于latte-ec模块main->cart包下的ShopCartAdapter。

主要作用:购物车页面中每个item的转换类,购物车的数据适配器,将json数据与视图绑定。通过选中的item个数和单价,计算总价

public class ShopCartAdapter extends MultipleRecyclerAdapter {
......
    private ICartItemListener mCartItemListener = null;//监听接口    
private double mTotalPrice = 0.0;//总价钱
    private int mCheckCount = 0;
......
    protected ShopCartAdapter(List data) {
        super(data);
        //初始化总价
        for (MultipleItemEntity entity : data) {
            final double price = entity.getFiled(ShopCartItemFields.PRICE);//获取每个item的单个价钱
            final int count = entity.getFiled(ShopCartItemFields.COUNT);//获取每个item的数量
            final double total = price * count;//每个item的总价
            mTotalPrice = mTotalPrice + total;//总total
        }
        //添加购物车item布局
        addItemType(ShopCartItemType.SHOP_CART_ITEM, R.layout.item_shop_cart);
    }
......
    public void setIsSelectedAll(boolean isSelectedAll) {
        this.mIsSelectedAll = isSelectedAll;
    }

    public void setCartItemListener(ICartItemListener listener) {//设置监听接口
        this.mCartItemListener = listener;
    }

    public double getTotalPrice(){//获取总价
        return mTotalPrice;
    }

    @Override
    protected void convert(MultipleViewHolder holder, final MultipleItemEntity entity) {
        super.convert(holder, entity);
        switch (holder.getItemViewType()) {
......            
                //添加加减事件
                iconMinus.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        final int currentCount = entity.getFiled(ShopCartItemFields.COUNT);//从现有数据取出数量值
                        if (Integer.parseInt(tvCount.getText().toString()) > 1) {//数量大于1,可以减
                            RestClient.builder()
                                    .url("shop_cart_count.php")
                                    .loader(mContext)
                                    .params("count", currentCount)
                                    .success(new ISuccess() {
                                        @Override
                                        public void onSuccess(String response) {//点击一次,数据提交到服务器,数量保持同步
                                            int countNum = Integer.parseInt(tvCount.getText().toString());
                                            countNum--;
                                            tvCount.setText(String.valueOf(countNum));//更改数量值
                                            if (mCartItemListener != null) {//如果设置了监听
                                                mTotalPrice = mTotalPrice - price;//每减一个,总价减每个的price
                                                final double itemTotal = countNum * price;//每个item的总价
                                                mCartItemListener.onItemClick(itemTotal);//具体还没操作
                                            }
                                        }
                                    })
                                    .build()
                                    .post();
                        }
                        if (Integer.parseInt(tvCount.getText().toString()) == 1) {
                            Toast.makeText(mContext, "该宝贝不能减少了呦!", Toast.LENGTH_SHORT).show();
                        }
                    }
                });
                iconPlus.setOnClickListener(new View.OnClickListener() {
                    final int currentCount = entity.getFiled(ShopCartItemFields.COUNT);

                    @Override
                    public void onClick(View v) {
                        RestClient.builder()
                                .url("shop_cart_count.php")
                                .loader(mContext)
                                .params("count", currentCount)
                                .success(new ISuccess() {
                                    @Override
                                    public void onSuccess(String response) {
                                        int countNum = Integer.parseInt(tvCount.getText().toString());
                                        countNum++;
                                        tvCount.setText(String.valueOf(countNum));
                                        if (mCartItemListener != null) {
                                            mTotalPrice = mTotalPrice + price;
                                            final double itemTotal = countNum * price;
                                            mCartItemListener.onItemClick(itemTotal);
                                        }
                                    }
                                })
                                .build()
                                .post();
                    }
                });
                break;
            default:
                break;
        }
    }
}

位于latte-ec模块main->cart包下的ICartItemListener接口。

主要作用:传item的总价,通过接口返回值。

public interface ICartItemListener {
    void onItemClick(double itemTotalPrice);
}

位于latte-ec模块main->cart包下的ShopCartDelegate。

主要作用:购物车页面的根fragment,回调监听商品总价。

public class ShopCartDelegate extends BottomItemDelegate implements ISuccess,ICartItemListener {

    private ShopCartAdapter mAdapter = null;
    //购物车数量标记
    private int mCurrentCount = 0;
    private int mTotalCount = 0;
......
    @BindView(R2.id.tv_shop_cart_total_price)//购物车总价钱的按钮
    AppCompatTextView mTotalPrice = null;
.......
    @Override
    public void onSuccess(String response) {
        final ArrayList data =
                new ShopCartDataConverter()
                        .setJsonData(response)
                        .convert();
        mAdapter = new ShopCartAdapter(data);
**      mAdapter.setCartItemListener(this);//数据请求结束,添加监听
        final LinearLayoutManager manager = new LinearLayoutManager(getContext());
        mRecyclerView.setLayoutManager(manager);
        mRecyclerView.setAdapter(mAdapter);
        checkItemCount();
    }

    @Override
    public void onItemClick(double itemTotalPrice) {
        final double price = mAdapter.getTotalPrice();//购物车总价
        mTotalPrice.setText(String.valueOf(price));//购物车总价显示
    }

仿电商App:笔记(十一):购物车,订单,支付功能开发(包含支付宝支付)(一)_第8张图片  仿电商App:笔记(十一):购物车,订单,支付功能开发(包含支付宝支付)(一)_第9张图片

 

你可能感兴趣的:(latte项目)