自定义viewGroup实现流式布局

95 篇文章 0 订阅

在很多商城我们会看到如下效果

//有些小伙伴可能对view和viewgroup有点傻傻分不清,简单说下,ViewGroup是用来装载view的容器,他也是继承view;view是可视化控件;比如我们系统的容器控件 LinearLayout就是继承viewGroup;TextView就是继承TextView;

-------------------------------------------------------------------------------分析实现逻辑-------------------------------------------------------

仔细观察 这个流式布局,就是对子控件如何摆放的问题,那每个view的摆放,需要知道他放的位置即view对应left top right bottom 四个参数就可以知道他摆放位置了。那我们如何知道呢,

通过上图我们可以把界面可以分成一行一行的,我们只需要知道每行的高,和每行view对象,就可以了,这些数据怎么获取呢?

我们可以重新onMeasure方法使用List<Integer>集合保存每行高,使用List<List<View>> listLineView 双层集合记录view

 

------------------------------------------------------------------------onMeasure代码------------------------------------------------------------------

   private boolean isFlag;

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        if (isFlag) {
            return;
        }

        isFlag = true;

        //获取自己的宽高
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);

        //保存测量信息 每行的view ,每行的高度
        saveMeasureInfo(widthMeasureSpec, heightMeasureSpec, widthSize);

    }

    private void saveMeasureInfo(int widthMeasureSpec, int heightMeasureSpec, int widthSize) {
        //当前view宽 高
        int iChildWidth = 0;
        int iChildHeight = 0;

        //当前行宽  行高 因为存在多行
        int iCurLineW = 0;
        int iCurLineH = 0;


        //获取子view数量用于 for循环
        int childCount = getChildCount();
        Log.e("zdh","-----------"+childCount);

        //单行信息容器
        List<View> viewList = new ArrayList<>();

        //for循环所有子view
        for (int i = 0; i < childCount; i++) {
            //获取子view
            View childAt = getChildAt(i);
            //测量自己
            measureChild(childAt, widthMeasureSpec, heightMeasureSpec);
            //获取布局参数--》xml资源:MarginLayoutParams 这个是xml中 margin参数信息
            MarginLayoutParams layoutParams = (MarginLayoutParams) childAt.getLayoutParams();

            //获取实际宽度和高度(比如view使用了margin属性--》实际宽=宽+margin左距离+margin右距离)
            iChildWidth = childAt.getMeasuredWidth() + layoutParams.leftMargin + layoutParams.rightMargin;
            iChildHeight = childAt.getMeasuredHeight() + layoutParams.topMargin + layoutParams.bottomMargin;

            //是否需要换行  iCurLineW是当前行遍历view的宽 的总和  加上现在遍历的view的宽 比父容器的宽大就需要换行了
            if (iCurLineW + iChildWidth > widthSize) {
//                    //记录当前行最大宽度,高度类加
//                    measureWidth=Math.max(measureWidth,iChildWidth);
//                    measureHeight+=iChildHeight;


                //首先是不换行的,所以执行换行
                //保存这行数据 和宽高
                listLineHeight.add(iCurLineH);
                listLineView.add(viewList);

                //记录新的行信息
                iCurLineW = iChildWidth;
                iCurLineH = iChildHeight;


                //添加新行记录
                viewList = new ArrayList<>();
                viewList.add(childAt);


            } else {
                //不换行情况 代码首先会执行这里面
                iCurLineW += iChildWidth;
                iCurLineH = Math.max(iCurLineH, iChildHeight);

                //添加到viewList里面
                viewList.add(childAt);

            }

            //最后一行需要换行
            if (i == childCount - 1) {
                listLineView.add(viewList);
                listLineHeight.add(iCurLineH);
            }


        }
    }

 

 

------------------------------------------------------------onLayout代码----------------------------------------------------------------------

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    //开始布局摆放
    int left, top, right, bottom;

    //记录当前顶部高 和左边高度
    int curTop = 0;
    int curLeft = 0;



    //开始迭代
    for (int i = 0; i < listLineView.size(); i++) {
        List<View> viewList = listLineView.get(i);
        //遍历 高集合
        for (int i1 = 0; i1 < viewList.size(); i1++) {
            View childView = viewList.get(i1);
            //获取margin 参数信息
            MarginLayoutParams layoutParams = (MarginLayoutParams) childView.getLayoutParams();


            left = curLeft + layoutParams.leftMargin;
            top = curTop + layoutParams.topMargin;

            right = left + childView.getMeasuredWidth();
            bottom = top + childView.getMeasuredHeight();

            //调用自身的layout进行布局
            childView.layout(left, top, right, bottom);

            //左边部分累加
            curLeft += childView.getMeasuredWidth() + layoutParams.leftMargin + layoutParams.rightMargin;


        }

        //换行置空左边标记
        curLeft = 0;
        //累加顶部
        curTop += listLineHeight.get(i);

    }

    //清空集合
    listLineView.clear();
    listLineHeight.clear();


}

 

------------------------------------------------------------注意获取view参数信息 需要重新下面方法----------------------------------

/**
 * 注意我们使用自定义view的margin参数数据 需要重新 generateLayoutParams方法获取布局参数
 */
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
    return new MarginLayoutParams(getContext(), attrs);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值