自定义FlowLayout,android flowLayout实现(1)

public class XCFlowLayout extends ViewGroup {

// 存储所有子View

private List<List> mAllChildViews = new ArrayList<List>();

// 每一行的高度

private List mLineHeight = new ArrayList();

public XCFlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

}

public XCFlowLayout(Context context, AttributeSet attrs) {

this(context, attrs, 0);

}

public XCFlowLayout(Context context) {

this(context, null);

}

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

// TODO Auto-generated method stub

// 父控件传进来的宽度和高度以及对应的测量模式

int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);

int modeWidth = MeasureSpec.getMode(widthMeasureSpec);

int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);

int modeHeight = MeasureSpec.getMode(heightMeasureSpec);

// 如果当前ViewGroup的宽高为wrap_content的情况

int width = 0; // 自己测量的宽度

int height = 0; // 自己测量的高度

int lineWidth = 0;// 每一行的宽度

int lineHeight = 0; // 每一行的高度

int childCount = getChildCount();// 获取子view的个数

for (int i = 0; i < childCount; i++) {

View child = getChildAt(i);

// 测量子View的宽和高

measureChild(child, widthMeasureSpec, heightMeasureSpec);

// 得到LayoutParams

MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams();

// 得到子View占据的宽度

int childWidth = child.getMeasuredWidth() + lp.leftMargin

  • lp.rightMargin;

// 得到子View占据的高度

int childHeight = child.getMeasuredHeight() + lp.topMargin

  • lp.bottomMargin;

if (lineWidth + childWidth > sizeWidth) {// 需要进行换行

width = Math.max(width, lineWidth); // 得到最大宽度

lineWidth = childWidth; // 重置lineWidth

height += lineHeight; // 得到高度

lineHeight = childHeight;// 重置LineHeight

} else {// 不需要进行换行

lineWidth += childWidth;// 叠加行宽

lineHeight = Math.max(lineHeight, childHeight);

}

if (i == childCount - 1) {// 处理最后一个子View的情况

width = Math.max(width, lineWidth);

height += lineHeight;

}

}

// wrapcontent

setMeasuredDimension(modeWidth == MeasureSpec.EXACTLY ? sizeWidth

width, modeHeight == MeasureSpec.EXACTLY ? sizeHeight

height);

// super.onMeasure(widthMeasureSpec, heightMeasureSpec);

}

@Override

protected void onLayout(boolean changed, int l, int t, int r, int b) {

// TODO Auto-generated method stub

mAllChildViews.clear();

mLineHeight.clear();

int width = getWidth();// 获取当前ViewGroup宽度

int lineWidth = 0;

int lineHeight = 0;

List lineViews = new ArrayList();// 记录当前行的View

int childCount = getChildCount();

for (int i = 0; i < childCount; i++) {

View child = getChildAt(i);

MarginLayoutParams lp = (MarginLayoutParams) child

.getLayoutParams();

int childWidth = child.getMeasuredWidth();

int childHeight = child.getMeasuredHeight();

// 需要换行

if (lineWidth + childWidth + lp.leftMargin + lp.rightMargin > width) {

mLineHeight.add(lineHeight); // 记录lineHeight

mAllChildViews.add(lineViews); // 记录当前行的Views

// 重置 行的宽高

lineWidth = 0;

lineHeight = childHeight + lp.topMargin + lp.bottomMargin;

// 重置当前行的View集合;

lineViews = new ArrayList();

}

lineWidth += childWidth + lp.leftMargin + lp.rightMargin;

lineHeight = Math.max(lineHeight, childHeight + lp.topMargin

  • lp.bottomMargin);

lineViews.add(child);

}

// 处理最后一行

mLineHeight.add(lineHeight);

mAllChildViews.add(lineViews);

// 设置子View的位置

int left = 0;

int top = 0;

// 获取行数

int lineCount = mAllChildViews.size();

for (int i = 0; i < lineCount; i++) {

// 当前行的views和高度

lineViews = mAllChildViews.get(i);

lineHeight = mLineHeight.get(i);

for (int j = 0; j < lineViews.size(); j++) {

View child = lineViews.get(j);

// 判断是否显示

if (child.getVisibility() == View.GONE) {

continue;

}

MarginLayoutParams lp = (MarginLayoutParams) child

.getLayoutParams();

int cLeft = left + lp.leftMargin;

int cTop = top + lp.topMargin;

int cRight = cLeft + child.getMeasuredWidth();

int cBottom = cTop + child.getMeasuredHeight();

// 进行子View进行布局

child.layout(cLeft, cTop, cRight, cBottom);

left += child.getMeasuredWidth() + lp.leftMargin

  • lp.rightMargin;

}

left = 0;

top += lineHeight;

}

}

/**

  • 与当前ViewGroup对应的LayoutParams

*/

@Override

public LayoutParams generateLayoutParams(AttributeSet attrs) {

return new MarginLayoutParams(getContext(), attrs);

}

}

二.xml部分

结语

由于篇幅限制,文档的详解资料太全面,细节内容太多,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!以下是目录截图:

由于整个文档比较全面,内容比较多,篇幅不允许,下面以截图方式展示 。

再附一部分Android架构面试视频讲解:


《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

由于篇幅限制,文档的详解资料太全面,细节内容太多,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!以下是目录截图:

[外链图片转存中…(img-kPzUBizW-1715141292942)]

由于整个文档比较全面,内容比较多,篇幅不允许,下面以截图方式展示 。

再附一部分Android架构面试视频讲解:

[外链图片转存中…(img-CQ9dPciH-1715141292943)]
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值