Unity ContentSizeFitter 限制最大尺寸(限制最大大小)

使用UGUI制作界面的时候,经常有使用ContentSizeFitter组件来让父对象适应所有子对象的总大小的情况,而有时候会有需求说,父对象达到某个最大尺寸后,就固定这个大小不再增长了,就是说有个最大尺寸的限制,这要怎么实现呢?话不多说,上代码:

文件:ClampedContentSizeFitter.cs

using UnityEngine;
using UnityEngine.UI;

namespace ZetanStudio.UI
{
    public class ClampedContentSizeFitter : ContentSizeFitter
    {
#pragma warning disable IDE1006 // 命名样式
        [SerializeField] private float m_MaxWidth = -1;
        public float maxWdith { get => m_MaxWidth; set { m_MaxWidth = value; SetDirty(); } }

        [SerializeField] private float m_MaxHeight = -1;
        public float maxHeight { get => m_MaxHeight; set { m_MaxHeight = value; SetDirty(); } }

        [System.NonSerialized] private RectTransform m_Rect;
        private RectTransform rectTransform
        {
            get
            {
                if (m_Rect == null)
                    m_Rect = GetComponent<RectTransform>();
                return m_Rect;
            }
        }
#pragma warning restore IDE1006 // 命名样式

        private DrivenRectTransformTracker m_Tracker;

        protected ClampedContentSizeFitter()
        { }

        protected override void OnDisable()
        {
            m_Tracker.Clear();
            LayoutRebuilder.MarkLayoutForRebuild(rectTransform);
        }

        private void HandleSelfFittingAlongAxis(int axis)
        {
            FitMode fitting = (axis == 0 ? horizontalFit : verticalFit);
            if (fitting == FitMode.Unconstrained)
            {
                m_Tracker.Add(this, rectTransform, DrivenTransformProperties.None);
                return;
            }

            m_Tracker.Add(this, rectTransform, (axis == 0 ? DrivenTransformProperties.SizeDeltaX : DrivenTransformProperties.SizeDeltaY));

            var maxValue = axis == 0 ? m_MaxWidth : m_MaxHeight;
            if (fitting == FitMode.MinSize)
                rectTransform.SetSizeWithCurrentAnchors((RectTransform.Axis)axis, maxValue >= 0 ? Mathf.Min(LayoutUtility.GetMinSize(m_Rect, axis), maxValue) : LayoutUtility.GetMinSize(m_Rect, axis));
            else
                rectTransform.SetSizeWithCurrentAnchors((RectTransform.Axis)axis, maxValue >= 0 ? Mathf.Min(LayoutUtility.GetPreferredSize(m_Rect, axis), maxValue) : LayoutUtility.GetPreferredSize(m_Rect, axis));
        }

        public override void SetLayoutHorizontal()
        {
            m_Tracker.Clear();
            HandleSelfFittingAlongAxis(0);
        }

        public override void SetLayoutVertical()
        {
            HandleSelfFittingAlongAxis(1);
        }
    }
}

相应的检查器界面代码:

文件:ClampedContentSizeFitterInspector.cs(放入任意Editor文件夹中)

using UnityEditor;
using UnityEngine;

namespace ZetanStudio.UI.Editor
{
    [CustomEditor(typeof(ClampedContentSizeFitter))]
    public class ClampedContentSizeFitterInspector : UnityEditor.UI.ContentSizeFitterEditor
    {
        SerializedProperty m_HorizontalFit;
        SerializedProperty m_VerticalFit;
        SerializedProperty m_MaxWidth;
        SerializedProperty m_MaxHeight;

        protected override void OnEnable()
        {
            base.OnEnable();
            m_HorizontalFit = serializedObject.FindProperty("m_HorizontalFit");
            m_VerticalFit = serializedObject.FindProperty("m_VerticalFit");
            m_MaxWidth = serializedObject.FindProperty("m_MaxWidth");
            m_MaxHeight = serializedObject.FindProperty("m_MaxHeight");
        }

        public override void OnInspectorGUI()
        {
            base.OnInspectorGUI();
            serializedObject.Update();
            if (m_HorizontalFit.enumValueIndex != 0)
                LayoutElementField(m_MaxWidth, 0, new GUIContent("最大宽度"));
            if (m_VerticalFit.enumValueIndex != 0)
                LayoutElementField(m_MaxHeight, 0, new GUIContent("最大高度"));
            serializedObject.ApplyModifiedProperties();
        }

        void LayoutElementField(SerializedProperty property, float defaultValue, GUIContent rawLabel)
        {
            LayoutElementField(property, _ => defaultValue, rawLabel);
        }

        void LayoutElementField(SerializedProperty property, System.Func<RectTransform, float> defaultValue, GUIContent rawLabel)
        {
            Rect position = EditorGUILayout.GetControlRect();

            // Label
            GUIContent label = EditorGUI.BeginProperty(position, rawLabel, property);

            // Rects
            Rect fieldPosition = EditorGUI.PrefixLabel(position, label);

            Rect toggleRect = fieldPosition;
            toggleRect.width = 16;

            Rect floatFieldRect = fieldPosition;
            floatFieldRect.xMin += 16;

            // Checkbox
            EditorGUI.BeginChangeCheck();
            bool enabled = EditorGUI.ToggleLeft(toggleRect, GUIContent.none, property.floatValue >= 0);
            if (EditorGUI.EndChangeCheck())
            {
                // This could be made better to set all of the targets to their initial width, but mimizing code change for now
                property.floatValue = (enabled ? defaultValue((target as ClampedContentSizeFitter).transform as RectTransform) : -1);
            }

            if (!property.hasMultipleDifferentValues && property.floatValue >= 0)
            {
                // Float field
                EditorGUIUtility.labelWidth = 4; // Small invisible label area for drag zone functionality
                EditorGUI.BeginChangeCheck();
                float newValue = EditorGUI.FloatField(floatFieldRect, new GUIContent(" "), property.floatValue);
                if (EditorGUI.EndChangeCheck())
                {
                    property.floatValue = Mathf.Max(0, newValue);
                }
                EditorGUIUtility.labelWidth = 0;
            }

            EditorGUI.EndProperty();
        }
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: UnityContentSizeFitter的坑: 1. 如果你的RectTransform的宽高都是,那么ContentSizeFitter是不会起作用的。 2. 如果你的RectTransform的宽高都是固定的,那么ContentSizeFitter也是不会起作用的。 3. 如果你的RectTransform的宽高是由父级控件决定的,那么ContentSizeFitter会根据子级控件的大小来自动调整父级控件的大小。 4. 如果你的RectTransform的宽高是由子级控件决定的,那么ContentSizeFitter会根据子级控件的大小来自动调整父级控件的大小,但是如果子级控件的大小超出了父级控件的大小,那么ContentSizeFitter也无法起作用。 5. 如果你的RectTransform的宽高是由子级控件决定的,但是你又想让ContentSizeFitter起作用,那么你需要在子级控件上添加LayoutElement组件,并设置Preferred Width和Preferred Height属性,这样ContentSizeFitter才能根据子级控件的大小来自动调整父级控件的大小。 ### 回答2: 在使用Unity开发UI界面的过程中,可能会用到ContentSizeFitter这个组件。这个组件的主要作用是自动调整UI元素的大小,以适应内容的变化。但是这个组件有很多坑,需要注意。 第一个坑是设置HorizontalAlignment或VerticalAlignment属性时不起作用。 例如,你想让一个文本框垂直居中,可以设置VerticalAlignment属性为Middle。但是在实际使用中,你会发现设置这个属性并不会生效。这是因为ContentSizeFitter组件会自动调整UI元素的大小,导致VerticalAlignment属性失效。 第二个坑是如果ContentSizeFitter的父对象被设置了Layout Group组件,则ContentSizeFitter组件可能会失效。 Layout Group组件用于控制UI元素的排列方式,例如水平排列或垂直排列。但是如果你在ContentSizeFitter的父对象上添加了Layout Group组件,ContentSizeFitter组件可能会失效。这是因为Layout Group组件会自动调整UI元素的大小和位置,覆盖了ContentSizeFitter组件的作用。 第三个坑是当ContentSizeFitter组件和Layout Group组件同时存在时,它们的优先级是不确定的。 如果你在ContentSizeFitter的父对象上同时添加了Layout Group组件和ContentSizeFitter组件,那么它们之间的优先级是不确定的。有时ContentSizeFitter组件会覆盖Layout Group组件,有时Layout Group组件会覆盖ContentSizeFitter组件,导致UI出现意想不到的结果。 综上所述,虽然ContentSizeFitter组件能够自动调整UI元素的大小,但是在使用过程中需要注意以上三个坑。特别是当ContentSizeFitter组件和Layout Group组件同时存在时,需要保证它们的优先级正确,否则可能会导致UI出现不可预知的问题。 ### 回答3: UnityContentSizeFitter组件可以在UILayout组件中的容器元素上设置,用于根据元素的内容自动调整其大小。在使用ContentSizeFitter组件时,有些坑需要注意。本文就对一些常见的ContentSizeFitter的坑进行探讨。 坑一:ContentSizeFitter自适应只考虑本身内容的尺寸 ContentSizeFitter组件的自适应是根据本身的内容来计算尺寸的。如果在ContentSizeFitter组件所在的父级容器的RectTransform组件中设置了具体的尺寸,那么容器将只会根据ContentSizeFitter的内容大小进行缩放。如果父级容器的尺寸ContentSizeFitter的自适应大小冲突,那么可能会出现内容被裁剪或者缩放错乱的情况。 坑二:ContentSizeFitter和GridLayoutGroup冲突问题 GridLayoutGroup组件可以在父级容器中创建一个网格布局。当GridLayoutGroup组件和ContentSizeFitter组件同时使用时,可能会出现布局错乱问题。此时需要在GridLayoutGroup组件和ContentSizeFitter组件中选择一个作为主要组件,根据需求进行适当调整。 坑三:ContentSizeFitter和Text组件的冲突问题 在使用ContentSizeFitter组件时,如果元素中包含Text组件,可能会出现Text内容显示不全的问题。此时需要在Text组件中设置Preferred Width或Preferred Height。这样可以避免内容被截断,同时通过ContentSizeFitter组件实现自适应大小。 坑四:ContentSizeFitter和自定义Mesh组件的冲突问题 自定义Mesh组件的渲染方式与Unity预制体的UI组件不同,如果在自定义Mesh组件中使用ContentSizeFitter组件,可能会出现布局错乱问题。此时需要根据具体情况进行剪裁操作或调整Mesh组件的大小来保证布局正常。 以上就是一些常见的使用ContentSizeFitter组件时要注意的坑。开发者在使用ContentSizeFitter组件时需要根据具体情况进行适当调整,避免出现尺寸错误或布局混乱的问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

莫需要

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

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

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

打赏作者

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

抵扣说明:

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

余额充值