获取UI文本元素的高度不正确 Unity

4

我有一些代码可以设置文本元素的自定义宽度,然后高度会自动调整,如下所示:

Title.SetTextContainerSize("autoH", 330);

public void SetTextContainerSize(string fit, float dimension = 0)
    {
        if (UIElement.GetComponent<ContentSizeFitter>() == null)
            UISizeFitterComponent = UIElement.AddComponent(typeof(ContentSizeFitter)) as ContentSizeFitter;

        if (fit == "autoWH")
        {
            UISizeFitterComponent.horizontalFit = ContentSizeFitter.FitMode.PreferredSize;
            UISizeFitterComponent.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
            base.SetDimensions( RectOptions.sizeDelta);
        }
        else if (fit == "autoW")
        {
            UISizeFitterComponent.horizontalFit = ContentSizeFitter.FitMode.PreferredSize;
            base.SetDimensions( new Vector2(RectOptions.rect.width, dimension));
        }
        else if (fit == "autoH")
        { //here is a problem.. 
            UISizeFitterComponent.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
            Canvas.ForceUpdateCanvases();
            Debug.Log(new Vector2(dimension, RectOptions.rect.height));
            base.SetDimensions( new Vector2(dimension, RectOptions.rect.height));
        }
    }

编辑 添加了设置尺寸的功能

public void SetDimensions(Vector2 dimensions)
    {
        RectOptions.sizeDelta = dimensions;
        Dimensions = dimensions; //this just sets the value of a property. 
    }

但是当我调用更新文本的函数时,从Debug.Log()中得到以下结果,它说宽度=330,而高度是2077。在这种情况下,宽度是正确的,但是高度完全不对。
请看这里实际元素和其正确高度的截图。 enter image description here 编辑2 我的Unity版本是2018.1.3f1
当更新元素的实际高度时,我做错了什么?
如果有完全不同的方法可以做到这一点,我也可以接受对当前函数进行完全重写,如果需要的话 :)
如果有什么不清楚的地方,请让我知道,以便我可以澄清! 编辑3 我决定添加使用该函数的类的全部代码和调用各自函数的代码,也许存在导致错误的问题:
这是调用有问题的函数的代码:
var Title = new EasyText(new Vector2(390, -20), Vector2.zero, Data.title, 30, _color: new Color(0,0,0,1));
Title.SetTextContainerSize("autoH", 330);
Main.MainCanvas.Add(Title);

var titleBottom = (Title.Dimensions.y);
Debug.Log(titleBottom);

这是以上代码调用的类:
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System.Collections.Generic;

namespace Easy.UI
{

    public static class EasyUISettings
    {
        public struct AnchorPoints
        {
            public static readonly Vector2 TopLeft = new Vector2(0, 1);
            public static readonly Vector2 Center = new Vector2(0.5f, 0.5f);
            public static readonly Vector2 CenterLeft = new Vector2(0, 0.5f);
            public static readonly Vector2 CenterRight = new Vector2(1, 0.5f);
            public static readonly Vector2 TopCenter = new Vector2(0.5f, 1);
            public static readonly Vector2 BottomCenter = new Vector2(0.5f, 0);
        }

        public struct CoordinateReference
        {
            private CoordinateReference(int minX, int maxX, int minY, int maxY)
            {
                AnchorMin = new Vector2(minX, minY);
                AnchorMax = new Vector2(maxX, maxY);
            }

            public Vector2 AnchorMin { get; set; }
            public Vector2 AnchorMax { get; set; }

            public static readonly CoordinateReference TopLeft = new CoordinateReference(0, 0, 1, 1);
            public static readonly CoordinateReference TopRight = new CoordinateReference(1, 1, 1, 1);
            public static readonly CoordinateReference BottomLeft = new CoordinateReference(0, 0, 0, 0);
            public static readonly CoordinateReference BottomRight = new CoordinateReference(1, 1, 0, 0);

        }

        public struct TextAlignment
        {
            public static readonly TextAnchor TopLeft = TextAnchor.UpperLeft;
            public static readonly TextAnchor TopRight = TextAnchor.UpperRight;
            public static readonly TextAnchor TopCenter = TextAnchor.UpperCenter;
            public static readonly TextAnchor CenterLeft = TextAnchor.MiddleLeft;
            public static readonly TextAnchor CenterRight = TextAnchor.MiddleRight;
            public static readonly TextAnchor CenterCenter = TextAnchor.MiddleCenter;
            public static readonly TextAnchor BottomLeft = TextAnchor.LowerLeft;
            public static readonly TextAnchor BottomCenter = TextAnchor.LowerCenter;
            public static readonly TextAnchor BottomRight = TextAnchor.LowerRight;
        }
    }

    public static class EasyUIHelpers
    {
        public static void DestroyUIElement(EasyUIELementFoundation element)
        {
            element.DestroyUIElement();
            element = null;
        }
    }

    public class EasyCanvas
    {

        private GameObject CanvasObject, Events;
        private RectTransform Rect;
        private Canvas CanvasScript;
        private CanvasScaler Scaler;
        private GraphicRaycaster Raycaster;
        private StandaloneInputModule Inputs;
        private List<EasyUIELementFoundation> CanvasElements;

        public EasyCanvas()
        {
            CanvasElements = new List<EasyUIELementFoundation>();

            CanvasObject = new GameObject();
            CanvasObject.name = "EasyCanvas";
            Rect = CanvasObject.AddComponent(typeof(RectTransform)) as RectTransform;
            CanvasScript = CanvasObject.AddComponent(typeof(Canvas)) as Canvas;
            Scaler = CanvasObject.AddComponent(typeof(CanvasScaler)) as CanvasScaler;
            Raycaster = CanvasObject.AddComponent(typeof(GraphicRaycaster)) as GraphicRaycaster;

            CanvasScript.pixelPerfect = true;

            Events = new GameObject();
            Events.name = "EasyEventsHandler";
            Events.AddComponent(typeof(EventSystem));
            Inputs = Events.AddComponent(typeof(StandaloneInputModule)) as StandaloneInputModule;
        }

        public EasyCanvas(string _type, Camera c) : this()
        {
            CanvasScript.worldCamera = c;
            CanvasScript.planeDistance = 0.15f;

            if (_type.Equals("Camera"))
            {
                CanvasScript.renderMode = RenderMode.ScreenSpaceCamera;
                Scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
                Scaler.referenceResolution = new Vector2(1920, 1080);
                Scaler.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight;
            }
            else if(_type.Equals("World"))
                CanvasScript.renderMode = RenderMode.WorldSpace;
        }

        public void Add(EasyUIELementFoundation element)
        {
            element.AddToCanvas(CanvasScript);
            CanvasElements.Add(element);
        }

        public void EmptyCanvas()
        {
            for (int i = CanvasElements.Count - 1; i >= 0 ; i--)
            {
                CanvasElements[i].DestroyUIElement();
                CanvasElements[i] = null;
                CanvasElements.RemoveAt(i);
            }
        }

        public Vector2 GetCanvasDimensions()
        {
            return Rect.sizeDelta;
        }
    }

    public abstract class EasyUIELementFoundation
    {
        protected GameObject UIElement;
        protected RectTransform RectOptions;
        public Vector2 Position { get; private set; }
        public Vector2 Dimensions { get; private set; }
        public Vector2 PivotPoint { get; private set; }
        public EasyUISettings.CoordinateReference ReferenceCoordinates { get; private set; }

        protected EasyUIELementFoundation(Vector2 _position, Vector2 _dimensions)
        {
            UIElement = new GameObject();
            RectOptions = UIElement.AddComponent(typeof(RectTransform)) as RectTransform;
            SetPivotReference(EasyUISettings.AnchorPoints.TopLeft);
            SetCoordinateReference(EasyUISettings.CoordinateReference.TopLeft);
            SetPosition(_position);
            SetDimensions(_dimensions);
        }

        public void SetCoordinateReference(EasyUISettings.CoordinateReference reference)
        {
            RectOptions.anchorMin = reference.AnchorMin;
            RectOptions.anchorMax = reference.AnchorMax;
            ReferenceCoordinates = reference;
        }

        public void SetPivotReference(Vector2 reference)
        {
            RectOptions.pivot = reference;
            PivotPoint = reference;
        }

        public void SetPosition(Vector2 pos)
        {
            RectOptions.anchoredPosition = pos;
            Position = pos;
        }

        public void SetDimensions(Vector2 dimensions)
        {
            RectOptions.sizeDelta = dimensions;
            Dimensions = dimensions;
        }

        public void AddToCanvas(Canvas c)
        {
            UIElement.transform.SetParent(c.transform, false);
        }

        public void DestroyUIElement()
        {
            Object.Destroy(UIElement);
        }
    }

    public class EasyText : EasyUIELementFoundation
    {
        protected ContentSizeFitter UISizeFitterComponent;
        protected Text UITextComponent;
        public string Text { get; private set; }
        public Color TextColor { get; private set; }
        public Font TextFont { get; private set; }
        public int FontSize { get; private set; }
        public TextAnchor TextAlignment { get; private set; }

        public EasyText(Vector2 _position = default(Vector2), Vector2 _dimensions = default(Vector2), string _text = "Base Text", int _fontSize = 15, Font _font = null, Color _color = default(Color), TextAnchor _align = default(TextAnchor)) : base(_position, _dimensions)
        {
            UITextComponent = UIElement.AddComponent(typeof(Text)) as Text;
            SetText(_text);
            SetTextSize(_fontSize);
            SetFont(_font);
            SetTextColor(_color);
            SetTextAlignment(_align);
        }

        public void SetText(string text)
        {
            Text = text;
            UITextComponent.text = Text;
        }

        public void SetTextSize(int size)
        {
            FontSize = size;
            UITextComponent.fontSize = size;
        }

        public void SetFont(UnityEngine.Object font)
        {
            var ValidFont = (Font)font;
            if(ValidFont != null)
            {
                TextFont = ValidFont;
                UITextComponent.font = TextFont;
            }
            else
            {
                TextFont = Resources.GetBuiltinResource(typeof(Font), "Arial.ttf") as Font;
                UITextComponent.font = TextFont;
                Debug.LogWarning("No font was specified using default font");
            }
        }

        public void SetTextColor(Color color)
        {
            TextColor = color;
            UITextComponent.color = TextColor;
        }

        public void SetTextAlignment(TextAnchor alignment)
        {
            TextAlignment = alignment;
            UITextComponent.alignment = alignment;
        }

        public void SetTextContainerSize(string fit, float dimension = 0)
        {
            if (UIElement.GetComponent<ContentSizeFitter>() == null)
                UISizeFitterComponent = UIElement.AddComponent(typeof(ContentSizeFitter)) as ContentSizeFitter;

            if (fit == "autoWH")
            {
                UISizeFitterComponent.horizontalFit = ContentSizeFitter.FitMode.PreferredSize;
                UISizeFitterComponent.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
                base.SetDimensions( RectOptions.sizeDelta);
            }
            else if (fit == "autoW")
            {
                UISizeFitterComponent.horizontalFit = ContentSizeFitter.FitMode.PreferredSize;
                UISizeFitterComponent.verticalFit = ContentSizeFitter.FitMode.Unconstrained;
                base.SetDimensions( new Vector2(RectOptions.rect.width, dimension));
            }
            else if (fit == "autoH")
            {
                UISizeFitterComponent.horizontalFit = ContentSizeFitter.FitMode.Unconstrained;
                UISizeFitterComponent.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
                // THIS NEEDS A FIX OMG
                // LayoutRebuilder.ForceRebuildLayoutImmediate(RectOptions);
                Canvas.ForceUpdateCanvases();
                UISizeFitterComponent.SetLayoutVertical();
                base.SetDimensions( new Vector2(dimension, RectOptions.rect.height));
            }
        }

        public void RemoveContentSizeFitter()
        {
            var component = UIElement.GetComponent(typeof(ContentSizeFitter)) as ContentSizeFitter;
            if(component != null)
                Object.Destroy(component);
        }
    }
}

1
你尝试过将UISizeFitterComponent.horizontalFit设置为Unconstrained吗?它可能仍然被设置为PreferredSize。 - Immorality
我可以问一下为什么获取正确的高度很重要吗? - FutureCake
我猜没有内容,可能是代码读错了。 为了诊断问题,您能否发一下SetDimensions方法? - Immorality
添加了SetDimensions函数。 - FutureCake
1个回答

1

经过数小时的努力寻找解决方案,我终于找到了它。

其实这是一个非常愚蠢的错误。

以下是解释:

我以以下方式初始化我的自定义UIText类:

var Title = new EasyText(new Vector2(390, -20), Vector2.zero, Data.title, 30, _color: new Color(0,0,0,1));

注意文本元素的Vector.zero尺寸?是的,这将会引起一些问题。
因为我接下来调用了刚创建的标题元素上的这个:
Title.SetTextContainerSize("autoH", 330);

这会调用我的尺寸适配器更新函数,请参见下面的内容:
public void SetTextContainerSize(string fit, float dimension = 0)
    {
        if (UIElement.GetComponent<ContentSizeFitter>() == null)
            UISizeFitterComponent = UIElement.AddComponent(typeof(ContentSizeFitter)) as ContentSizeFitter;

        if (fit == "autoWH")
        {
            UISizeFitterComponent.horizontalFit = ContentSizeFitter.FitMode.PreferredSize;
            UISizeFitterComponent.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
            base.SetDimensions( RectOptions.sizeDelta);
        }
        else if (fit == "autoW")
        {
            UISizeFitterComponent.horizontalFit = ContentSizeFitter.FitMode.PreferredSize;
            UISizeFitterComponent.verticalFit = ContentSizeFitter.FitMode.Unconstrained;
            Canvas.ForceUpdateCanvases();
            base.SetDimensions( new Vector2(RectOptions.rect.width, dimension));
        }
        else if (fit == "autoH")
        {
            UISizeFitterComponent.horizontalFit = ContentSizeFitter.FitMode.Unconstrained;
            UISizeFitterComponent.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
            Canvas.ForceUpdateCanvases();
            base.SetDimensions( new Vector2(dimension, RectOptions.rect.height));
        }
    }

在适合值为autoW或autoH的情况下,程序将添加内容大小调整器,但由于元素的大小因初始化而为0。内容大小调整器将使元素扩展到极限,因为另一个大小只是0。 然后我更新画布,但这并没有做任何事情,因为元素的宽度或高度为0。导致在获取值时出现巨大的数字。那么如何解决这个问题? 只需确保在添加内容大小调整器之前,元素具有一定的宽度或高度,如下所示:
public void SetTextContainerSize(string fit, float dimension = 0)
    {
        if (UIElement.GetComponent<ContentSizeFitter>() == null)
            UISizeFitterComponent = UIElement.AddComponent(typeof(ContentSizeFitter)) as ContentSizeFitter;

        if (fit == "autoWH")
        {
            UISizeFitterComponent.horizontalFit = ContentSizeFitter.FitMode.PreferredSize;
            UISizeFitterComponent.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
        }
        else if (fit == "autoW")
        {
            base.SetDimensions(new Vector2(dimension, dimension));
            UISizeFitterComponent.horizontalFit = ContentSizeFitter.FitMode.PreferredSize;
            UISizeFitterComponent.verticalFit = ContentSizeFitter.FitMode.Unconstrained;
            Canvas.ForceUpdateCanvases();
            base.SetDimensions( new Vector2(RectOptions.rect.width, dimension));
        }
        else if (fit == "autoH")
        {
            base.SetDimensions(new Vector2(dimension, dimension));
            UISizeFitterComponent.horizontalFit = ContentSizeFitter.FitMode.Unconstrained;
            UISizeFitterComponent.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
            Canvas.ForceUpdateCanvases();
            base.SetDimensions( new Vector2(dimension, RectOptions.rect.height));
        }
    }

这解决了我的问题。我真的希望这能帮助到未来的任何人!
如果您不理解任何内容,请留下评论,以便我澄清我的答案:)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接