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】自定义 View 系列-ViewGroup -> 正文阅读

[移动开发]【Android】自定义 View 系列-ViewGroup

自定义 ViewGroup 其实也不复杂,但是要对子 View 的margin属性支持,就还需要花点经历。

下面自己写了一个自定义的 FlowLayout,支持了本身的 padding 属性的同时,也支持子 View 的 margin 属性。基本注释都已尽可能详尽地写在代码中。

先上效果图

?

?

兄弟们,上代码

import android.content.Context
import android.graphics.Rect
import android.util.AttributeSet
import android.view.ViewGroup
import androidx.core.view.children
import kotlin.math.max

/**
 *
 * @Author: QCoder
 * @CreateDate: 2021/12/6
 * @Description: 流式布局,当一行放不下后,换行放
 * 支持了本身的 Padding 属性,以及子 View 的 margin 属性
 * @Email: 526416248@qq.com
 */
class QFlowLayout(context: Context, attrs: AttributeSet) : ViewGroup(context, attrs) {

    //通过矩阵记录每个子 View margin 后的具体位置
    private val childrenBounds = mutableListOf<Rect>()
    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        //获取 QFlowLayout 的宽高的期望值 (XSize) 和 测量模式(XMode),其中 X 代表宽或高,下面同义。
        val widthMode = MeasureSpec.getMode(widthMeasureSpec)
        val widthSize = MeasureSpec.getSize(widthMeasureSpec)
        val heightMode = MeasureSpec.getMode(heightMeasureSpec)
        val heightSize = MeasureSpec.getSize(heightMeasureSpec)

        // QFlowLayout 的实际宽度
        var selfWidth = 0
        // QFlowLayout 的实际高度
        var selfHeight = 0
        //当行的宽度(当行已有宽度,由子 View 和 margin,padding 属性累加起来的)
        var currentLineWidth = 0
        //当行的高度
        var currentLineHeight = 0

        //遍历测量子 View
        for (child in children) {
            //判断,若 visibility == GONE ,即不可见又不占位置的时候,跳过测量
            if (child.visibility == GONE) continue
            //测量子 View。child 当前的子 View;XMeasureSpec 是QFlowLayout 对子 View 的期望
            measureChild(child, widthMeasureSpec, heightMeasureSpec)

            //获取到子 View 的 layout属性。
            val lp = child.layoutParams as MarginLayoutParams
            val childWidth = child.measuredWidth + lp.leftMargin + lp.rightMargin
            val childHeight = child.measuredHeight + lp.topMargin + lp.bottomMargin
            //判断是否需要换行,true 需要换行;false 不需要换行
            if (currentLineWidth + childWidth > widthSize - paddingLeft - paddingRight) {

                //将当前宽度和原先的宽度对比后,重置宽度为当前子 View 宽度
                selfWidth = max(selfWidth, currentLineWidth)
                currentLineWidth = childWidth


                selfHeight += currentLineHeight
                currentLineHeight = childHeight
                childrenBounds.add(
                    //因为需要换行,所以当前的子 View 是在新的一行,那么
                    // left 左边界 = 当前子View 的 leftMargin + QFlowLayout 的 paddingLeft
                    // top 上边界 = 累计的高度 selfHeight + 当前子View 的 topMargin + QFlowLayout 的 paddingTop
                    // right 右边界 = 当前子View 的宽度 + left
                    // bottom 下边界 = top + 当前子View 的高度
                    Rect(
                        lp.leftMargin + paddingLeft, //left
                        selfHeight + lp.topMargin + paddingTop, //top
                        child.measuredWidth + lp.leftMargin + paddingLeft, //right
                        selfHeight + lp.topMargin + paddingTop + child.measuredHeight //bottom
                    )
                )
            } else {
                //因为不需要换行,所以当前的子 View 在当行的接轨上去,那么
                // left 左边界 = 当行宽度 currentLineWidth + 当前子View 的 leftMargin + QFlowLayout 的 paddingLeft
                // top 上边界 = 累计的高度 selfHeight + 当前子View 的 topMargin + QFlowLayout 的 paddingTop
                // right 右边界 = 当行宽度 currentLineWidth + left
                // bottom 下边界 = top + 当前子View 的高度
                childrenBounds.add(
                    Rect(
                        currentLineWidth + lp.leftMargin + paddingLeft,//left
                        selfHeight + lp.topMargin + paddingTop,//top
                        child.measuredWidth + currentLineWidth + lp.leftMargin + paddingLeft, //right
                        selfHeight + lp.topMargin + paddingTop + child.measuredHeight//bottom
                    )
                )

                //不需要换行,所以当前行的宽度 = 原来的宽度 + 当前子 View 的宽度
                currentLineWidth += childWidth
                //行的高度,我们只需要知道最高的那就行
                currentLineHeight = max(currentLineHeight, childHeight)
            }

        }
        selfWidth = max(selfWidth, currentLineWidth) + paddingRight + paddingLeft
        selfHeight += currentLineHeight + paddingTop + paddingBottom
        setMeasuredDimension(
            if (widthMode == MeasureSpec.EXACTLY) widthSize else selfWidth,
            if (heightMode == MeasureSpec.EXACTLY) heightSize else selfHeight
        )
    }

    override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
        for ((index, child) in children.withIndex()) {
            val childBounds = childrenBounds[index]
            child.layout(
                childBounds.left,
                childBounds.top,
                childBounds.right,
                childBounds.bottom
            )
        }
    }

    override fun generateLayoutParams(attrs: AttributeSet?): LayoutParams {
        return MarginLayoutParams(context, attrs)
    }

    override fun generateLayoutParams(p: LayoutParams): LayoutParams {
        return MarginLayoutParams(p)
    }

    override fun generateDefaultLayoutParams(): LayoutParams {
        return MarginLayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
    }

}

最后,附上一个最近我整理的有关自定义 View 的知识网络结构图

链接:https://pan.baidu.com/s/1COTMibrJtANax7cXYL_eeA
提取码:tbok

?

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-12-08 13:55:57  更:2021-12-08 13:56: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年11日历 -2024/11/24 9:10:49-

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