- Home /
How do I calculate a text size with the Best Fit option using a TextGenerator
My goal is to link several Text components that they all have the same text size. Text size should be the minimum 'best fit' size of all components.
How I try to achieve it is by turning the 'best fit' option off and calculate the size with a custom TextGenerator, copying all TextGenerationSettings from the original Text components.
My Problem is: The calculated Text size is too small. It adjusts according to the RectTransform size, but is just wrong. Any thoughts about this?
Here is the code:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.EventSystems;
[ExecuteInEditMode]
public class kgLinkedBestFit : UIBehaviour
{
public int minTextSize = 5;
public int maxTextSize = 35;
public Text[] linkedTexts;
//TEMP: Editor Update
public void Update()
{
TextGenerator textGenerator = new TextGenerator();
int minimumBestFit = 1000;
foreach(Text t in linkedTexts)
{
//get current text generation settings for the text field
TextGenerationSettings settings = t.GetGenerationSettings(t.rectTransform.rect.size);
//change to best fit settings
settings.resizeTextForBestFit = true;
settings.resizeTextMinSize = minTextSize;
settings.resizeTextMaxSize = maxTextSize;
//calcuclate with text generator
textGenerator.Populate(t.text,settings);
//set new bestFit if new calculation is smaller than current bestFit
minimumBestFit = textGenerator.fontSizeUsedForBestFit < minimumBestFit ? textGenerator.fontSizeUsedForBestFit : minimumBestFit;
}
/*at this stage minimumBestFit is calculated too small. When the original textfield is set to best fit, the text size will be 22, the calculated text size is only 12*/
foreach(Text t in linkedTexts)
{
//adjust font sizes
t.fontSize = minimumBestFit;
}
}
}
Answer by hugojacob · Nov 25, 2015 at 09:19 AM
Hey.Old post, but for others i will answer.
I ran into the same problem. When using fontSizeUsedForBestFit variable the size returned did not match in the editor. After a long research the short answer to the problem is to divide the fontsize with the your canvas scale factor like this:
fontsize = fontsize / canvas.scaleFactor;
hope this helps others.
It sure did help!
Here's my full code for getting the current dynamic font size. Place these in a public static class.
public static int GetCurrentDynamicFontSize(this Text text)
{
if (text == null) return -1;
float multiplier = 1;
Canvas canvas = text.GetHighestCanvas();
if (canvas)
multiplier = 1 / canvas.scaleFactor;
return (int)(text.cachedTextGenerator.fontSizeUsedForBestFit * multiplier);
}
public static Canvas GetHighestCanvas<T>(this T component) where T : Component
{
if (component == null) return null;
Canvas[] parentCanvases = component.GetComponentsInParent<Canvas>();
if (parentCanvases != null && parentCanvases.Length > 0)
{
return parentCanvases[parentCanvases.Length - 1];
}
return null;
}
Answer by Gwom · Apr 19, 2017 at 03:09 PM
In case anyone else wants it, you have to wait a frame so the fontSizeUsedForBestFit gets calculated. I get consistant size of an item by adding anything I want to an array in the inspector and on play, wait a frame, find the size and apply it:
using UnityEngine.UI;
/// <summary>
/// Cant work in editor, but will when the play button is pressed
/// </summary>
public class ConsistantTextSize : MonoBehaviour {
public Text[] m_TextList;
private int m_Size = 1;
// Use this for initialization
void Start () {
SetSizes();
}
public void SetSizes()
{
foreach (var item in m_TextList)
item.resizeTextMaxSize = 1000;
StartCoroutine(WaitFrame());
}
public IEnumerator WaitFrame()
{
// returning 0 will make it wait 1 frame
// need to wait a frame in order for the layout to work out the size
yield return 0;
ApplySizes();
}
public void ApplySizes()
{
// Get the first one
if (m_TextList.Length > 0)
m_Size = m_TextList[0].cachedTextGenerator.fontSizeUsedForBestFit;
// See if any are smaller
foreach (var item in m_TextList)
{
if (item.cachedTextGenerator.fontSizeUsedForBestFit < m_Size)
m_Size = item.cachedTextGenerator.fontSizeUsedForBestFit;
}
// Apply as max size to all of the images
foreach (var item in m_TextList)
item.resizeTextMaxSize = m_Size;
}
}