自定义view流式布局FlowLayout

2022-04-02  本文已影响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>
上一篇 下一篇

猜你喜欢

热点阅读