“傻瓜”式填充,自定义LayoutManager
来源:互联网 发布:netbeans php下载 编辑:程序博客网 时间:2024/05/17 17:55
“傻瓜”式填充,自定义LayoutManager
RecycleView的高效是众所周知的事了,官方提供的LayoutManager基本上能满足90%上以的界面开发了,但难免会有一些“非人类”设计师会想出的界面,例如机顶盒上不规则的gridlayout了,但是这种情况也可以通过自定义的LayoutManager来解决
在自定义LayoutManager前,我们先来简单的学习一下RecycleView的两级缓存:scrapt和recycle。
scrap Heap,当需要view时,recycle会来这里查找有没有所需要的view,注意这里的view是可以直接使用的,即不会再触发bindViewHolder 了,我们可以通过detachAndScrapView方法将view回收到scrap
Recycle Pool,当在scrap里没有找到直接的view可以用时,会来recycle里查找是否有可以间接使用的view,即通过适配器重新绑定数据bindViewHolder后可以使用。我们可以通过removeAndRecycleView来将view回收至recycle里。
先看效果:
代码:
public class HomeLayoutManager extends RecyclerView.LayoutManager { private LayoutState mLayoutState; private ArrayList<RectF> mItemRectFList; //用来判断是否到边界了 private int mTotalW; //主要用来标志item是否已在当前界面上 private final HiveBucket mBooleanMap = new HiveBucket(); public HomeLayoutManager(ArrayList<RectF> itemRectFList) { mItemRectFList = itemRectFList; init(); } private void init() { mLayoutState = new LayoutState(); mBooleanMap.reset(); } @Override public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {// super.onLayoutChildren(recycler, state); int itemCount = state.getItemCount(); if (itemCount <= 0) { return; } if (state.isPreLayout()) { return; } //回收当前所有的view到Scrap里 detachAndScrapAttachedViews(recycler); //初始化标志位 mBooleanMap.reset(); // 遍历所有的item fill(recycler, state); } private void fill(RecyclerView.Recycler recycler, RecyclerView.State state) { if (state.isPreLayout()) { return; } //更新recycleview的控件窗口位置 updateLayoutState(); mTotalW = 0; int itemCount = state.getItemCount(); for (int i = 0; i < itemCount; i++) { // 得到当前position下的视图显示区域 RectF bounds = new RectF(mItemRectFList.get(i)); //需要根据你的实际情况来设置边界值 if (bounds.right > mTotalW) { mTotalW = (int) bounds.right; } //注:这边事先获取item的位置来判断是否要显示在屏幕上后再来获取itemView的对象,所以itemView的位置信息由外部传进来 if (!mBooleanMap.get(i) && RectF.intersects(bounds, mLayoutState.containerRect)) { // 通过recycler得到该位置上的View,Recycler负责是否使用旧的还是生成新的View。 View view = recycler.getViewForPosition(i); bounds.offset(mLayoutState.offsetX, mLayoutState.offsetY); // 然后我们将得到的View添加到Recycler中 addView(view); //标志当前item已在界面上 mBooleanMap.set(i); // 然后测量View带Margin的的尺寸 measureChildWithMargins(view, 0, 0); // 然后layout带Margin的View,将View放置到对应的位置 layoutDecoratedWithMargins(view, (int) bounds.left, (int) bounds.top, (int) bounds.right, (int) bounds.bottom); } //预留右边50的边界,左边50的边界已在item位置里 mTotalW += 50; } @Override public RecyclerView.LayoutParams generateDefaultLayoutParams() { return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); } //水平滑动开关 @Override public boolean canScrollHorizontally() { return true; } @Override public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {// //实际要滑动的距离 int travel = dx; //判断是否到边界 //如果滑动到最左边 if (-mLayoutState.offsetX + dx < 0) { travel = mLayoutState.offsetX; } else if (-mLayoutState.offsetX + dx + getWidth() > mTotalW) {//如果滑动到最右边 travel = mTotalW + mLayoutState.offsetX - getWidth(); } //移动 offsetChildrenHorizontal(-travel); //记录当前移动距离,绘制界面时需要用到 mLayoutState.offsetX -= travel; //回收view的Recycle scrapOutSetViews(recycler); //重新绘制界面:在滑动过程中需要将新进入屏幕的view设置出来 fill(recycler, state); return travel; } private void scrapOutSetViews(RecyclerView.Recycler recycler) { int count = getChildCount(); for (int i = count - 1; i >= 0; i--) { View view = getChildAt(i); if (!RectF.intersects(new RectF(0, 0, getWidth(), getHeight()), new RectF(view.getLeft(), view.getTop(), view.getRight(), view.getBottom()))) { int position = getPosition(view); mBooleanMap.clear(position); removeAndRecycleViewAt(i, recycler); } } } //更新父控件窗口位置 private void updateLayoutState() { mLayoutState.containerRect.set(0, 0, getWidth(), getHeight()); mLayoutState.containerRect.offset(-mLayoutState.offsetX, -mLayoutState.offsetY); } private class LayoutState { int offsetX; int offsetY; final RectF containerRect = new RectF(); }}
注释在代码中已经写得很清楚了,这里采用的是横向滑动,当然也可以通过重写canScrollVertically和scrollVerticallyBy来实现垂直方向的滑动。
最后捧上git地址:https://github.com/jackliy/CusLayoutManager
阅读全文
0 0
- “傻瓜”式填充,自定义LayoutManager
- 自定义LayoutManager
- LayoutManager自定义
- android RecyclerView自定义 LayoutManager
- Recyclerview-自定义LayoutManager
- 【Android】掌握自定义LayoutManager(二) 实现流式布局
- Android 掌握自定义LayoutManager(二) 实现流式布局
- 掌握自定义LayoutManager之实现流式布局
- RecylerView 自定义 LayoutManager 基础一
- RecylerView 自定义 LayoutManager 基础二
- LayoutManager
- RecyclerView自定义LayoutManager,打造不规则布局
- 自定义LayoutManager的详解及其使用
- RecyclerView——实现自定义LayoutManager
- RecyclerView自定义LayoutManager实现横向瀑布流
- 自定义LayoutManager带你撸个LinearLayoutManager
- RecyclerView自定义LayoutManager,打造不规则布局
- RecyclerView系列(7)—自定义LayoutManager
- tensorflow实现图像色彩的调整
- 1727: Dungeon Master
- android 几个常见过时解决办法
- MySQL查询数据表中表字段及其注释
- opencv中的harris角点检测函数
- “傻瓜”式填充,自定义LayoutManager
- 《UNIX网络编程 卷1》 笔记: TCP 客户/服务器程序示例
- 『ORACLE』 对永久表空间进行DDL操作(11g)
- 《数据结构实战》模拟文件系统目录组织------树的应用
- 原生Hibernate和Jpa Hibernate
- HDU 1111 Piggy-Bank(完全背包例题)
- Python笔记(6)----列表、元组、字符串、字典等的相关用法
- 方法的调用-----求一个质数
- java高精度数字