Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles

Unity UI Alignment woes

A topic by nospoone created 7 days ago Views: 62 Replies: 8
Viewing posts 1 to 10
(1 edit)

Hey!

Thanks again for STM, been a user for a wee bit (we even talked before!) and it has worked wonders for me. I unfortunately come to you today with a problem. 

Context
I have a simple screen with some text in it:


This looks great, however when I want to localize the text, things get hairy. Here is the code I use to localize my text:

using UnityEngine;
using I2.Loc;
[RequireComponent(typeof(SuperTextMesh))]
public class VSScreenTextHelper : MonoBehaviour {
    public string LocalizationString;
    private SuperTextMesh textMesh;
    
    void Awake () {
        textMesh = GetComponent<SuperTextMesh>();
        textMesh.Text = LocalizationManager.GetTermTranslation(LocalizationString);
    }
}

Pretty simple, yeah? This script is attached to the GameObject that has the STM component on it, which is a UI object (it has a RectTransform). The code puts in a new string inside STM's Text property and sends it on its way. Yet, as you might have already realized, problems arise.

Problem
When setting Text on an STM instance via code on a UI object, STM loses its alignment until any property is triggered in the inspector. Below is a gif of the process.


What I've tried
I tried a couple things before coming on these here forums to ask for help:

  • Messing with the parent's layout options
  • Using content size fitters
  • Triggering Rebuild() after changing the text
  • Toggling options via code, and then Rebuild()ing

I would love to dive into STM's codebase to figure it out but unfortunately with a big deadline looming above my head it's impossible for me to do so. I hope I provided enough information for you to be able to have at least a vague idea of what's going on.

Thanks for any help you can provide!

Developer

Does it make a difference when you put that function under Start() instead of Awake()?

(1 edit)

Calling Rebuild() unfortunately doesn't do it, as well as putting the method under Start(). 🤔

Thanks for taking the time to look into this 😊

Developer

Would it be possible to get a screenshot of the scene view? I'm curious how STM's bounding boxes are set up with Unity UI. I'm currently still unable to reproduce this, would it be possible to set me a sample project that recreates the bug?

Here's an example project, just add STM and it should reproduce correctly!

Developer

Ok awesome, I'm able to repro it. I'll see what I can do!

Developer

Hey! I'm halfway through solving the problem.

When autoWrap is defined, instead of setting the UI Autowrap value to be "(float)tr.rect.width" I'm setting it to be "preferredWidth" (a value set by Unity UI) and it seems to make the text appear on one line as expected.


That said, text still has an offset applied to it until it's updated. (Even turning on reading and setting the mesh to read all at once didn't fix this) but strangely enough, the text bounds are *half* correct. The blue box that's supposed to be the bounds are set incorrectly, but the yellow box defining the text mesh's actual size is accurate to where the text *should* be.


I've got to head out right now, but hopefully I can use that info to track this down asap!

(1 edit)

Great find! That makes sense - it made me remember something about TextMeshPro's Rebuild() which is passing in a `UnityEngine.UI.CanvasUpdate` value. From that, I tried calling `Canvas.ForceUpdateCanvases();` just before setting the text (so before triggering a Rebuild()) and it worked. My script looks like this now:

using UnityEngine;
using I2.Loc;
    
[RequireComponent(typeof(SuperTextMesh))]
public class VSScreenTextHelper : MonoBehaviour {
    public string LocalizationString;
    private SuperTextMesh textMesh;
    
    void Start () {
        textMesh = GetComponent<SuperTextMesh>();
        Canvas.ForceUpdateCanvases();
        textMesh.Text = LocalizationManager.GetTermTranslation(LocalizationString);
    }
}

This makes me think that this is happening only because I'm calling it inside the Start/Awake function. As per docs (emphasis mine):

A canvas performs its layout and content generation calculations at the end of a frame, just before rendering, in order to ensure that it's based on all the latest changes that may have happened during that frame. This means that in the Start callback and the first Update callback, the layout and content under the canvas may not be up-to-date.

Code that relies on up-to-date layout or content can call this method to ensure it before executing code that relies on it.

I hope this can lead you to a potential implementable solution inside STM! Cheers!

Developer

Hey!


That's awesome, thank you so much for finding this... Unity UI has so many specifics to it, I probably wouldn't have found this myself. I'll make is so that always gets called when Rebuild() gets called. It seems to solve it!


Thank you!