灵活的网格布局

本文介绍如何通过继承Unity的LayoutGroup并重写CalculateLayoutInputHorizontal方法,创建一个能自动适应并支持九宫格布局的网格组件,可根据不同适配类型调整列行数、间距和内边距。
摘要由CSDN通过智能技术生成

总所周知 Grid Layout Group 平平无奇,单元格大小都要手动设置。
想做个九宫格布局。还要手动计算单元格大小,偏移量等
使用Vertical Layout Group 和 Horzontal Layout Group 组合又非常麻烦

想要自定义布局,只需继承 Layout Group 重写 CalculateLayoutInputHorizontal 单元格坐标以及大小即可

    public override void CalculateLayoutInputHorizontal()
    {
        base.CalculateLayoutInputHorizontal();

        //code
    }

Layout Group定义自行查阅文档:
https://docs.unity3d.com/2018.4/Documentation/ScriptReference/UI.LayoutGroup.html

第一步:对子对象数量开平方根计算出行列数

        float squareRoot = Mathf.Sqrt(rectChildren.Count);
        var rows = Mathf.CeilToInt(squareRoot);
        var columns = Mathf.CeilToInt(squareRoot);
        //如果行或列为0没必要继续
        if (rows == 0 || columns == 0)
            return;

第二步:计算单元格大小

        var cellWidth = rectTransform.rect.width / columns;
        var cellHeight = rectTransform.rect.height / rows;

第三步:计算单元格坐标并设置单元格

        for (var i = 0; i < rectChildren.Count; i++)
        {
            //获取行索引
            var rowIndex = i / columns;
            //获取列索引
            var columnIndex = i % columns;

            //计算坐标
            var x = cellWidth  * columnIndex ;
            var y = cellHeight  * rowIndex ;

            var item = rectChildren[i];

            //设置单元格坐标以及大小
            SetChildAlongAxis(item, 0, x, cellWidth);
            SetChildAlongAxis(item, 1, y, cellHeight);
        }

现在你将会得到一个这样的布局
在这里插入图片描述
单元格之间应该有间隔存在,添加间隔的大小计算

        var spacingWidth = spacing.x / columns * (columns - 1);
        var spacingHeight = spacing.y / rows * (rows - 1);

单元格大小减去间隔大小

        var cellWidth = width - spacingWidth;
        var cellHeight = height - spacingHeight;

单元格坐标添加上间隔位置

            var x = (cellWidth + spacing.x) * columnIndex;
            var y = (cellHeight + spacing.y) * rowIndex;

这是添加上间隔计算后的布局样子
在这里插入图片描述
除了间隔,还应该添加上内边距的偏移,计算内边距大小

        var paddingWidth = (padding.left + padding.right) / columns;
        var paddingHeight = (padding.top + padding.bottom) / rows;

单元格减少内边距大小

        var cellWidth = width - spacingWidth - paddingWidth;
        var cellHeight = height - spacingHeight - paddingHeight;

单元格坐标偏移

            var x = (cellWidth + spacing.x) * columnIndex + padding.left;
            var y = (cellHeight + spacing.y) * rowIndex + padding.top;

最终效果:
在这里插入图片描述
除了平铺,你可能还想要它基于水平或垂直布局

        if (fitType == FitType.FIXEDCOLUMNS)
            columns = 1;
        else if (fitType == FitType.FIXEDROWS)
            rows = 1;

        if (fitType == FitType.Width || fitType == FitType.FIXEDCOLUMNS)
            rows = Mathf.CeilToInt(rectChildren.Count / (float)columns);

        if (fitType == FitType.Height || fitType == FitType.FIXEDROWS)
            columns = Mathf.CeilToInt(rectChildren.Count / (float)rows);

在这里插入图片描述
在这里插入图片描述

总结:
因为对象是可以嵌套的,所以可以很方便的做出类似网站一样的布局
在这里插入图片描述

实现代码:

using UnityEngine;
using UnityEngine.UI;

/// <summary>
/// 灵活的网格布局
/// </summary>
public class FlexibleGridLayout : LayoutGroup
{
    /// <summary>
    /// 适配类型
    /// </summary>
    public enum FitType
    {
        /// <summary>
        /// 均匀分布
        /// </summary>
        UniForm,
        /// <summary>
        /// 水平优先
        /// </summary>
        Horizontal,
        /// <summary>
        /// 垂直优先
        /// </summary>
        Verticality,
        /// <summary>
        /// 固定行
        /// </summary>
        FixedRow,
        /// <summary>
        /// 固定列
        /// </summary>
        FixedColumn
    }

    /// <summary>
    /// 适配类型,默认均匀分布
    /// </summary>
    [Header("Flexible Grid")]
    public FitType fitType = FitType.UniForm;
    /// <summary>
    /// 单元格间隔
    /// </summary>
    public Vector2 spacing;

    /// <summary>
    /// 计算水平布局
    /// </summary>
    public override void CalculateLayoutInputHorizontal()
    {
        base.CalculateLayoutInputHorizontal();

        float squareRoot = Mathf.Sqrt(rectChildren.Count);
        var rows = Mathf.CeilToInt(squareRoot);
        var columns = Mathf.CeilToInt(squareRoot);

        if (fitType == FitType.FixedColumn)
            columns = 1;
        else if (fitType == FitType.FixedRow)
            rows = 1;

        if (fitType == FitType.Horizontal || fitType == FitType.FixedColumn)
            rows = Mathf.CeilToInt(rectChildren.Count / (float)columns);

        if (fitType == FitType.Verticality || fitType == FitType.FixedRow)
            columns = Mathf.CeilToInt(rectChildren.Count / (float)rows);

        if (rows == 0 || columns == 0)
            return;

        var width = rectTransform.rect.width / columns;
        var height = rectTransform.rect.height / rows;

        var spacingWidth = spacing.x / columns * (columns - 1);
        var spacingHeight = spacing.y / rows * (rows - 1);

        var paddingWidth = (padding.left + padding.right) / columns;
        var paddingHeight = (padding.top + padding.bottom) / rows;

        var cellWidth = width - spacingWidth - paddingWidth;
        var cellHeight = height - spacingHeight - paddingHeight;

        for (var i = 0; i < rectChildren.Count; i++)
        {
            var rowIndex = i / columns;
            var columnIndex = i % columns;

            var x = (cellWidth + spacing.x) * columnIndex + padding.left;
            var y = (cellHeight + spacing.y) * rowIndex + padding.top;

            var item = rectChildren[i];

            SetChildAlongAxis(item, 0, x, cellWidth);
            SetChildAlongAxis(item, 1, y, cellHeight);
        }
    }

    public override void CalculateLayoutInputVertical()
    {

    }

    public override void SetLayoutHorizontal()
    {
        //布局刷新是从最里面开始一直到外面
        //有时候外面布局会无效
        //在这里再从外面到里面刷新一次
        CalculateLayoutInputHorizontal();
    }

    public override void SetLayoutVertical()
    {
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小鱼游戏开发

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值