Get height of UI text element not correct Unity

Viewed 2088

I have some code to set a custom with for a text element and then the height gets adjusted automatically like so:

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));
        }
    }

Edit Added the set dimensions function

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

but when i call the function to update the text i get the following result from the Debug.Log() it says the width = 330 and the height is 2077. In this case the width is correct but the height is not even close.

See here a screenshot of the actual element and its correct height. enter image description here

Edit 2 My unity version is 2018.1.3f1

what am i doing wrong when updating the actual height of the element?

If there is an completely other way to do it i am also open for complete rewrites of the current function if nessesary :)

IF something is unclear let me know so i can clarify!

Edit 3 I decided to add the full code of the classes that use the fuction and the code that calls the respective function, Maybe there is a problem that causes the error:

this is the code that calls the problametic function:

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

This is the classes that are called by the above code:

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 Answers

after spending hours upon hours trying to find a solution i finally found it..

It was actually a really stupid mistake.

Here is an explaination:

I initiated my custom UIText class in the following way:

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

Notice the Vector.zero for the dimensions of the text element? yeah that is gonna cause some problems.

Because the following i did was call this, on the just created title element:

Title.SetTextContainerSize("autoH", 330);

this would call my size fitter update function see below:

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));
        }
    }

In the cases the fit value is either autoW or autoH the program will add the content size fitter but since the size of the element is 0 because of the initialization. The content size fitter is gonna expand the element to the extreme because the other size is just 0. Then i update the canvases but this doesnt do anything because the element has a width or height of 0. Resulting in the huge numbers when getting the values back. So how to fix this?

Just make sure the element has some width or height before adding the content size fitter like so:

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));
        }
    }

and that solved my problem. I really hope this helps anyone in the future!
If you dont understand anything, drop a comment so i can clarify my answer :)

Related