Android流式布局

来源:互联网 发布:怎么安装photoshop软件 编辑:程序博客网 时间:2024/06/05 06:21

看了慕课网上hyman老师的讲解,现在将自己写的代码记录一下
hyman老师的视频地址http://www.imooc.com/learn/237

解释全部在代码里面啦

package com.example.flowlayout;import android.content.Context;import android.util.AttributeSet;import android.view.View;import android.view.ViewGroup;import java.util.ArrayList;import java.util.List;/** * Created by libingyuan on 2016/12/9. * <p> * 模式: * AT_MOST==wrap_content * EXACTILY=match_parent,100dp * ... */public class FlowLayout extends ViewGroup {    //存储行的View的位置    private List<List<View>> mAllView = new ArrayList<>();    //每一行的高度    private List<Integer> mLineHeight = new ArrayList<>();    /*    使用new关键字创建的时候调用     */    public FlowLayout(Context context) {        this(context, null);    }    /*    在xml中调用的时候会调用这个方法     */    public FlowLayout(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    /*    在xml中有自定义属性的时候会调用     */    public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        //测量父布局的大小和模式        int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);        int modeWidth = MeasureSpec.getMode(widthMeasureSpec);        int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);        int modeHeight = MeasureSpec.getMode(heightMeasureSpec);        /**         * 当父控件为match_parent或精确值的时候sizeWidth等是固定的,         * 但是是wrap_content的时候就需要重新动态测量宽高         */        //父控件的宽高(wrap_content的时候)        int width = 0;        int height = 0;        //每一行的宽高(wrap_content的时候)        int lineWidth = 0;        int lineHeight = 0;        //所有子View的个数        int childCount = getChildCount();        //循环这些子View        for (int i = 0; i < childCount; i++) {            //得到其中的一个子View            View child = getChildAt(i);            //测量子View的宽和高            measureChild(child, widthMeasureSpec, heightMeasureSpec);            //得到子View的layoutParams            MarginLayoutParams lp = (MarginLayoutParams) child.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;                //高度累加                height += lineHeight;                //重置行高                lineHeight = childHeight;            } else {//未换行                //叠加行宽                lineWidth += childWidth;                //得到这一行的最大高度                lineHeight = Math.max(lineHeight, childHeight);            }            //最后一个控件            if (i == childCount - 1) {                width = Math.max(width, lineWidth);                height += lineHeight;            }        }        //设置父控件的宽高        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) {        mAllView.clear();        mLineHeight.clear();        //每一行的宽高        int lineWidth = 0;        int lineHeight = 0;        //存储这行所有的子view        List<View> lineView = new ArrayList<>();        //得到viewgroup的宽度        int width = getWidth();        //得到子View的个数        int cCount = getChildCount();        //循环子View        for (int i = 0; i < cCount; i++) {            //得到每一个字View            View child = getChildAt(i);            //得到子View的margin            MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();           //子View 的宽度            int childWidth = child.getMeasuredWidth();            //子View 的高度            int childHeight = child.getMeasuredHeight();            //如果需要换行(这是个for循环的出口,            // 只有符合if条件,也就是换行的时候才会添加总的list以及重置)            if (childWidth + lineWidth + lp.leftMargin + lp.rightMargin > width) {                //记录当前行的高度                mLineHeight.add(lineHeight);                //添加当前行所有的View                mAllView.add(lineView);                //重置行宽和行高                lineWidth = 0;                lineHeight = childHeight + lp.topMargin + lp.bottomMargin;                //重置这一行的list                lineView = new ArrayList<>();            }            //计算行宽(累加)            lineWidth += childWidth + lp.leftMargin + lp.rightMargin;            //得到行高(最大)            lineHeight = Math.max(lineHeight, childHeight + lp.topMargin + lp.bottomMargin);            //添加进list            lineView.add(child);        }        //处理最后一行(for循环的if里面没办法加载最后一行,这里特殊处理)        mLineHeight.add(lineHeight);        mAllView.add(lineView);        /**         * 下面开始为每个子View设置位置,主要是想办法计算子View的left top rigth bottom,         * 然后调用子View 的layout方法即可         */        //行的高度(换成lineheight应该更容易理解,不过已经存在啦,所以用了left)        int top = 0;        //行的宽度(同上)        int left = 0;        //有多少行        int lineNum = mAllView.size();        //循环设置每一行        for (int i = 0; i < lineNum; i++) {            //得到这一行所有的子view集合            lineView = mAllView.get(i);            //得到这一行所有子View的高度集合            lineHeight = mLineHeight.get(i);            //循环子View集合得到每一个子View            for (int j = 0; j < lineView.size(); j++) {                //得到每一个子View                View child = lineView.get(j);                //判断子View 是否隐藏,是,则不处理(注意:gone不占空间,所以不处理,INVISIBLE不可见但是占空间,不能跳过)                if (child.getVisibility() == View.GONE) {                    continue;                }                //得到子View 的margin                MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();                //分别计算子View 的四个值                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)            left = 0;            //行高(top)叠加            top += lineHeight;        }    }    //设置子View的Layoutparams是什么类型    @Override    public LayoutParams generateLayoutParams(AttributeSet attrs) {        return new MarginLayoutParams(getContext(), attrs);    }}

用法直接把它当作一个LinearLayout或其他的布局用就行啦

0 0
原创粉丝点击