- Home /
How to get the width of UI Text with Horizontal Overflow?
I'm looking for a way to get the width of a new UI Text width Horizontal Overflow = Overflow. I need the width to position other objects (like custom Image bullet points at the start of a centered text line) according to the with of the text. The Width of the RectTransform is unchanged when the text displayed is wider than the RectTransform size.
Not got access to unity so cant test this but ins$$anonymous$$d of letting the text overflow the edge put a content size filter on it. Set horizontal to preferred and it should expand the rect transform.
So you can get the size direct from the recttransform.
Thanks a lot! Even if it's not the anser to my question it was an excellent solution to my problem!
Answer by Glurth · Feb 11, 2015 at 03:17 PM
http://docs.unity3d.com/ScriptReference/Font.GetCharacterInfo.html
This function will allow you to determine the size of any particular character, in a given font. You can create a loop to go through your string and add up all the character widths.
(but I think you will be better off with the suggestion posted in the comment, by mmmpies, about how to expand the rect transform automatically. Had no idea about that option myself, thanks Pie.)
thanks! seems like a proper way to do it. Like you suggest, I'll think i stay with mmmpies approach.
No problem @mpete and @Glurth it never hurts to know more than one way to do something so good answer.
You might also want to mess with the pivot point @mpete, say you drag the pivot to the left center then the text will grow out from that point. Handy if aligning multiple texts to either left or right.
$$anonymous$$any thanks Glurth, I post my own method for who needs help:
int CalculateLengthOf$$anonymous$$essage(string message)
{
int totalLength = 0;
Font myFont = chatText.font; //chatText is my Text component
CharacterInfo characterInfo = new CharacterInfo();
char[] arr = message.ToCharArray();
foreach(char c in arr)
{
myFont.GetCharacterInfo(c, out characterInfo, chatText.fontSize);
totalLength += characterInfo.advance;
}
return totalLength;
}
looks good! $$anonymous$$ay I suggest you make the 14 into a parameter?
Why not, i changed the constant to text field ^^
I was looking the same issue and tried this code, but "chatText.fontSize" return constant font size, not after the "best fit" text function. So, for all next seekers, I will add my comment. The answer is to use "Text.cachedTextGenerator.fontSizeUsedForBestFit"
https://answers.unity.com/questions/784199/how-to-get-the-current-best-fit-size-of-a-text-com.html
Answer by green-coder · Apr 25, 2015 at 05:38 AM
You can get the width of the text in the limits of the RectTransform of his own GameObject via scripting by using:
GetComponent<Text>().preferredWidth
It works if you have the "horizontal overflow" option set.
If you want to uncheck it, then you will need to enlarge the RectTransform or the text will wrap to more than 1 line and you will get the width of the set of lines instead : this can be done using a "Content Size Fitter", as explained in the other answers.
I can confirm this works. (Thanks!) I also think it is a more direct way of arriving at the width than the solution of measuring each character. The text component can have other properties affecting layout. It should be the authority on how much space its text will occupy.
Answer by DiegoSLTS · Feb 11, 2015 at 05:03 PM
Maybe you're doing it the wrong way. You're getting the width of the text because the width doesn't change when the text overflows, but there's a way to make it change according to the text width (so the overflow configuration is not needed). Add a "Content Size Fitter" component to the same game object with the Text component, and set "Horizontal Fit" to "Preferred size". The gameObject's size will change according to the pivot, set pivot.x to 0.5 and it will be centered.
This way the width will change, so you just have to set the image as a child game object of the text, and place it at the start.
I like this feature, but it has one flaw: The final value size of the transform is not updated until next frame, so you cannot trust on the sizes of the RectTransform when you ask for them.
$$anonymous$$y workaround is to use Coroutines:
I change the text on the Label
Then Starting a Coroutine with a yield return null that delays one frame:
private void SetLbl(int amount) { _lbl.text = amount.ToString (); StartCoroutine (SetLblDelayed ()); } private IEnumerator SetLblDelayed() { //Wait a frame until you can use the new width (sizeDelta.x) of the Label yield return null; Vector3 pos = otherTransform.localPosition; pos.x = _lbl.transform.localPosition.x + _lbl.GetComponent<RectTransform>().sizeDelta.x otherTransform.localPosition = pos; }
I used this method with a state machine all inside of Update().
//This layout worked for me using the ContentSizeFitter that takes a frame to load.
//Sample visual novel text box engine layout
public enum State { Idle, Start, Preload, Init, OpenAni, ScrollText, CloseAni, End }
public State state;
int PreloadTimer = 0;
Update() {
switch (state) {
case State.Idle:
//wait for trigger...
break;
case State.Start:
start_SetPreloadTimer(5); //preload for 5 frames
break;
case State.Preload:
preload_CountTimerDown();
break;
case State.Init:
init_initializeValues();
break;
etc etc....
}
}
// ------------------------------------- $$anonymous$$ETHODS ------------------------------
private void start_SetPreloadTimer(int Frames) {
PreloadTimer = Frames;
state = State.Preload;
}
private void preload_CountTimerDown() {
if (PreloadTimer > 0)
PreloadTimer--;
if (PreloadTimer == 0)
state = State.Init;
}
A state machine might not even need you to preload at all, because it won't run at first anyway, so it's ideal in that way. Preloading could be only if the game has just loaded and it's triggered or something, or you could make a static timer count down like a firstLoadTimer or something I don't know.
Answer by Bezzy · Aug 09, 2015 at 04:21 PM
There are some other small issues with this - the rect does not update until the next render frame, and as a result you can't do sub-string positioning things. I'm trying the font.GetCharacterInfo approach, but there's a lot to worry about. Not as simple as just adding char-widths together.
[edit]
public static float GetSizeOfWord(Text text, string word)
{
float width = 0.0f;
CharacterInfo charInfo;
foreach (char c in word)
{
text.font.GetCharacterInfo(c, out charInfo, text.fontSize);
width += charInfo.advance;
}
return width;
}
^ This is not quite right. I don't exactly know whether to use .advance or .glyphWidth
I'm also going to try changing the text, and forcing the text meshes to update using "Canvas.ForceUpdateCanvases()", and then sampling the size, but this could be a huge performance hit on a large canvas.
True, not quite THAT simple, tabs in particular are tricky, also don't forget to check for cr/lf before adding a char width. But leaving out tabs, I found this in my code that works (inside a loop where I increment through "c" used below), perhaps it will help you..
if (!font.GetCharacterInfo(word[c], out fontCharInfo, (int)charFontSize, charStyle))
{
Debug.Log("failed to get font char info for : " + word[c]);
return;
}
charWidth = fontCharInfo.advance / 10.0f;
charWidth *= text$$anonymous$$esh.characterSize;
(I think, but don't hold me to it, that glyphWidth is the width WITHOUT the spacing that normally goes between letters. also, note that there is some weirdness with computing the height of the text: http://answers.unity3d.com/questions/932474/unitys-textmesh-fontlineheight-and-the-number-975f.html)
Your answer
Follow this Question
Related Questions
Display text above prefabs in Unity 4.6 0 Answers
UI: Loading the text in a Text type with a String? 1 Answer
Graphic problem with UI Text 2 Answers
What's your equivalent of old GUIStyle ? 0 Answers
UI Text compression on android 1 Answer