热门标签之流式布局

来源:互联网 发布:python update mysql 编辑:程序博客网 时间:2024/05/01 18:44

说到流式布局第一时间想起的就是RecyclerView,但是在很多很多种情况下,并不适用于用它。因为RecyclerView是一个带滚动的view,而当我们需要多个RecyclerView在一个界面上拼接一起滑动的时候,也就是说可能会遇到ScrollView嵌套RecyclerView的情况下,这个时候无论是改写RecyclerView的LayoutParams还是重写RecyclervView的滑动事件都不是一个好主意,因为RecyclerView是一个布局复用的控件,改写了这些东西意味着你将不能再使用复用模式而导致内耗加大,当item不可见时,内存不会回收,从而造成OOM的风险。
所以使用新的方式替代RecyclerView是我们目前唯一的选择,新的选择和RecyclerView的最大区别在于是否有滑动事件,也就是说,它不是一个AbsListView,也没有滑动事件。它是一个ViewGroup,这个GroupView像LinearLayout、RadioGroup一样是一个可以装载子控件的布局集合,我们可以通过动态的添加子控件方式,进行界面效果的实现。
第一步,自定义View,继承ViewGroup,重写onMeasure()方法,动态的适配子控件的宽高从而达到流式布局的效果。

public class FlowLayout extends ViewGroup {    private float mVerticalSpacing; //每个item纵向间距    private float mHorizontalSpacing; //每个item横向间距    private int mMinimumWidth = 0;    private FlowLayoutAdapter mAdapter;    public FlowLayout(Context context) {        super(context);        this.mMinimumWidth = (ConstantsUtils.DISPLAYW - 100) / 2;    }    public FlowLayout(Context context, AttributeSet attrs) {        super(context, attrs);        this.mMinimumWidth = (ConstantsUtils.DISPLAYW - 100) / 2;    }    public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        this.mMinimumWidth = (ConstantsUtils.DISPLAYW - 100) / 2;    }    public void setHorizontalSpacing(float pixelSize) {        mHorizontalSpacing = pixelSize;    }    public void setVerticalSpacing(float pixelSize) {        mVerticalSpacing = pixelSize;    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        int selfWidth = resolveSize(0, widthMeasureSpec);        int paddingLeft = getPaddingLeft();        int paddingTop = getPaddingTop();        int paddingRight = getPaddingRight();        int paddingBottom = getPaddingBottom();        int childLeft = paddingLeft;        int childTop = paddingTop;        int lineHeight = 0;        //通过计算每一个子控件的高度,得到自己的高度        for (int i = 0, childCount = getChildCount(); i < childCount; ++i) {            View childView = getChildAt(i);            childView.setMinimumWidth(mMinimumWidth);            LayoutParams childLayoutParams = childView.getLayoutParams();            childView.measure(                    getChildMeasureSpec(widthMeasureSpec, paddingLeft + paddingRight,                            childLayoutParams.width),                    getChildMeasureSpec(heightMeasureSpec, paddingTop + paddingBottom,                            childLayoutParams.height));            int childWidth = childView.getMeasuredWidth();            int childHeight = childView.getMeasuredHeight();            // 如果子控件有需要设置最小宽度的可以在此重设            if (childWidth < mMinimumWidth){                childView.setMinimumWidth(mMinimumWidth);            }            lineHeight = Math.max(childHeight, lineHeight);            if (childLeft + childWidth + paddingRight > selfWidth) {                childLeft = paddingLeft;                childTop += mVerticalSpacing + lineHeight;                lineHeight = childHeight;            } else {                childLeft += childWidth + mHorizontalSpacing;            }        }        int wantedHeight = childTop + lineHeight + paddingBottom;        setMeasuredDimension(selfWidth, resolveSize(wantedHeight, heightMeasureSpec));    }    @Override    protected void onLayout(boolean changed, int l, int t, int r, int b) {        int myWidth = r - l;        int paddingLeft = getPaddingLeft();        int paddingTop = getPaddingTop();        int paddingRight = getPaddingRight();        int childLeft = paddingLeft;        int childTop = paddingTop;        int lineHeight = 0;        //根据子控件的宽高,计算子控件应该出现的位置。        for (int i = 0, childCount = getChildCount(); i < childCount; ++i) {            View childView = getChildAt(i);            if (childView.getVisibility() == View.GONE) {                continue;            }            int childWidth = childView.getMeasuredWidth();            int childHeight = childView.getMeasuredHeight();            lineHeight = Math.max(childHeight, lineHeight);            if (childLeft + childWidth + paddingRight > myWidth) {                childLeft = paddingLeft;                childTop += mVerticalSpacing + lineHeight;                lineHeight = childHeight;            }            childView.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);            childLeft += childWidth + mHorizontalSpacing;        }    }    public void setAdapter(FlowLayoutAdapter adapter){        this.mAdapter = adapter;        mAdapter.init();    }    // 数据适配器    public interface FlowLayoutAdapter{        /** 初始化布局,可在此方法内动态添加控件*/        void init();        /** 刷新布局*/        void refresh();        /** 设置动作事件的刷新回调*/        void setChoosed(String name,String value);    }}

第二步,布局文件中写入ScrollView,内包含一个子控件LinearLayout,并在java代码中动态添加FlowLayout控件。

第三步,重写FlowLayout的监听器,并进行监听调用

0 0
原创粉丝点击