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

Posted

技术标签:

【中文标题】获取 UI 文本元素的高度不正确 Unity【英文标题】:Get height of UI text element not correct Unity 【发布时间】:2018-09-05 14:43:25 【问题描述】:

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

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。在这种情况下,宽度是正确的,但高度甚至不接近。

在此处查看实际元素及其正确高度的屏幕截图。

编辑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);
        
    

【问题讨论】:

您是否尝试过将 UISizeFitterComponent.horizo​​ntalFit 设置为不受约束?它可能仍设置为 PreferredSize 我可以问一下为什么这与获得正确的高度有关吗? 没什么,没看懂代码。但是为了诊断问题,您可以发布 SetDimensions 方法吗? 添加了 SetDimensions 函数 【参考方案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));
        
    

在 fit 值是 autoW 或 autoH 的情况下,程序将添加内容大小 fitter 但由于初始化,元素的大小为 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));
        
    

这解决了我的问题。我真的希望这对将来的任何人都有帮助! 如果您有任何不明白的地方,请发表评论,以便我澄清我的答案:)

【讨论】:

以上是关于获取 UI 文本元素的高度不正确 Unity的主要内容,如果未能解决你的问题,请参考以下文章

UI 元素无法正确缩放

获取是不是按下 Unity UI 元素 [重复]

反应:如何获得一个元素高度,消失并以新大小出现

计算 SVG 文本高度和宽度的正确方法

在 Unity UI Builder 中动态更改视觉元素的背景图像

如何在具有特定宽度和高度的矩形中获取 svg 文本元素?