【Android】掌握自定义LayoutManager(二) 实现流式布局

本文详细介绍了如何在Android中自定义LayoutManager以实现流式布局。通过分析和实现关键方法,包括填充子View、处理滑动方向和边界条件,展示了流式布局的工作原理。代码示例展示了如何在不考虑滑动位移的情况下布局所有可见的子View,然后逐步添加滑动逻辑,使其能够响应用户的上下滑动操作。
摘要由CSDN通过智能技术生成

mFirstVisiPos = 0;

mLastVisiPos = getItemCount();

//初始化时调用 填充childView

fill(recycler, state);

}

这个fill(recycler, state);方法将是你自定义LayoutManager之旅一生的敌人,简单的说它承担了以下任务:

在考虑滑动位移的情况下:

1 回收所有屏幕不可见的子View

2 layout所有可见的子View

在这一节,我们先看一下它的简单版本,不考虑滑动位移,不考虑滑动方向等,只考虑初始化时,从头至尾,layout所有可见的子View,在下一节我会配合滑动事件放出它的完整版.

int topOffset = getPaddingTop();//布局时的上偏移

int leftOffset = getPaddingLeft();//布局时的左偏移

int lineMaxHeight = 0;//每一行最大的高度

int minPos = mFirstVisiPos;//初始化时,我们不清楚究竟要layout多少个子View,所以就假设从0~itemcount-1

mLastVisiPos = getItemCount() - 1;

//顺序addChildView

for (int i = minPos; i <= mLastVisiPos; i++) {

//找recycler要一个childItemView,我们不管它是从scrap里取,还是从RecyclerViewPool里取,亦或是onCreateViewHolder里拿。

View child = recycler.getViewForPosition(i);

addView(child);

measureChildWithMargins(child, 0, 0);

//计算宽度 包括margin

if (leftOffset + getDecoratedMeasurementHorizontal(child) <= getHorizontalSpace()) {//当前行还排列的下

layoutDecoratedWithMargins(child, leftOffset, topOffset, leftOffset + getDecoratedMeasurementHorizontal(child), topOffset + getDecoratedMeasurementVertical(child));

//改变 left lineHeight

leftOffset += getDecoratedMeasurementHorizontal(child);

lineMaxHeight = Math.max(lineMaxHeight, getDecoratedMeasurementVertical(child));

} else {//当前行排列不下

//改变top left lineHeight

leftOffset = getPaddingLeft();

topOffset += lineMaxHeight;

lineMaxHeight = 0;

//新起一行的时候要判断一下边界

if (topOffset - dy > getHeight() - getPaddingBottom()) {

//越界了 就回收

removeAndRecycleView(child, recycler);

mLastVisiPos = i - 1;

} else {

layoutDecoratedWithMargins(child, leftOffset, topOffset, leftOffset + getDecoratedMeasurementHorizontal(child), topOffset + getDecoratedMeasurementVertical(child));

//改变 left lineHeight

leftOffset += getDecoratedMeasurementHorizontal(child);

lineMaxHeight = Math.max(lineMaxHeight, getDecoratedMeasurementVertical(child));

}

}

}

用到的一些工具函数(在系列开篇已介绍过):

//模仿LLM Horizontal 源码

/**

  • 获取某个childView在水平方向所占的空间

  • @param view

  • @return

*/

public int getDecoratedMeasurementHorizontal(View view) {

final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)

view.getLayoutParams();

return getDecoratedMeasuredWidth(view) + params.leftMargin

  • params.rightMargin;

}

/**

  • 获取某个childView在竖直方向所占的空间

  • @param view

  • @return

*/

public int getDecoratedMeasurementVertical(View view) {

final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)

view.getLayoutParams();

return getDecoratedMeasuredHeight(view) + params.topMargin

  • params.bottomMargin;

}

public int getVerticalSpace() {

return getHeight() - getPaddingTop() - getPaddingBottom();

}

public int getHorizontalSpace() {

return getWidth() - getPaddingLeft() - getPaddingRight();

}

如上编写一个超级简单的fill()方法,运行,你的程序应该就能看到流式布局的效果出现了。

可是千万别开心,因为痛苦的计算远没到来。

如果这些都看不懂,那么我建议:

一,直接下载完整代码,配合后面的章节看,看到后面也许前面的就好理解了= =。

二,去学习一下自定义ViewGroup的知识。

此时虽然界面上已经展示了流式布局的效果,可是它并不能滑动,下一节我们让它动起来。

四,动起来

=====

想让我们自定义的LayoutManager动起来,最简单的写法如下:

@Override

public boolean canScrollVertically() {

return true;

}

@Override

public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {

i

  • 8
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值