IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android 中自定义ViewGroup实现流式布局的效果 -> 正文阅读

[移动开发]Android 中自定义ViewGroup实现流式布局的效果

前言:

自定义View与自定义ViewGroup的区别:

  1. 自定义View:在没有现成的View,需要自己实现的时候,就使用自定义View,一般继承自View,SurfaceView或其他的View。这个是控件。
  2. 自定义ViewGroup:一般是利用现有的组件根据特定的布局方式来组成新的组件,大多继承自ViewGroup或各种Layout。这个是组件。

自定义View的绘制流程图如下:
在这里插入图片描述

下面来实现流式布局,定义一个类FlowLayout继承自ViewGroup,重写里面的相关方法,实现流式布局的效果。

public class FlowLayout extends ViewGroup {
    //每个item横向间距
    private int mHorizontalSpacing = dp2px(16);
    //每个item竖向间距
    private int mVerticalSpacing = dp2px(8);

    //记录所有的行,一行一行的存储,用于Layout
    private List<List<View>> allLines;
    //记录每一行的行高,用于Layout
    List<Integer> lineHeights = new ArrayList<>();

    //new FlowLayout(传入上下文)
    public FlowLayout(Context context) {
        super(context);
    }

    //在xml中使用 在xml转化为java代码的时候,通过反射调用有两个参数的构造函数
    public FlowLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    //代码中有不同的主题style,调用有三个参数的构造函数
    public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    //进行集合的初始化
    private void initMeasureParams() {
        if (allLines != null) {
            allLines.clear();
        } else {
            allLines = new ArrayList<>();
        }
        if (lineHeights != null) {
            lineHeights.clear();
        } else {
            lineHeights = new ArrayList<>();
        }
    }

    //度量
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //每次进入onMeasure()方法中 都需要将全局变量重新初始化
        initMeasureParams();
        //度量子View的宽度和高度
        int childCount = getChildCount();
        int paddingLeft = getPaddingLeft();
        int paddingRight = getPaddingRight();
        int paddingTop = getPaddingTop();
        int paddingBottom = getPaddingBottom();

        //ViewGroup解析的宽度
        int selfWidth = MeasureSpec.getSize(widthMeasureSpec);
        //ViewGroup解析的高度
        int selfHeight = MeasureSpec.getSize(heightMeasureSpec);

        //保存一行中的所有View
        List<View> lineViews = new ArrayList<>();

        //记录这一行已经使用了多宽的size
        int lineWidthUsed = 0;
        //一行的行高
        int lineHeight = 0;
        //measure过程中,子View要求的父ViewGroup的宽
        int parentNeededWidth = 0;
        //measure过程中,子View要求的父ViewGroup的高
        int parentNeededHeight = 0;

        for (int i = 0; i < childCount; i++) {
            View childView = getChildAt(i);
            LayoutParams childLP = childView.getLayoutParams();
            int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, paddingLeft + paddingRight, childLP.width);
            int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, paddingBottom + paddingTop, childLP.height);
            childView.measure(childWidthMeasureSpec, childHeightMeasureSpec);

            //获取子View的宽高
            int childMeasuredWidth = childView.getMeasuredWidth();
            int childMeasuredHeight = childView.getMeasuredHeight();

            //通过宽度来判断是否需要换行,通过换行后的每行的行高来获取
            //整个ViewGroup的行高
            if (childMeasuredWidth + lineWidthUsed + mHorizontalSpacing > selfWidth) {
                allLines.add(lineViews);
                lineHeights.add(lineHeight);

                //一旦换行,我们就可以判断当前列需要的宽和高了,所以此时需要记录下来
                parentNeededHeight = parentNeededHeight + lineHeight + mVerticalSpacing;
                parentNeededWidth = Math.max(parentNeededWidth, lineWidthUsed + mHorizontalSpacing);
                lineViews = new ArrayList<>();
                lineWidthUsed = 0;
                lineHeight = 0;
            }

            //view是分行layout的,所以要记录每一行有哪些View,这样可以方便布局
            lineViews.add(childView);
            //每行都会有自己的宽和高
            lineWidthUsed = lineWidthUsed + childMeasuredWidth + mHorizontalSpacing;
            lineHeight = Math.max(lineHeight, childMeasuredHeight);
        }

        //根据子View的度量结果,来重新度量自己的ViewGroup
        //作为一个ViewGroup,它自己也是一个View,它的大小也需要根据它的父亲给它提供的宽高来度量
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        int realWidth = (widthMode == MeasureSpec.EXACTLY) ? selfWidth : parentNeededWidth;
        int realHeight = (heightMode == MeasureSpec.EXACTLY) ? selfHeight : parentNeededHeight;

        //度量自己的宽度和高度
        setMeasuredDimension(realWidth, realHeight);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        //获取Layout中的行数
        int lineCount = allLines.size();
        int curL = getPaddingLeft();
        int curT = getPaddingTop();
        for (int i = 0; i < lineCount; i++) {
            List<View> lineViews = allLines.get(i);
            int lineHeight = lineHeights.get(i);
            for (int j = 0; j < lineViews.size(); j++) {
                View view = lineViews.get(j);
                int left = curL;
                int top = curT;
                int right = left + view.getMeasuredWidth();
                int bottom = top + view.getMeasuredHeight();
                view.layout(left, top, right, bottom);
                curL = right + mHorizontalSpacing;
            }
            curL = getPaddingLeft();
            curT = lineHeight + curT + mVerticalSpacing;
        }
    }
    
	//dp转为px
    public static int dp2px(int dp) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, Resources.getSystem().getDisplayMetrics());
    }
}

之后我们在xml中,进行引用,就可以了。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".ViewGroupActivity">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="搜索历史"
        android:textColor="@color/black"
        android:textSize="17sp" />

    <com.example.animationtest.view.FlowLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/tv_back_color"
            android:text="水果味孕妇奶粉"
            android:textColor="@color/black" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/tv_back_color"
            android:text="儿童洗衣机"
            android:textColor="@color/black" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/tv_back_color"
            android:text="洗衣机全自动"
            android:textColor="@color/black" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/tv_back_color"
            android:text="手机"
            android:textColor="@color/black"
            android:textSize="16sp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/tv_back_color"
            android:text="儿童汽车可坐人111111111111111111"
            android:textColor="@color/black"
            android:textSize="16sp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/tv_back_color"
            android:text="抽真空收纳袋"
            android:textColor="@color/black"
            android:textSize="16sp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/tv_back_color"
            android:text="儿童滑板车"
            android:textColor="@color/black"
            android:textSize="16sp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/tv_back_color"
            android:text="稳定器 电容"
            android:textColor="@color/black"
            android:textSize="16sp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/tv_back_color"
            android:text="儿童洗衣机"
            android:textColor="@color/black"
            android:textSize="16sp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/tv_back_color"
            android:text="衣服"
            android:textColor="@color/black"
            android:textSize="16sp" />


        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/tv_back_color"
            android:text="运动鞋"
            android:textColor="@color/black"
            android:textSize="16sp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/tv_back_color"
            android:text="手表"
            android:textColor="@color/black"
            android:textSize="16sp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/tv_back_color"
            android:text="水果味孕妇奶粉"
            android:textColor="@color/black" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/tv_back_color"
            android:text="儿童洗衣机"
            android:textColor="@color/black" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/tv_back_color"
            android:text="洗衣机全自动"
            android:textColor="@color/black" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/tv_back_color"
            android:text="手机"
            android:textColor="@color/black"
            android:textSize="16sp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/tv_back_color"
            android:text="抽真空收纳袋"
            android:textColor="@color/black"
            android:textSize="16sp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/tv_back_color"
            android:text="儿童滑板车"
            android:textColor="@color/black"
            android:textSize="16sp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/tv_back_color"
            android:text="稳定器 电容"
            android:textColor="@color/black"
            android:textSize="16sp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/tv_back_color"
            android:text="儿童洗衣机"
            android:textColor="@color/black"
            android:textSize="16sp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/tv_back_color"
            android:text="衣服"
            android:textColor="@color/black"
            android:textSize="16sp" />


        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/tv_back_color"
            android:text="运动鞋"
            android:textColor="@color/black"
            android:textSize="16sp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/tv_back_color"
            android:text="手表"
            android:textColor="@color/black"
            android:textSize="16sp" />
    </com.example.animationtest.view.FlowLayout>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="搜索发现"
        android:textColor="@color/black"
        android:textSize="17sp" />

    <com.example.animationtest.view.FlowLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/tv_back_color"
            android:text="水果味孕妇奶粉"
            android:textColor="@color/black" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/tv_back_color"
            android:text="儿童洗衣机"
            android:textColor="@color/black" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/tv_back_color"
            android:text="洗衣机全自动"
            android:textColor="@color/black" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/tv_back_color"
            android:text="手机"
            android:textColor="@color/black"
            android:textSize="16sp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/tv_back_color"
            android:text="儿童汽车可坐人111111111111111111"
            android:textColor="@color/black"
            android:textSize="16sp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/tv_back_color"
            android:text="抽真空收纳袋"
            android:textColor="@color/black"
            android:textSize="16sp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/tv_back_color"
            android:text="儿童滑板车"
            android:textColor="@color/black"
            android:textSize="16sp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/tv_back_color"
            android:text="稳定器 电容"
            android:textColor="@color/black"
            android:textSize="16sp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/tv_back_color"
            android:text="儿童洗衣机"
            android:textColor="@color/black"
            android:textSize="16sp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/tv_back_color"
            android:text="衣服"
            android:textColor="@color/black"
            android:textSize="16sp" />


        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/tv_back_color"
            android:text="运动鞋"
            android:textColor="@color/black"
            android:textSize="16sp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/tv_back_color"
            android:text="手表"
            android:textColor="@color/black"
            android:textSize="16sp" />

    </com.example.animationtest.view.FlowLayout>
</LinearLayout>

运行后,效果如下:

在这里插入图片描述

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-02-24 15:24:46  更:2022-02-24 15:25:08 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年9日历 -2024/9/20 16:26:44-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码