关于MVP架构,类似的文章太多了,此处省略, Retrofit + Rx框架类似的文章也很多,此处也省略,主要写双层RecyclerView的适配器。
店铺层:RecyclerCartAdapter
商品层:RecyclerCartPlusAdapter
RecyclerCartAdapter提供ISelectAll,IPlusOrMinus,IParentDeSelect三个接口,由View层的Fragment来实现,RecyclerCartAdapter对外提供两个公共方法outCheckAll,outUpdateRecycler,具体功能如下:
ISelectAll:监视所有的店铺是否都已选中,此时应更新Fragment的全选按钮为选中状态。
IPlusOrMinus:提供重算Fragment中的总价和总数量的两个方法 (reCalculatePrice,reCalculateCount)。
IParentDeSelect:将店铺是否选中的状态传递到Fragment,由presenter(展示层)调用Api去更新网站后台数据;接收由商品层适配器传递过来的商品是否选中的状态,并传递给Fragment,由presenter(展示层)调用Api去更新网站后台数据。
outCheckAll:在Fragment中点击全选按钮,更新两层RecyclerView的状态和数据,并更新总价和总数量。
outUpdateRecycler:在Fragment中点击删除和清空,更新两层RecyclerView的状态和数据。
RecyclerCartPlusAdapter提供ICheckParent,IChildDeSelect两个接口,由外层的RecyclerCartAdapter来实现,功能如下:
ICheckParent,将商品ID,所在店铺ID,商品单价、数量,是否选中传递到外层的RecyclerCartAdapter,由外层的RecyclerCartAdapter分析是否该店铺下所有商品都已选中,此时应更新店铺为选中状态,调用IPlusOrMinus中的方法更新Fragment的总价和数量。
IChildDeSelec:将商品是否选中的状态传递到外层的RecyclerCartAdapter。
第一层RecyclerView(店铺),对应CartShopEntity
public class RecyclerCartAdapter extends RecyclerView.Adapter implements RecyclerCartPlusAdapter.ICheckParent,RecyclerCartPlusAdapter.IChildDeSelect {
private List mCartShopEntities = new ArrayList();
private Context mContext;
private RecyclerCartPlusAdapter mCartPlusAdapter;
private CompoundButton.OnCheckedChangeListener mOnCheckedChangeListener;
private ISelectAll mISelectAll;
private IPlusOrMinus mPlusOrMinus;
private boolean isOutCheck = false;
private IParentDeSelect mParentDeSelect;
public RecyclerCartAdapter(List cartShopEntities, Context context, ISelectAll selectAll, IPlusOrMinus plusOrMinus, IParentDeSelect parnetDeSelect) {
mCartShopEntities = cartShopEntities;
mContext = context;
mISelectAll = selectAll;
mPlusOrMinus = plusOrMinus;
mParentDeSelect = parnetDeSelect;
}
public void setCartShopEntities(List cartShopEntities) {
mCartShopEntities = cartShopEntities;
notifyDataSetChanged();
}
public void setContext(Context context) {
mContext = context;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(mContext).inflate(R.layout.item_cart_shops, null,false);
return new ItemHolder(view);
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
ItemHolder mItemHolder = (ItemHolder) viewHolder;
mItemHolder.shop_name.setText(mCartShopEntities.get(i).getShopName());
Picasso.with(mContext)
.load(WebApiContent.BASEURL + mCartShopEntities.get(i).getShopImg())
.placeholder(R.drawable.icon_default)
.into(mItemHolder.shop_logo);
mCartPlusAdapter = new RecyclerCartPlusAdapter(mContext, mCartShopEntities.get(i).getList(),WebApiContent::cartGoodDetail,this,this);
if (mItemHolder.cart_shop_goods.getAdapter() == null){
mItemHolder.cart_shop_goods.setAdapter(mCartPlusAdapter);
}
mOnCheckedChangeListener = (buttonView, isChecked) -> {
double totalPrice = 0;
long buyNum = 0;
List cartIds = new ArrayList();
for (CartGoodEntity goodEntity : mCartShopEntities.get(i).getList()) {
if (isChecked){
if (goodEntity.getIsCheck() == 0){
cartIds.add(goodEntity.getCartId());
buyNum += goodEntity.getCartNum();
totalPrice += Double.parseDouble(goodEntity.getShopPrice()) * goodEntity.getCartNum();
}
} else {
cartIds.add(goodEntity.getCartId());
buyNum += goodEntity.getCartNum();
totalPrice += Double.parseDouble(goodEntity.getShopPrice()) * goodEntity.getCartNum();
}
goodEntity.setIsCheck(isChecked ? 1 : 0);
}
mCartShopEntities.get(i).setIsCheck(isChecked ? 1 : 0);
boolean isCheckAll = true;
for (CartShopEntity cartShopEntity : mCartShopEntities) {
if (cartShopEntity.getIsCheck() == 0){
isCheckAll = false;
break;
}
}
int deSelect = isChecked ? 1 : 0;
mISelectAll.selectAll(isCheckAll);
mPlusOrMinus.reCalculatePrice(totalPrice,isChecked);
mPlusOrMinus.reCalculateCount(buyNum,isChecked);
mParentDeSelect.parentDeSelect(cartIds,deSelect);
mItemHolder.cart_shop_goods.getAdapter().notifyDataSetChanged();
};
mItemHolder.mCheckShop.setOnCheckedChangeListener(null);
if (mCartShopEntities.get(i).getIsCheck() == 1){
mItemHolder.mCheckShop.setChecked(true);
} else if (mCartShopEntities.get(i).getIsCheck() == 0){
mItemHolder.mCheckShop.setChecked(false);
}
mItemHolder.mCheckShop.setOnCheckedChangeListener(mOnCheckedChangeListener);
if (isOutCheck){
mItemHolder.cart_shop_goods.getAdapter().notifyDataSetChanged();
}
if (i == mCartShopEntities.size()){
isOutCheck = false;
}
}
@Override
public int getItemCount() {
return mCartShopEntities.size();
}
@Override
public void setCheckParent(int ShopId,int GoodsId,boolean isPlusOrMinus,double goodPrice,int buyNum) {
boolean isCheckShop = true;
for (CartShopEntity cartShopEntity : mCartShopEntities) {
if (cartShopEntity.getShopId() == ShopId) {
List list = cartShopEntity.getList();
for (CartGoodEntity goodEntity : list) {
if (goodEntity.getIsCheck() == 0){
isCheckShop = false;
break;
}
}
cartShopEntity.setIsCheck(isCheckShop?1:0);
break;
}
}
boolean isCheckAll = true;
for (CartShopEntity cartShopEntity : mCartShopEntities) {
if (cartShopEntity.getIsCheck() == 0){
isCheckAll = false;
break;
}
}
mISelectAll.selectAll(isCheckAll);
double totalPrice = goodPrice * (double) buyNum;
String formattotalPrice = String.format("%.2f", totalPrice);
mPlusOrMinus.reCalculatePrice(Double.parseDouble(formattotalPrice),isPlusOrMinus);
mPlusOrMinus.reCalculateCount(buyNum,isPlusOrMinus);
updateRecycler();
}
public void updateRecycler(){
new Handler().post(new Runnable() {
@Override
public void run() {
notifyDataSetChanged();
}
});
}
public void updateRecycler(int i){
new Handler().post(new Runnable() {
@Override
public void run() {
notifyItemChanged(i);
}
});
}
public void outUpdateRecycler(){
isOutCheck = true;
updateRecycler();
}
@Override
public void childDeSelect(List cartIds, int deSelect) {
mParentDeSelect.parentDeSelect(cartIds,deSelect);
}
public class ItemHolder extends RecyclerView.ViewHolder{
@BindView(R.id.shop_logo)
ImageView shop_logo;
@BindView(R.id.shop_name)
TextView shop_name;
@BindView(R.id.cart_shop_goods)
RecyclerView cart_shop_goods;
@BindView(R.id.checkShop)
CheckBox mCheckShop;
public ItemHolder(@NonNull View itemView) {
super(itemView);
ButterKnife.bind(this,itemView);
LinearLayoutManager manager = new LinearLayoutManager(mContext){
@Override
public RecyclerView.LayoutParams generateDefaultLayoutParams() {
return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}
};
manager.setOrientation(LinearLayoutManager.VERTICAL);
manager.setAutoMeasureEnabled(false);
cart_shop_goods.setFocusableInTouchMode(false);
cart_shop_goods.requestFocus();
cart_shop_goods.setNestedScrollingEnabled(false);
cart_shop_goods.setHasFixedSize(true);
cart_shop_goods.setLayoutManager(manager);
cart_shop_goods.setItemAnimator(new DefaultItemAnimator());
cart_shop_goods.addItemDecoration(new SpacesItemDecoration(1));
}
}
public interface ISelectAll{
void selectAll(boolean canSelectAll);
}
public interface IPlusOrMinus{
void reCalculatePrice(double price, boolean isPlusOrMinus);
void reCalculateCount(long cartNum, boolean isPlusOrMinus);
}
public interface IParentDeSelect {
void parentDeSelect(List cartIds,int deSelect);
}
public void outCheckAll(boolean canCheckAll){
double totalPrice = 0;
long buyNum = 0;
for (CartShopEntity cartShopEntity : mCartShopEntities) {
cartShopEntity.setIsCheck(canCheckAll ? 1 : 0);
for (CartGoodEntity goodEntity : cartShopEntity.getList()) {
if (canCheckAll && goodEntity.getIsCheck() == 0){
buyNum += goodEntity.getCartNum();
totalPrice += Double.parseDouble(goodEntity.getShopPrice()) * goodEntity.getCartNum();
} else if (!canCheckAll && goodEntity.getIsCheck() == 1){
buyNum += goodEntity.getCartNum();
totalPrice += Double.parseDouble(goodEntity.getShopPrice()) * goodEntity.getCartNum();
}
goodEntity.setIsCheck(canCheckAll ? 1 : 0);
}
}
mPlusOrMinus.reCalculatePrice(totalPrice,canCheckAll);
mPlusOrMinus.reCalculateCount(buyNum,canCheckAll);
isOutCheck = true;
updateRecycler();
}
}
第二层RecyclerView(商品),对应CartGoodEntity
public class RecyclerCartPlusAdapter extends RecyclerView.Adapter {
private List mCartGoodEntities = new ArrayList();
private Context mContext;
private WebApiContent.CartGoodClickCallback mGoodsClickCallback;
private ICheckParent mCheckParent;
private IChildDeSelect mChildDeSelect;
public RecyclerCartPlusAdapter(Context context, List cartGoodEntities, WebApiContent.CartGoodClickCallback goodsClickCallback, ICheckParent checkParent,IChildDeSelect childDeSelect) {
mCartGoodEntities = cartGoodEntities;
mContext = context;
mGoodsClickCallback = goodsClickCallback;
mCheckParent = checkParent;
mChildDeSelect = childDeSelect;
}
public void setCartGoodEntities(List cartGoodEntities) {
mCartGoodEntities = cartGoodEntities;
notifyDataSetChanged();
}
public void setContext(Context context) {
mContext = context;
}
public void setGoodsClickCallback(WebApiContent.CartGoodClickCallback goodsClickCallback) {
mGoodsClickCallback = goodsClickCallback;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(mContext).inflate(R.layout.itme_cart_goods, viewGroup,false);
return new ChildItemHolder(view);
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
ChildItemHolder itemHolder = (ChildItemHolder) viewHolder;
double totalPrice = Double.parseDouble(mCartGoodEntities.get(i).getShopPrice()) * (double) mCartGoodEntities.get(i).getCartNum();
String formattotalPrice = String.format("%.2f", totalPrice);
itemHolder.price_goods_item.setText(formattotalPrice + "元");
itemHolder.title_goods_item.setText(mCartGoodEntities.get(i).getGoodsName());
itemHolder.cart_goods_buyNum.setText(String.valueOf(mCartGoodEntities.get(i).getCartNum()) + "件");
Picasso.with(mContext)
.load(WebApiContent.BASEURL + mCartGoodEntities.get(i).getGoodsImg())
.placeholder(R.drawable.icon_default)
.into(itemHolder.iv_goods_item);
itemHolder.mCheckGood.setOnCheckedChangeListener(null);
if (mCartGoodEntities.get(i).getIsCheck() == 0){
itemHolder.mCheckGood.setChecked(false);
} else {
itemHolder.mCheckGood.setChecked(true);
}
itemHolder.liner_item_good.setOnClickListener(v -> mGoodsClickCallback.onItemClicked(mContext,mCartGoodEntities.get(i)));
itemHolder.mCheckGood.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked){
mCartGoodEntities.get(i).setIsCheck(1);
} else {
mCartGoodEntities.get(i).setIsCheck(0);
}
List cartIDs = new ArrayList();
cartIDs.add(mCartGoodEntities.get(i).getCartId());
int deSelect = isChecked ? 1 : 0;
mChildDeSelect.childDeSelect(cartIDs,deSelect);
mCheckParent.setCheckParent(mCartGoodEntities.get(i).getShopId(),
mCartGoodEntities.get(i).getGoodsId(),
isChecked,
Double.parseDouble(mCartGoodEntities.get(i).getShopPrice()),
mCartGoodEntities.get(i).getCartNum());
notifyDataSetChanged();
}
});
}
@Override
public int getItemCount() {
return mCartGoodEntities.size();
}
public class ChildItemHolder extends RecyclerView.ViewHolder {
@BindView(R.id.iv_goods_item)
ImageView iv_goods_item;
@BindView(R.id.title_goods_item)
TextView title_goods_item;
@BindView(R.id.price_goods_item)
TextView price_goods_item;
@BindView(R.id.liner_item_good)
LinearLayout liner_item_good;
@BindView(R.id.cart_goods_buyNum)
TextView cart_goods_buyNum;
@BindView(R.id.checkGood)
CheckBox mCheckGood;
public ChildItemHolder(@NonNull View itemView) {
super(itemView);
ButterKnife.bind(this,itemView);
}
}
public void setCheckParent(ICheckParent checkParent) {
mCheckParent = checkParent;
}
public interface ICheckParent {
void setCheckParent(int ShopId,int GoodsId,boolean isPlusOrMinus,double goodPrice,int buyNum);
}
public interface IChildDeSelect {
void childDeSelect(List cartIds,int deSelect);
}
}
View层,我使用Fragment
public class MainCartFragment extends BaseFragment implements CartContract.IGartView,RecyclerCartAdapter.ISelectAll,RecyclerCartAdapter.IPlusOrMinus, RecyclerCartAdapter.IParentDeSelect,SwipeRefreshLayout.OnRefreshListener {
@BindView(R.id.cart_list_recycler)
RecyclerView cart_list_recycler;
@BindView(R.id.cart_list_relative)
RelativeLayout cart_list_relative;
@BindView(R.id.iv_emptycart)
ImageView iv_emptycart;
@BindView(R.id.cart_good_counts)
TextView cart_good_counts;
@BindView(R.id.checkAll)
CheckBox mCheckAll;
@BindView(R.id.tv_total)
TextView tv_total;
@BindView(R.id.btn_settle)
Button btn_settle;
@BindView(R.id.tv_clearCart)
TextView tv_clearCart;
@BindView(R.id.tv_deleteCart)
TextView tv_deleteCart;
@BindView(R.id.tv_editCart)
TextView tv_editCart;
@BindView(R.id.swipe_carts)
SwipeRefreshLayout mSwipe_carts;
private List mResultShopEntities;
private CompoundButton.OnCheckedChangeListener mCheckedChangeListener;
private Handler mHandler = new Handler();
private Runnable mRefresh = new Runnable() {
@Override
public void run() {
mSwipe_carts.setRefreshing(false);
//此处代码隐藏,内容为调用Api获取最新的购物车数据
}
};
@OnClick(R.id.tv_clearCart)
public void clearCart(){
//此处代码隐藏,内容为调用Api清空购物车数据
mResultShopEntities = new ArrayList();
mCartAdapter.setCartShopEntities(mResultShopEntities);
mTotalCartNum = 0;
mCheckAll.setOnCheckedChangeListener(null);
mCheckAll.setChecked(false);
mCheckAll.setOnCheckedChangeListener(mCheckedChangeListener);
}
@OnClick(R.id.tv_deleteCart)
public void deleteCart(){
if (mCheckAll.isChecked()){
clearCart();
return;
}
int minusNum = 0;
List goodIdList = new ArrayList();
for (CartShopEntity shopEntity : mResultShopEntities) {
for (CartGoodEntity goodEntity : shopEntity.getList()) {
if (goodEntity.getIsCheck() == 1) {
goodIdList.add(goodEntity.getGoodsId());
minusNum += goodEntity.getCartNum();
}
}
}
mTotalCartNum -= minusNum;
int[] goodListArray = new int[goodIdList.size()];
for (int i = 0; i < goodIdList.size(); i++) {
goodListArray[i] = goodIdList.get(i);
}
//此处代码隐藏,内容为调用Api删除选中的购物车数据
for (CartShopEntity shopEntity : mResultShopEntities) {
ListIterator goodListIterator = shopEntity.getList().listIterator();
while (goodListIterator.hasNext()){
CartGoodEntity nextGood = goodListIterator.next();
if (goodIdList.contains(nextGood.getGoodsId())){
goodListIterator.remove();
}
}
}
Iterator shopListIterator = mResultShopEntities.iterator();
while (shopListIterator.hasNext()){
CartShopEntity nextShop = shopListIterator.next();
if (nextShop.getList().size() == 0){
shopListIterator.remove();
}
}
}
@OnClick(R.id.tv_editCart)
public void editCart(){
if (tv_editCart.getText().toString().equals("编辑")) {
tv_total.setVisibility(View.GONE);
btn_settle.setVisibility(View.GONE);
tv_editCart.setText("完成");
tv_deleteCart.setVisibility(View.VISIBLE);
tv_clearCart.setVisibility(View.VISIBLE);
} else if (tv_editCart.getText().toString().equals("完成")){
tv_total.setVisibility(View.VISIBLE);
btn_settle.setVisibility(View.VISIBLE);
tv_editCart.setText("编辑");
tv_deleteCart.setVisibility(View.GONE);
tv_clearCart.setVisibility(View.GONE);
}
}
private RecyclerCartAdapter mCartAdapter;
private double mTotalPrice = 0;
private long mTotalCartNum = 0;
@Override
protected CartPresenter createPresenter() {
return new CartPresenter(this);
}
@Override
protected int getLayoutId() {
return R.layout.fragment_main_cart;
}
@Override
protected void initToolbar(Bundle savedInstanceState) {
}
@Override
protected void initData() {
mResultShopEntities = new ArrayList();
mSwipe_carts.setOnRefreshListener(this);
mSwipe_carts.setColorSchemeResources(
R.color.red, R.color.orange, R.color.green, R.color.blue);
List list = new ArrayList();
mCartAdapter = new RecyclerCartAdapter(list,mContext,this,this,this);
//此处代码隐藏,内容为调用Api获取最新的购物车数据
LinearLayoutManager manager = new LinearLayoutManager(mContext);
manager.setOrientation(LinearLayoutManager.VERTICAL);
manager.setAutoMeasureEnabled(false);
cart_list_recycler.setLayoutManager(manager);
cart_list_recycler.setHasFixedSize(true);
cart_list_recycler.setItemAnimator(new DefaultItemAnimator());
cart_list_recycler.addItemDecoration(new SpacesItemDecoration(1));
cart_list_recycler.setAdapter(mCartAdapter);
mCheckedChangeListener = new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
mCartAdapter.outCheckAll(isChecked);
}
};
RxCompoundButton.checkedChanges(mCheckAll).subscribe(aBoolean -> tv_clearCart.setEnabled(aBoolean));
}
@Override
public void onDestroyView() {
super.onDestroyView();
mTotalCartNum = 0;
mTotalPrice = 0;
mResultShopEntities.clear();
}
@Override
public void setStatus(int status, String info) {
if (info.equals("refresh")){
mResultShopEntities = new ArrayList();
mCartAdapter = new RecyclerCartAdapter(mResultShopEntities,mContext,this,this,this);
cart_list_recycler.setAdapter(mCartAdapter);
}
}
@Override
public void setData() {
mCartAdapter.setCartShopEntities(mResultShopEntities);
mCartAdapter.outUpdateRecycler();
cart_good_counts.setText("共" + mTotalCartNum + "件宝贝");
mTotalPrice = 0;
tv_total.setText("合计:¥" + mTotalPrice);
}
@Override
public void setAdapter(CartTotalEntity cartTotalEntity) {
mResultShopEntities = new ArrayList();
if (MainApplication.totalPriceNet > 0){
mTotalPrice = MainApplication.totalPriceNet;
String formattotalPrice = String.format("%.2f", mTotalPrice);
tv_total.setText("合计:¥" + formattotalPrice);
}
if (cartTotalEntity.getCarts().size() > 0) {
boolean isCheckAll = true;
mResultShopEntities = cartTotalEntity.getCarts();
for (CartShopEntity cartShopEntity : mResultShopEntities) {
if (isCheckAll){
for (CartGoodEntity goodEntity : cartShopEntity.getList()){
if (goodEntity.getIsCheck() == 0){
isCheckAll = false;
break;
}
}
}
}
mCheckAll.setOnCheckedChangeListener(null);
if (isCheckAll){
mCheckAll.setChecked(true);
}
mCheckAll.setOnCheckedChangeListener(mCheckedChangeListener);
for (CartShopEntity resultShopEntity : mResultShopEntities) {
resultShopEntity.setIsCheck(1);
for (CartGoodEntity goodEntity : resultShopEntity.getList()) {
if (goodEntity.getIsCheck() == 0){
resultShopEntity.setIsCheck(0);
break;
}
}
}
mTotalCartNum = 0;
for (CartShopEntity shopEntity : mResultShopEntities) {
for (CartGoodEntity goodEntity : shopEntity.getList()) {
mTotalCartNum += goodEntity.getCartNum();
}
}
iv_emptycart.setVisibility(View.GONE);
cart_good_counts.setText("共" + mTotalCartNum + "件宝贝");
cart_list_relative.setVisibility(View.VISIBLE);
mCartAdapter.setCartShopEntities(mResultShopEntities);
} else {
cart_list_relative.setVisibility(View.INVISIBLE);
iv_emptycart.setVisibility(View.VISIBLE);
}
}
@Override
public void showLoading() {
//
}
@Override
public void hideLoading() {
//
}
@Override
public void showMsg(String msg) {
showToast(msg);
}
@Override
public void selectAll(boolean canSelectAll) {
mCheckAll.setOnCheckedChangeListener(null);
if (canSelectAll){
mCheckAll.setChecked(true);
} else {
mCheckAll.setChecked(false);
}
mCheckAll.setOnCheckedChangeListener(mCheckedChangeListener);
}
@Override
public void reCalculatePrice(double price, boolean isPlusOrMinus) {
if (isPlusOrMinus){
mTotalPrice += price;
} else {
mTotalPrice -= price;
}
mTotalPrice = Math.abs(mTotalPrice);
String formattotalPrice = String.format("%.2f", mTotalPrice);
tv_total.setText("合计:¥" + formattotalPrice);
}
@Override
public void reCalculateCount(long cartNum, boolean isPlusOrMinus) {
if (isPlusOrMinus){
mTotalCartNum += cartNum;
} else {
mTotalCartNum -= cartNum;
}
cart_good_counts.setText("共" + mTotalCartNum + "件宝贝");
}
@Override
public void onRefresh() {
mTotalPrice = 0;
mTotalCartNum = 0;
mResultShopEntities.clear();
mHandler.postDelayed(mRefresh,2000);
}
@Override
public void parentDeSelect(List cartIds,int deSelect) {
//此处代码隐藏,内容为调用Api更新购物车是否选中的状态数据
}
}