美文网首页
自定义view流式布局FlowLayout

自定义view流式布局FlowLayout

作者: 冰楓紫憶 | 来源:发表于2022-04-02 17:38 被阅读0次

    效果图:


    image.png
    package com.zsw.mycustomviewlearn.customview;
    
    import android.content.Context;
    import android.util.AttributeSet;
    import android.view.View;
    import android.view.ViewGroup;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * @author zsw
     * @date 2022/4/2
     * @desc
     */
    public class FlowLayout extends ViewGroup {
        private List<List<View>> allViewList = new ArrayList<>();
        private List<Integer> mLineMaxHeight = new ArrayList<>();
    
        public FlowLayout(Context context) {
            super(context);
        }
    
        public FlowLayout(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    
        @Override
        protected LayoutParams generateLayoutParams(LayoutParams p) {
            super.generateLayoutParams(p);
            return new MarginLayoutParams(p);
        }
    
        @Override
        public LayoutParams generateLayoutParams(AttributeSet attrs) {
            return new MarginLayoutParams(getContext(), attrs);
        }
    
        @Override
        protected LayoutParams generateDefaultLayoutParams() {
            return new MarginLayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
        }
    
        /**
         * 摆放控件 子控件排布
         *
         * @param b  表示该ViewGroup的大小或者位置是否发生变化
         *           以下参数控件的位置
         * @param i
         * @param i1
         * @param i2
         * @param i3
         */
        @Override
        protected void onLayout(boolean b, int i, int i1, int i2, int i3) {
            allViewList.clear();
            mLineMaxHeight.clear();
            //每一行View的集合
            List<View> lineViewList = new ArrayList<>();
            //子View的个数
            int childCount = getChildCount();
            //记录每一行的宽度
            int lineWidth = 0;
            //记录每一行子View最高的高度
            int maxLineHeight = 0;
            /*************遍历所有View,将View添加到List<List<View>>集合中***************/
            for (int j = 0; j < childCount; j++) {
                View childView = getChildAt(j);
                MarginLayoutParams lp = (MarginLayoutParams) childView.getLayoutParams();
                int childWidth = lp.leftMargin + childView.getMeasuredWidth() + lp.rightMargin;
                int childHeight = lp.topMargin + childView.getMeasuredHeight() + lp.bottomMargin;
    
                //如果当前这行的已用宽度+这个子view的宽度 大于 父view的宽度那说明折行放不下了需要另外起一行
                if (lineWidth + childWidth > getWidth()) {
                    //把这一行的View和高信息加入到集合中
                    allViewList.add(lineViewList);
                    mLineMaxHeight.add(maxLineHeight);
                    //另起一行
                    lineWidth = 0;
                    maxLineHeight = 0;
                    lineViewList = new ArrayList<>();
                }
                lineWidth += childWidth;
                lineViewList.add(childView);
                maxLineHeight = Math.max(maxLineHeight, childHeight);
    
                //单独处理最后一行
                if (j == childCount - 1) {
                    allViewList.add(lineViewList);
                    mLineMaxHeight.add(maxLineHeight);
                }
    
            }
            /************遍历集合中的所有View并显示出来*****************/
            //表示一个view距离父容器的左边距
            int mLeft = 0;
            //表示一个view距离父容器的上边距
            int mTop = 0;
            for (int j = 0; j < allViewList.size(); j++) {
                List<View> lineViews = allViewList.get(j);
                int lineHeight = mLineMaxHeight.get(j);
    
                for (int k = 0; k < lineViews.size(); k++) {
    
                    View childView = lineViews.get(k);
                    MarginLayoutParams mlp = (MarginLayoutParams) childView.getLayoutParams();
                    int childLeft = mLeft + mlp.leftMargin;
                    int childTop = mTop + mlp.topMargin;
                    int childRight = childLeft + childView.getMeasuredWidth();
                    int childBottom = childTop + childView.getMeasuredHeight();
                    //四个参数分别表示View的左上角和右下角 每个子View放在对应的位置
                    childView.layout(childLeft, childTop, childRight, childBottom);
                    mLeft += mlp.leftMargin + childView.getMeasuredWidth() + mlp.rightMargin;
                }
                mLeft = 0;
                mTop += lineHeight;
            }
    
        }
    
        /**
         * 测量大小
         *
         * @param widthMeasureSpec
         * @param heightMeasureSpec
         */
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            //获得宽高的测量模式和测量值
            int widthMode = MeasureSpec.getMode(widthMeasureSpec);
            int widthSize = MeasureSpec.getSize(widthMeasureSpec);
            int heightMode = MeasureSpec.getMode(heightMeasureSpec);
            int heightSize = MeasureSpec.getSize(heightMeasureSpec);
    
            //获得容器中子View的个数
            int childCount = getChildCount();
            //记录每一行View的总宽度
            int lineWidth = 0;
            //记录每一行最高View的高度
            int lineHeightMax = 0;
            //记录当前ViewGroup的总高度
            int totalHeight = 0;
    
            //对子View进行测量
            for (int i = 0; i < childCount; i++) {
                //获得子view
                View childView = getChildAt(i);
                //测量子View
                measureChild(childView, widthMeasureSpec, heightMeasureSpec);
                //获取子View margin信息
                MarginLayoutParams lp = (MarginLayoutParams) childView.getLayoutParams();
                //获得子View的测量宽度
                int childWidth = childView.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
                //获得子View的测量高度
                int childHeight = childView.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
    
                //如果当前这行的已用宽度+这个子view的宽度 大于 父view的宽度那说明折行放不下了需要另外起一行
                if (lineWidth + childWidth > widthSize) {
                    //统计总高度
                    totalHeight += lineHeightMax;
                    //开启新的一行
                    lineWidth = childWidth;
                    //新的一行的高度
                    lineHeightMax = childHeight;
                } else {
                    //记录每一行的总宽度
                    lineWidth += childWidth;
                    //比较每一行最高的View
                    lineHeightMax = Math.max(lineHeightMax, childHeight);
                }
                //当该View已是最后一个View时,将该行最大高度添加到totalHeight中
                // (因为上面的代码如果是最后一个时并没有加上这一行的高度) 只有lineHeightMax 赋值,并没有统计到totalHeight
                if (i == childCount - 1) {
                    totalHeight += lineHeightMax;
                }
            }
            //如果高度的测量模式是EXACTLY,则高度用测量值,否则用计算出来的总高度(这时高度的设置为wrap_content)
            int realHeightSize = 0;
            //EXACTLY 表示在 XML 布局文件中宽高使用 match_parent 或者固定大小的宽高;表示使用固定值,否则wrap_content
            if (heightMode == MeasureSpec.EXACTLY) {
                //使用固定值
                realHeightSize = heightSize;
            } else {
                //使用计算出来的值
                realHeightSize = totalHeight;
            }
            //设置当前view的大小
            setMeasuredDimension(widthSize, realHeightSize);
        }
    }
    
    

    使用方式一

    <com.zsw.mycustomviewlearn.customview.FlowLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="150dp"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            android:background="#00ff00">
    
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginRight="10dp"
                android:layout_marginBottom="10dp"
                android:background="#ff4000"
                android:text="aaaaaaaaaa" />
    
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginRight="10dp"
                android:layout_marginBottom="10dp"
                android:background="#ff4000"
                android:text="bbbbbbb" />
    
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginRight="10dp"
                android:layout_marginBottom="10dp"
                android:background="#ff4000"
                android:text="CCCCCCCCC" />
    
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginRight="10dp"
                android:layout_marginBottom="10dp"
                android:background="#ff4000"
                android:text="rrrrrrrr" />
    
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginRight="10dp"
                android:layout_marginBottom="10dp"
                android:background="#ff4000"
                android:text="eeee" />
    
    
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginRight="10dp"
                android:layout_marginBottom="10dp"
                android:background="#ff4000"
                android:text="vvvvvvv" />
    
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginRight="10dp"
                android:layout_marginBottom="10dp"
                android:background="#ff4000"
                android:text="ttt" />
    
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginRight="10dp"
                android:layout_marginBottom="10dp"
                android:background="#ff4000"
                android:text="666666666666" />
    
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginRight="10dp"
                android:layout_marginBottom="10dp"
                android:background="#ff4000"
                android:text="uuuuuuuuuu" />
    
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginRight="10dp"
                android:layout_marginBottom="10dp"
                android:background="#ff4000"
                android:text="qqqqqqqqqq" />
    
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginRight="10dp"
                android:layout_marginBottom="10dp"
                android:background="#ff4000"
                android:text="eeeeeeeeeeee" />
    
    
        </com.zsw.mycustomviewlearn.customview.FlowLayout>
    

    使用方式二:

    xml中:
    <com.zsw.mycustomviewlearn.customview.FlowLayout
            android:id="@+id/flowLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" >
    
    activity中:
            flowLayout = findViewById(R.id.flowLayout);
            List<String> stringList = new ArrayList<>();
            stringList.add("盘发发簪");
            stringList.add("茶歇连衣裙");
            stringList.add("亲子装");
            stringList.add("情侣对戒");
            stringList.add("气泡");
            stringList.add("旗袍");
            stringList.add("泡泡机");
            stringList.add("蘑菇屋");
            bindDataView(stringList);
    
    public void bindDataView(List<String> strings) {
            if (flowLayout == null) return;
            flowLayout.removeAllViews();
            for (int i = 0; i < strings.size(); i++) {
                View view = createSingleView(strings.get(i));
                flowLayout.addView(view);
            }
        }
    
        private View createSingleView(String text) {
            View view = LayoutInflater.from(this).inflate(R.layout.item_flow, flowLayout, false);
            TextView textView = view.findViewById(R.id.tv_content);
            textView.setText(text);
            view.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Toast.makeText(MainActivity.this, text, Toast.LENGTH_SHORT).show();
                }
            });
            return view;
        }
    

    item_flow.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="horizontal"
        android:layout_width="wrap_content"
        android:layout_height="30dp"
        android:background="@drawable/bg_item_flow"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="5dp"
        android:layout_marginBottom="10dp"
        android:gravity="center_vertical">
    
        <TextView
            android:id="@+id/tv_content"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="优惠券"
            android:textColor="#333333"
            android:textSize="14dp"
            android:layout_marginLeft="4dp"
            android:layout_marginRight="10dp"/>
    
        <ImageView
            android:layout_width="22dp"
            android:layout_height="22dp"
            android:layout_marginLeft="10dp"
            android:src="@drawable/xiaolian"/>
    </LinearLayout>
    

    相关文章

      网友评论

          本文标题:自定义view流式布局FlowLayout

          本文链接:https://www.haomeiwen.com/subject/ozotsrtx.html