Unity3D - “父级有一种布局组”错误

Posted

技术标签:

【中文标题】Unity3D - “父级有一种布局组”错误【英文标题】:Unity3D - "Parent has a type of layout group" error 【发布时间】:2018-10-30 07:41:46 【问题描述】:

我在 Canvas 中有这个简单的结构:

游戏对象(垂直布局组) UI 图像(垂直布局组) TMP UGUI 文本(水平布局组,内容大小调整器)

现在,它工作得很好,当文本超出边界时,UI-Image 会展开。 但是由于我有一个布局组作为我的 TMP 文本的父级,所以我在文本内的内容大小调整器中收到一个错误,说“父级有一种布局组组件......”。 结果,当我更改文本时,图像高度有时不会更新(不会增长或缩小,只有在我刷新或保存项目后)。

我在这里做错了吗?

【问题讨论】:

正如警告所说,父游戏对象(image_container)有一个布局组组件。内容大小调整器应该在没有布局组的游戏对象下 @Tricko 我知道。但我没有其他方法可以实现基于文本的扩展,所以我的问题是有什么替代方法可以做到这一点? 【参考方案1】:

我将把它转换为答案,因为我要附上图片。我为聊天功能做了类似的事情。

    使父级的内容尺寸更合适,并将水平或垂直尺寸设置为首选尺寸。

    让其直接子元素成为背景,并为其添加一个布局元素以控制其最小尺寸。还要向它添加一个布局组以控制您将作为子项放置的文本。

    将文本添加为​​背景的子项

    更改文本以检查背景。

[编辑] 1.我把Parent的布局组改成VerticalLayoutGroup。 2. 我复制了游戏对象“背景”,但使用不同的文本,您可以看到ContentSizeFitterVerticalLayoutGroup 如何控制孩子的大小。

在上面的屏幕截图中,我从未对 rect 变换进行任何调整。我只是更改了文本,如您所见,每个文本/对话框/消息的背景也进行了调整。

【讨论】:

您好,效果很好,但是如果我在聊天层中有另一个“垂直布局”(如果我们查看您的架构)怎么办? 父级上的VerticalLayout 的目的是什么?如果您有多个消息,只需复制上面示例中的游戏对象“背景”。我将编辑屏幕截图,以便您还可以检查父级中的 ContentSizeFitter 的工作方式。 非常感谢您的帮助和详细的回答:)【参考方案2】:

我被这个问题困扰了一年多,终于以正确的方式解决了。

解决方法很简单:

    在父对象的布局组组件上勾选“控制子大小宽度/高度”。 删除任何子对象的内容大小调整器。

【讨论】:

【参考方案3】:

制作了一个从原始 contentSizeFitter 组件复制的自定义脚本,我在其中添加了一个名为 applyToParent 的布尔值,如果“true”并且父级具有 rectTransform 组件,则父级将沿当前对象缩放。您甚至可以添加一个 recttransforms 变量列表,您可以使它们也遵循相同的大小! screenshot

using UnityEngine;
using UnityEngine.EventSystems;

namespace UnityEngine.UI

    [AddComponentMenu("Layout/Custom Content Size Fitter", 888)]
    [ExecuteAlways]
    [RequireComponent(typeof(RectTransform))]
    /// <summary>
    /// Resizes a RectTransform to fit the size of its content & the ability to modify the size of the parent as well
    /// </summary>
    /// <remarks>
    /// The ContentSizeFitter can be used on GameObjects that have one or more ILayoutElement components, such as Text, Image, HorizontalLayoutGroup, VerticalLayoutGroup, and GridLayoutGroup.
    /// </remarks>
    public class CustomContentSizeFitter :  UIBehaviour, ILayoutSelfController
    
        /// <summary>
        /// The size fit modes avaliable to use.
        /// </summary>
        public enum FitMode
        
            /// <summary>
            /// Don't perform any resizing.
            /// </summary>
            Unconstrained,
            /// <summary>
            /// Resize to the minimum size of the content.
            /// </summary>
            MinSize,
            /// <summary>
            /// Resize to the preferred size of the content.
            /// </summary>
            PreferredSize
        
        [SerializeField] protected FitMode m_HorizontalFit = FitMode.Unconstrained;
       
       
        /// <summary>
        /// The fit mode to use to determine the width.
        /// </summary>
        public FitMode horizontalFit  get  return m_HorizontalFit;  set  if (SetPropertyUtility2.SetStruct(ref m_HorizontalFit, value)) SetDirty();  

        [SerializeField] protected FitMode m_VerticalFit = FitMode.Unconstrained;

        /// <summary>
        /// The fit mode to use to determine the height.
        /// </summary>
        public FitMode verticalFit  get  return m_VerticalFit;  set  if (SetPropertyUtility2.SetStruct(ref m_VerticalFit, value)) SetDirty();  


        private DrivenRectTransformTracker m_Tracker;

        protected CustomContentSizeFitter()
        

        protected override void OnEnable()
        
            base.OnEnable();
            SetDirty();
        

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

        protected override void OnRectTransformDimensionsChange()
        
            SetDirty();
        

        public virtual void SetLayoutHorizontal()
        
            m_Tracker.Clear();
            HandleSelfFittingAlongAxis(0);
        

        /// <summary>
        /// Calculate and apply the vertical component of the size to the RectTransform
        /// </summary>
        public virtual void SetLayoutVertical()
        
            HandleSelfFittingAlongAxis(1);
        
        [System.NonSerialized] private RectTransform m_Rect;
        [System.NonSerialized] private RectTransform m_parentRect;
        private RectTransform rectTransform
        
            get
            
                if (m_Rect == null)
                    m_Rect = GetComponent<RectTransform>();
                return m_Rect;
            
        
        private RectTransform parentRectTransform
        
            get
            
                if (m_parentRect == null)
                    m_parentRect = rectTransform.parent.GetComponent<RectTransform>();
                return m_parentRect;
            
        
        private void HandleSelfFittingAlongAxis(int axis)
        
            FitMode fitting = (axis == 0 ? horizontalFit : verticalFit);
            if (fitting == FitMode.Unconstrained)
            
                // Keep a reference to the tracked transform, but don't control its properties:
                m_Tracker.Add(this, rectTransform, DrivenTransformProperties.None);
                return;
            

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

            // Set size to min or preferred size
            if (fitting == FitMode.MinSize)
                rectTransform.SetSizeWithCurrentAnchors((RectTransform.Axis)axis, LayoutUtility.GetMinSize(m_Rect, axis));
            else
                rectTransform.SetSizeWithCurrentAnchors((RectTransform.Axis)axis, LayoutUtility.GetPreferredSize(m_Rect, axis));
            
            if(applyToParent && parentRectTransform != null )
            
                if(fitting == FitMode.MinSize )
                    parentRectTransform.SetSizeWithCurrentAnchors((RectTransform.Axis)axis, LayoutUtility.GetMinSize(m_Rect, axis));
                else
                    parentRectTransform.SetSizeWithCurrentAnchors((RectTransform.Axis)axis, LayoutUtility.GetPreferredSize(m_Rect, axis));
            
        
        public bool applyToParent = true;

        protected void SetDirty()
        
            if (!IsActive())
                return;

            LayoutRebuilder.MarkLayoutForRebuild(rectTransform);
        

        #if UNITY_EDITOR
        protected override void OnValidate()
        
            SetDirty();
        
        #endif

    

    public static class SetPropertyUtility2
    
        public static bool SetColor(ref Color currentValue, Color newValue)
        
            if (currentValue.r == newValue.r && currentValue.g == newValue.g && currentValue.b == newValue.b && currentValue.a == newValue.a)
                return false;

            currentValue = newValue;
            return true;
        

        public static bool SetStruct<T>(ref T currentValue, T newValue) where T: struct
        
            if (currentValue.Equals(newValue))
                return false;

            currentValue = newValue;
            return true;
        

        public static bool SetClass<T>(ref T currentValue, T newValue) where T: class
        
            if ((currentValue == null && newValue == null) || (currentValue != null && currentValue.Equals(newValue)))
                return false;

            currentValue = newValue;
            return true;
        

    
    
    

【讨论】:

【参考方案4】:

最简单的解决方案,如果突然有其他人相关。

创建一个标准的 ScrollView,从中删除“内容”并添加文本而不是内容(不要忘记将文本添加到 ScrollRect 中的内容字段)。接下来,在文本中添加 ContentSizeFittier。enter image description here

【讨论】:

以上是关于Unity3D - “父级有一种布局组”错误的主要内容,如果未能解决你的问题,请参考以下文章

Unity3D的版本介绍

Unity3d 2021版本播放视频组件VideoPlayer报错The type name ‘VideoPlayer‘ could not be found in the namespace...

Unity3D之Legacy动画系统学习笔记

Unity3d可视化脚本框架如何在场景后工作?

Unity3D新手教学,让你十二小时,从入门到掌握!(三 ) [转]

uni-app 错误集合