Android(安卓)流式布局
16lz
2021-01-26
后附源码地址
思路:
1、自定义View;
2、由于这个View是要包含其他控件,所以继承ViewGroup;
3、设置这个自定义View的LayoutParams,重写generateLayoutParams,这里设置的是MarginLayoutParams;
4、重写OnMeasure,计算该容器的大小和子元素的大小
5、重写OnLayout,设置子控件的位置
这里需要注意:该空间的模式
**warp_content: MeasureSpec.AT_MOST 需要根据子布局的大小设置该控件的大小。
fill_parent和mach_parent:MeasureSpec.EXACTLY 直接使用获取大小即可**
int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
FlowView.java
package com.ucloud.oxpecker.views;import java.util.ArrayList;import java.util.List;import android.content.Context;import android.util.AttributeSet;import android.view.View;import android.view.ViewGroup;public class FlowView extends ViewGroup { public FlowView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public FlowView(Context context, AttributeSet attrs) { super(context, attrs); } public FlowView(Context context) { super(context); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int sizeWidth = MeasureSpec.getSize(widthMeasureSpec); int sizeHeight = MeasureSpec.getSize(heightMeasureSpec); int modeWidth = MeasureSpec.getMode(widthMeasureSpec); int modeHeight = MeasureSpec.getMode(heightMeasureSpec); // warp_content int width = 0, height = 0, lineWidth = 0, lineHeight = 0; for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); measureChild(child, widthMeasureSpec, heightMeasureSpec); MarginLayoutParams params = (MarginLayoutParams) child .getLayoutParams(); int childWidth = child.getMeasuredWidth() + params.leftMargin + params.rightMargin; int childHeight = child.getMeasuredHeight() + params.topMargin + params.bottomMargin; if (childWidth + lineWidth > sizeWidth - getPaddingLeft() - getPaddingRight()) { // 对比得到最大宽度 width = Math.max(lineWidth, width); // 重置lineWidth lineWidth = childWidth; // 记录行高 height += lineHeight; lineHeight = childHeight; } else { lineWidth += childWidth; lineHeight = Math.max(lineHeight, childHeight); } if (i == getChildCount() - 1) { width = Math.max(lineWidth, width); height += lineHeight; } } setMeasuredDimension(modeWidth == MeasureSpec.EXACTLY ? sizeWidth : width + getPaddingLeft() + getPaddingRight(), modeHeight == MeasureSpec.EXACTLY ? sizeHeight : height + getPaddingTop() + getPaddingBottom()); } private List> mAllViews = new ArrayList>(); // 每一行的高度 private List mLineHeight = new ArrayList(); // 每一行距离左边的距离 private List mLineMarginLeft = new ArrayList(); @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { mAllViews.clear(); mLineHeight.clear(); int width = getMeasuredWidth(); int lineWidth = 0, lineHeight = 0; List lineViews = new ArrayList(); for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); MarginLayoutParams params = (MarginLayoutParams) child .getLayoutParams(); int childWidth = child.getMeasuredWidth() + params.leftMargin + params.rightMargin; int childHeight = child.getMeasuredHeight() + params.topMargin + params.bottomMargin; if (childWidth + lineWidth > width - getPaddingLeft() - getPaddingRight()) { // 计算每行距离左边距离 int lineLeftMargin = (width - lineWidth) / 2; mLineMarginLeft.add(lineLeftMargin); // 行高 mLineHeight.add(lineHeight); mAllViews.add(lineViews); lineWidth = 0; lineHeight = childHeight; lineViews = new ArrayList(); } lineWidth += childWidth; lineHeight = Math.max(lineHeight, childHeight); lineViews.add(child); } /** 处理最后一行 **/ // 计算每行距离左边距离 int lineLeftMargin = (width - lineWidth) / 2; mLineMarginLeft.add(lineLeftMargin); // 行高 mLineHeight.add(lineHeight); mAllViews.add(lineViews); /** 设置子View的位置 **/ int left = getPaddingLeft(), top = getPaddingTop(); for (int i = 0; i < mAllViews.size(); i++) { lineViews = mAllViews.get(i); lineHeight = mLineHeight.get(i); // 居中显示的左边距 left += mLineMarginLeft.get(i); for (int j = 0; j < lineViews.size(); j++) { View child = lineViews.get(j); if (child.getVisibility() == View.GONE) continue; MarginLayoutParams params = (MarginLayoutParams) child .getLayoutParams(); int lc = left + params.leftMargin; int tc = top + params.topMargin; int rc = lc + child.getMeasuredWidth(); int bc = tc + child.getMeasuredHeight(); child.layout(lc, tc, rc, bc); left += child.getMeasuredWidth() + params.leftMargin + params.rightMargin; } left = getPaddingLeft(); top += lineHeight; } } @Override public LayoutParams generateLayoutParams(AttributeSet attrs) { return new MarginLayoutParams(getContext(), attrs); }}
调用方式
FlowView flowViewRecive = (FlowView) findViewById(R.id.flowView_recive);flowView.removeAllViews();AttrTextView tv = new AttrTextView(this);MarginLayoutParams lp = new MarginLayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);tv.setText("测试");lp.leftMargin = 10;lp.rightMargin = 10;lp.topMargin = 5;lp.bottomMargin = 5;tv.setBackgroundResource(R.drawable.shape_tv_email);tv.setTextColor(getResources().getColor(R.color.black));flowView.addView(tv, lp);
源码下载
更多相关文章
- Android(安卓)Studio无法运行模拟器或者真机的问题
- Android——SlidingMenu学习总结
- Android(安卓)View初始化基本流程
- Android仿微信底部菜单
- Android中DialogFragment的简单使用及常见问题
- android TextView空间的setTextSize()方法在真机上运行大小问题
- Android(安卓)界面适配笔记
- Android(安卓)开发学习进程0.15 adb cardview framelayout 控件
- android notification的用法