最近在重构APP的购物车功能,要实现的效果如下:
看上去挺简单的吧,之前用的布局是:
ScrollView+动态创建ListView(购物车有多少个供应商就add多少个ListView)
我重构购物车的目的:
1.布局修改,外层布局使用RecyclerView
2.全选能悬浮在购物车的底部,需要时展示
就这样两个改动,遇到了挺多问题,遇到问题就解决呗,以下是我记录的问题和重构时的想法。
重构一个模块我认为最重要的是理清逻辑,并且想好总布局该怎么做。
这个布局我最终用的布局如下,先写布局,展示里层数据,底部悬浮效果和实现功能先放一边。
RecyclerView(多布局,分为三块:配送中心(LinearLayout)+商品(RecyclerView)+底部价格(LinearLayout))
这个外层布局没啥好说的,做这一块出现问题了:
问题1:点击购物车-》点击其它模块-》点击购物车,重新获取数据-》刷新RecyclerView,这个本身逻辑没有问题,但是刷新时RecyclerView会自动移动到第二条数据,具体原因我还是没有找到,但我有解决方法。
解决:动态加载RecyclerView,每次跳转到购物车时动态创建RecyclerView。
接下来实现全选,单选,删除等逻辑,购物车的功能,这部分问题还是挺多的,点击底部全选要刷新商品选择状态,单个商品选择状态改变要刷新底部全选状态。
问题2:第二层RecyclerView中没有数据时,需要手动更新第一层RecyclerView,将其对应数据的头部、底部布局去掉。
解决: 在删除单个商品后判断该部分商品是否isEmpty,是空证明需要刷新,在设置数据的Fragment中将该数据源删除,然后adapter.notifyDataSetChanged();(可使用EventBus)
if (ArrayUtil.isEmpty(goodses)) {
presenter.notifyData(tag);
}
问题3:点击某个商品,需刷新对应的底部布局。
解决:和问题2差不多,在某个商品状态改变时,在设置数据的Fragment中刷新对应的position。
问题4:由问题3产生,设置数据的Fragment中刷新对应的position。
cartListAdapter.notifyItemChanged(msg.arg1);
在运行时会报错,直接导致程序崩溃。
原因:前几天查的,不知道记得对不对。在RecyclerView绘制或者滑动时刷新某个数据。
解决:这个方法能解决就没有试别的方法了。
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == 1) {
cartListAdapter.notifyItemChanged(msg.arg1);
}
}
};
功能这块折腾完了,没毛病。接下来看那个悬浮效果了,这可是个大坑呀。
思路:第一层RecyclerView的滑动事件addOnScrollListener获取到最后一个可见的position,根据position判断是哪个配送中心对应部分,然后展示对应的底部布局数据。
好,一堆问题来了。
问题5:addOnScrollListener是滑动事件,如果点击了某个地方的商品,不滑动不会更新底部数据。
解决:在某个商品状态改变时,手动更新底部布局数据。这里还需判断底部展示的position是否和改变的position相等。
问题6:例:当商品数据为一个时,还不会占满屏幕,它的底部还是会展示出来,很丑。
解决:这个问题我选择迂回战术解决,不会占满屏幕就证明数据太少了,它也不能滑动,所以外层RecyclerView第一个可见position就会一直是0,判断 position!=0 时才展示底部布局就行。
问题7:点击全选多次时,程序直接崩溃。
解决:这个问题就厉害了,找这个问题找的最久。在改变底部的选择状态时需要去刷新它对应的商品选择状态,也就是刷新里层RecyclerView,之前刷新用的外层RecyclerView对应的notifyItemChanged();
改成里层RecyclerView对应adapter.notifyDataSetChanged() 就可以了。
cartGoodsAdapters.get(position).setGoodsList(goodses);
cartGoodsAdapters.get(position).notifyDataSetChanged();
外层RecyclerView滑动逻辑:
//设置RecyclerView的滑动事件
recycler_cart1.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int firstItemPosition = 0;
int lastItemPosition = 0;
RecyclerView.LayoutManager layoutManager = recycler_cart1.getLayoutManager();
if (layoutManager instanceof LinearLayoutManager) {
firstItemPosition = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
lastItemPosition = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();
if (firstItemPosition != 0 && (lastItemPosition % 3 == 1 || lastItemPosition % 3 == 2)) {
if (view_center.getVisibility() != View.VISIBLE)
view_center.setVisibility(View.VISIBLE);
//当前是哪一组数据
int position = lastItemPosition / 3;
if (curShowPosition != position) {
initIsShowBottomView(position);
}
} else {
view_center.setVisibility(View.GONE);
}
}
}
});
private void initIsShowBottomView(int position) {
if ("0".equals(couldReplenishment) && orderTypes.get(position) != 2) {
tvReplenishment.setVisibility(View.VISIBLE);
couldReplenishment = "0";
} else {
tvReplenishment.setVisibility(View.GONE);
couldReplenishment = "1";
}
setBottomOnClickListener(position);
setViewData(position);
curShowPosition = position;
}