自定义 LayoutManger需要注意的几个地方

最近写销控表,需要有上万个数据表格的情况,
首先感谢 https://blog.csdn.net/wuyuxing24/article/details/79047924 的帖主,给了大家一个非常好的例子。本文也是根据他的帖子的原理,整理了自己在编写销控表的时候遇到的问题。

辅助字段帮助layoutDecoratedWithMargins进行定位;

很多demo 在onLayoutChildren 方法中 进行两个动作,一个是计算得到真实的最大宽高,一个是进行layout的动作, 我的观点,一旦外部数据获得的那时候,完全可以给实体添加字段计算好,左上右下的位置,把实体扔进来,比如添加下面的字段,进行定位的时候就很简单方便了
,即使是遇到异型单元格,比如有些单元格横向有合并,或者有些单元格纵向有合并的情况,也方便处理。

	//辅助在 onLayoutChildren 进行layoutDecoratedWithMargins的定位
	//需要布局的单元的宽度
	private int width;
	//需要布局的单元的高度
    private int height;
    //需要布局的单元的左边位置
    private int left;
    //需要布局的单元的上边位置
    private int top;

layoutDecoratedWithMargins的时候 就可以直接把数据bean扔进来解决问题

layoutDecoratedWithMargins(view, bean.getLeft() - mOffsetHorizontal, bean.getTop() - mOffsetVertical,  bean.getLeft() + bean.getWidth() - mOffsetHorizontal, bean.getTop() + bean.getHeight() - mOffsetVertical);

onLayoutChildren 中判断位置是否屏幕可见再获取view

很多demo在for循环一开始就去recycler.getViewForPosition(i),但这会有一个问题,当你的view特别多时,我遇到的是,可能有上万数据。这个时候 for循环的时候先去recycler.getViewForPosition(i); 会导致上万次的获取view ,这样的话,即使你在 Rect.intersects(mLayoutState.mSlideAreaRect, itemRect) 为 false 的时候去调用removeAndRecycleView(view, recycler); 进行view 的回收,依然会存在性能和卡顿问题。
但如果你根据屏幕是否可见,再去getView ,那个总共需要获取的view数,只是屏幕可见的那些个,理论上顶多100到200个,每次滑动的时候,scrollHorizontallyBy 或者 scrollVerticallyBy中可以detachAndScrapAttachedViews ,进行回收,性能大大提高。比如下面的代码,在view 不再屏幕可见的时候,也不需要执行removeAndRecycleView(view, recycler); 也不会卡顿,因为滑动的时候,一般都会去调用detachAndScrapAttachedViews

private void fillChildren2(RecyclerView.Recycler recycler, RecyclerView.State state) {
		if (getItemCount() <= 0 || state.isPreLayout()) {
			return;
		}
		Rect itemRect = new Rect();
		//处理header
		int displayNum = 0;
		int skipNum = 0;
		for(int i = 0; i < itemList.size(); i++) {

			ItemDataBean bean = itemList.get(i);
			itemRect.set(bean.getLeft(), bean.getTop(), bean.getLeft() + bean.getWidth(), bean.getTop() + bean.getHeight());
			if(Rect.intersects(mLayoutState.mSlideAreaRect, itemRect)) {
				View view = recycler.getViewForPosition(i);
				RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) view.getLayoutParams();
				displayNum++;
				layoutParams.width = bean.getWidth();
				layoutParams.height = bean.getHeight();
//				view.setLayoutParams(layoutParams);
				addView(view);
				measureChildWithMargins(view, 0, 0);
				layoutDecoratedWithMargins(view, bean.getLeft() - mLayoutState.mOffsetHorizontal, bean.getTop() - mLayoutState.mOffsetVertical,  bean.getLeft() + bean.getWidth() - mLayoutState.mOffsetHorizontal, bean.getTop() + bean.getHeight() - mLayoutState.mOffsetVertical);
			} else {
				//移除并回收掉滑出屏幕的View
//				removeAndRecycleView(view, recycler);
				skipNum++;
				continue;
			}

		}
		Log.e("LayoutManager",  "displayNum" + displayNum);
		Log.e("LayoutManager", "skipNum" + skipNum);
	}

ItemDecoration 无法重新绘制的问题

当你绘制一遍所有子view 后,你会发现,当你把这些在LayoutManger绘制过的view 重新拿出一些依照你的需求摆放时,可能这样说很抽象,给个图, 如下图这种销控表,当你需要固定楼层那一列,基本上做法是重新拿出已经摆放在底层的,再绘制一遍在指定的固定位置,这个时候你会发现这些重新绘制的view的ItemDecoration不见了,但参考官网说法,ItemDecoration中的onDraw是绘制在最底层的,从下到上是canvas → ItemDecoration → 你第一次绘制的view → 你第二次绘制的view ,就是说不管是否是第二次绘制的view ,ItemDecoration 始终是在最底层,所以给人一种第二次绘制的view没有ItemDecoration 的假象,因为他会被第一次绘制view 的遮住。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值