安卓自定义流式布局

废话少说直接上代码,对自定义view有一定了解的同学想必都能看懂:

package com.example.text.view;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;

/**
 * <p></p >
 * <p></p >
 *  横向排列的布局
 * @author jinzhenhua
 * @version 1.0  ,create at:2019/11/28 20:33
 */
public class FlowLayout extends ViewGroup {
    private String TAG = FlowLayout.class.getSimpleName();


    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 void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        measureChildren(widthMeasureSpec,heightMeasureSpec);//测量所有小孩的宽高,否则取不到子控件的大小和边距等

        int paddingTop = getPaddingTop();
        int paddingLeft = getPaddingLeft();
        int paddingRight = getPaddingRight();
        int paddingBottom = getPaddingBottom();

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);//经测试与getMeasuredWidth方法返回值一致
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);//控件的总高度


        int totalHeight = paddingTop + paddingBottom;//控件总高
        Log.e(TAG,"paddingTop:" + paddingTop + ",paddingBottom:" + paddingBottom);
        int totalWidth = 0;//控件总宽,也可以默认取最大值

//        if (heightMode == MeasureSpec.EXACTLY) {//固定宽高
//            Log.e("test", "onMeasure:heightSize="+heightSize);
//            totalHeight = heightSize;
//        }

        int currentLineWidth = paddingLeft + paddingRight;//当前行前边所有孩子的宽度之和 (包括左右边距)
        int currentLineHeight = 0;//当前行的高度(取决于本行最高的孩子的高度加上下间距),高度只有一个上下padding,不用每行都算padding

        int childCount = getChildCount();
        for(int i = 0; i < childCount; i++){
            View childView = getChildAt(i);
            MarginLayoutParams lp = (MarginLayoutParams) childView.getLayoutParams();

            //加上当前子控件后,是否不超越父控件的宽度
            int testWidth = currentLineWidth + childView.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
            if(testWidth > widthSize){//超过最大限制,需要换行
                totalWidth = Math.max(totalWidth,currentLineWidth);//取最大的那一行的宽度
                currentLineWidth = paddingLeft + paddingRight;//重置宽度

                totalHeight += currentLineHeight;//计算总高度
                currentLineHeight = 0;//重置高度
            }

            currentLineWidth += childView.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;//每次插入一个子控件,增加当前行的宽度
            currentLineHeight = Math.max(currentLineHeight,childView.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);//当前行,最高的高度
            Log.e(TAG,"childView.getMeasuredHeight():" + childView.getMeasuredHeight() + "," + i + "lp.topMargin:" + lp.topMargin + "," + i +"lp.topMargin:" + lp.bottomMargin);


        }
        totalWidth = Math.max(totalWidth,currentLineWidth);//有可能最后一个元素所在的最后一行,宽度最大
        totalHeight += currentLineHeight;//加上最后一行的高度


        totalHeight = Math.min(totalHeight,heightSize);//使用高度最小的那个
        Log.e(TAG,"totalHeight:" + totalHeight + ",heightSize:" + heightSize);

        setMeasuredDimension(totalWidth,totalHeight);
    }



    @Override
    protected void onLayout(boolean b, int i, int i1, int i2, int i3) {
        Log.e(TAG,"i:" + i + ",i1:" + i1 + ",i2:" + i2 + ",i3:" + i3);
        int paddingLeft = getPaddingLeft();
        int paddingTop = getPaddingTop();
        int currentLineWidth = paddingLeft;//当前行对应父组件所在的坐标,父组件的左上角为原点
        int totalHeight = paddingTop;//之前所有行的总高度(包括上下边距);
        int currentLineHeight = 0;//当前行的高度(取决于本行最高的孩子的高度加上下间距)

        int childCount = getChildCount();
        for (int j = 0; j < childCount; j++) {
            View child = getChildAt(j);
            MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();

            //测试一下新来的小孩,能否插入当前行
            int testWidth = currentLineWidth + child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
            if(testWidth > getMeasuredWidth()){
                totalHeight += currentLineHeight;//准备换行,总行高要增加当前行的高度
                currentLineWidth = paddingLeft;//准备换行,重新开始计算行宽
                currentLineHeight = 0;//准备换行,当前行高清零
            }

            //插入小孩
            int left = currentLineWidth + lp.leftMargin;
            int right = left + child.getMeasuredWidth();
            int top = totalHeight + lp.topMargin;
            int bottom = top + child.getMeasuredHeight();
            child.layout(left, top, right, bottom);
//            child.layout(50, 50, 300, 300);

            //每插完一个小孩,刷新当前行的行宽与行高
            currentLineWidth += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;//每摆完一个小孩,更新当前行的总宽度
            currentLineHeight = Math.max(currentLineHeight,child.getMeasuredHeight()+lp.topMargin + lp.bottomMargin);//每摆完一个小孩,检查本行行高是否被刷新
        }

        totalHeight += currentLineHeight;//最后一个小孩插完,刷新总行高
    }
}


<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".TestRxjavaActivity">

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="400dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent">
        <TextView
            android:text="阿达是打发斯蒂芬"
            android:layout_width="wrap_content"
            android:layout_height="20dp"/>
        <com.example.text.view.FlowLayout
            android:padding="10dp"
            android:id="@+id/flowlayout"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@color/color_click_blue" />
    </LinearLayout>


</androidx.constraintlayout.widget.ConstraintLayout>

activity中:

flowlayout = findViewById(R.id.flowlayout);
        for(int i = 0; i < texts.length; i++){
            TextView textView = new TextView(this);
            textView.setText(texts[i]);
            textView.setBackgroundResource(R.color.gray);
            textView.setTextColor(R.color.black );
            ViewGroup.MarginLayoutParams params= new ViewGroup.MarginLayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
            params.setMargins(10,10,10,10);//设置边距
            flowlayout.addView(textView,params);//指定params类型,不然在viewGroup中获取时会默认是LayoutParams
        }

效果如下:
在这里插入图片描述
这里右边有白边是因为我计算的时候是按最大的一行来算的,你如果想让他直接铺满屏幕可以在onMeasure 方法中设置宽高的时候直接用取到的宽度设置上去

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

        measureChildren(widthMeasureSpec,heightMeasureSpec);//测量所有小孩的宽高,否则取不到子控件的大小和边距等

        int paddingTop = getPaddingTop();
        int paddingLeft = getPaddingLeft();
        int paddingRight = getPaddingRight();
        int paddingBottom = getPaddingBottom();

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);//经测试与getMeasuredWidth方法返回值一致
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);//控件的总高度

		//省略若干代码...

        setMeasuredDimension(widthSize ,totalHeight);

    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值