Android 实现自定义FlowLayout

来源:互联网 发布:恩尼格玛密码机 知乎 编辑:程序博客网 时间:2024/06/06 13:24

参考自 http://blog.csdn.net/lmj623565791/article/details/38352503/

自定义ViewGroup实现流式布局的效果,支持Margin

这里写图片描述

代码

public class FlowViewGroup extends ViewGroup {    private static final String TAG = "FlowViewGroup";    /*所有子View,按照行进行存储*/    private List<List<View>> mEachLineViews = new ArrayList<>();    /*每行的高度*/    private List<Integer> mLineHeight = new ArrayList<>();    public FlowViewGroup(Context context) {        this(context, null);    }    public FlowViewGroup(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public FlowViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    /*针对wrap_content的情况进行处理*/    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        // mode and size        int widthSize = MeasureSpec.getSize(widthMeasureSpec);        int heightSize = MeasureSpec.getSize(heightMeasureSpec);        int widthMode = MeasureSpec.getMode(widthMeasureSpec);        int heightMode = MeasureSpec.getMode(heightMeasureSpec);        // wrap_content时记录宽和高        int width = 0;        int height = 0;        int lineWidth = 0;   // 最长的width        int lineHeight = 0;  // 累加的Height        int childCount = getChildCount();        // 测量所有子View        for (int i = 0; i < childCount; i++) {            View child = getChildAt(i);            measureChild(child, widthMeasureSpec, heightMeasureSpec);            MarginLayoutParams params = (MarginLayoutParams) child.getLayoutParams();            int childWidth = params.leftMargin + params.rightMargin + child.getMeasuredWidth();            int childHeight = params.topMargin + params.bottomMargin + child.getMeasuredHeight();            // 加入当前View时,宽度超过ViewGroup的宽度时,进行换行            if (lineWidth + childWidth > widthSize) {                width = Math.max(lineWidth, childWidth);                lineHeight += childHeight;                lineWidth = 0;            } else {                // 没有换行时,lineWidth继续累加                lineWidth += childWidth;                lineHeight = Math.max(lineHeight, childHeight); // 最大高度            }            if (i == childCount - 1) { // 处理最后一个子View的情况                width = Math.max(width, lineWidth);                height += lineHeight;            }        }        setMeasuredDimension(widthMode == MeasureSpec.AT_MOST ? width : widthSize                , heightMode == MeasureSpec.AT_MOST ? height : heightSize);    }    /*对子View位置的摆放*/    @Override    protected void onLayout(boolean changed, int l, int t, int r, int b) {        /*计算每个ChildView的位置*/        mEachLineViews.clear();        mLineHeight.clear();        int width = getWidth();        int childCount = getChildCount();        int lineHeight = 0;        int lineWidth = 0;        List<View> lineViews = new ArrayList<>();        for (int i = 0; i < childCount; i++) {            View childView = getChildAt(i);            MarginLayoutParams params = (MarginLayoutParams) childView.getLayoutParams();            int childWidth = childView.getMeasuredWidth() + params.leftMargin + params.rightMargin;            int childHeight = childView.getMeasuredHeight() + params.topMargin + params.bottomMargin;            // 需要换行的情况            if (lineWidth + childWidth > width) {                mLineHeight.add(lineHeight);                mEachLineViews.add(lineViews);                lineWidth = 0;                lineHeight = 0;                lineViews = new ArrayList<>();            }            // 没有换行,进行累加            lineWidth += childWidth;            lineHeight = Math.max(lineHeight, childHeight);            lineViews.add(childView);        }        // 记录最后一行        mLineHeight.add(lineHeight);        mEachLineViews.add(lineViews);        /*对每个ChildView进行显示*/        int left = 0;        int top = 0;        int lineNums = mEachLineViews.size();        for (int i = 0; i < lineNums; i++) {            // 获取每一行所有的View            lineViews = mEachLineViews.get(i);            lineHeight = mLineHeight.get(i);            // 对当前行的所有View排列位置            for (View childView : lineViews) {                if (childView.getVisibility() == View.GONE) {                    continue;                }                MarginLayoutParams params = (MarginLayoutParams) childView.getLayoutParams();                // 确定位置                int lc = left + params.leftMargin; // left                int tc = top + params.topMargin;   // top                int rc = lc + childView.getMeasuredWidth(); // right                int bc = tc + childView.getMeasuredHeight(); // bottom                childView.layout(lc, tc, rc, bc);                left += childView.getMeasuredWidth() + params.leftMargin + params.rightMargin;            }            left = 0;            top += lineHeight;        }    }    /* 生成默认的LayoutParams */    @Override    public LayoutParams generateLayoutParams(AttributeSet attrs) {        return new MarginLayoutParams(getContext(), attrs);    }    @Override    protected LayoutParams generateLayoutParams(LayoutParams p) {        return new MarginLayoutParams(p);    }    @Override    protected LayoutParams generateDefaultLayoutParams() {        return new MarginLayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);    }}

测试的布局代码

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:id="@+id/activity_main"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:paddingBottom="@dimen/activity_vertical_margin"    android:paddingLeft="@dimen/activity_horizontal_margin"    android:paddingRight="@dimen/activity_horizontal_margin"    android:paddingTop="@dimen/activity_vertical_margin"    tools:context="cn.edu.hebust.customviewgroup.MainActivity">    <cn.edu.hebust.customviewgroup.FlowViewGroup        android:layout_width="match_parent"        android:background="#dddddd"        android:layout_height="match_parent">        <TextView            android:layout_width="50dp"            android:layout_height="wrap_content"            android:layout_margin="10dp"            android:text="Hello World" />        <View            android:layout_width="120dp"            android:layout_height="30dp"            android:layout_margin="10dp"            android:background="#dd4564" />        <View            android:layout_width="40dp"            android:layout_height="10dp"            android:layout_margin="10dp"            android:background="#d652" />        <View            android:layout_width="220dp"            android:layout_height="20dp"            android:layout_margin="10dp"            android:background="#dd641d" />        <View            android:layout_width="20dp"            android:layout_height="50dp"            android:layout_margin="10dp"            android:background="#dd23ee" />        <View            android:layout_width="220dp"            android:layout_height="70dp"            android:layout_margin="10dp"            android:background="#d4d564" />    </cn.edu.hebust.customviewgroup.FlowViewGroup></RelativeLayout>
1 0