- Home /
Problem with centering text
Hi,
Here's the problem I've run into. I am doing an iOS card based 2D game. Since it's card-based it has a number of cards in it. Each card has about 3 to 6 lines of text.
I am using GUI.Label to show the text, and it's centering using the alignment setting in my GUIStyle. So far so good, everything is working fine, the text is presented as it should, and it's centered. HOWEVER... this happens with the text on many of my cards.
"This is a centered text meant
to show my problem regarding
centering of text. The problem
is that sometimes it looks like
this."
Last line? Not so good... just one word appears on the last line. Sometimes it's two, sometimes it's three, sometimes it ends up looking good. All lines are filled with as many words that fit, and the last line will simply hold as many words that are left to show, no matter if it looks good or not. This isnt exactly wrong, thats how word processors do it. But... its not very nice looking. I want it to look like this:
"This is a centered text meant
to show my problem regarding
centering of text. This is how
I would like it to look. Good!"
EVENLY centered text.
I store each card tex in a string, one big line of text, I could manually add a bunch of newlines in every string of course, but that would be painfully slow to do since there's a lot of cards, and if I wanted to change some text later I'd need to manually align it again.
So anyone has a suggestion how to automatically align a centered text evenly?
Thanks
Answer by Coderdood · May 23, 2013 at 09:54 PM
This is actually quite a bit harder than I thought but here is my stab at it. First some disclaimers:
Disclaimers
This code is more of a 'proof of concept' and probably could be optimized / improved quite a bit and isn't the type of thing you should really run every frame.
There are scenarios in which this code generates similar bad looking text as unity depending on the length of the words in the text / etc. It might be possible to improve this by allowing words to be broken into pieces but for readability I suggest keeping words intact.
Full Test Code
The following code draws two text boxes - the one on the left uses Unity3D standard label the other one uses some code to format the text before drawing. I added a button so that you can toggle between growing / shrinking the labels to see how the word wrap works at various sizes.
using UnityEngine;
using System.Collections;
public class TestDraw : MonoBehaviour
{
Vector2 area = new Vector2(275.0f, 200.0f);
bool grow = false;
void OnGUI()
{
// Common content
string testContent = "This is a centered text meant to show my problem regarding centering of text. The problem is that sometimes it looks like this.";
if(!grow) { area.x -= 0.05f; } else { area.x += 0.05f; }
// Bad text alignment
Rect badDisplayArea = new Rect(5.0f, 5.0f, area.x, area.y);
GUI.skin.label.alignment = TextAnchor.MiddleCenter;
GUI.Box(badDisplayArea, "");
GUI.Label(badDisplayArea, testContent);
// Good text alignment
Rect goodDisplayArea = new Rect(area.x + 10.0f, 5.0f, area.x, area.y);
GUI.skin.label.alignment = TextAnchor.MiddleCenter;
GUI.Box(goodDisplayArea, "");
DrawCenteredText(testContent, goodDisplayArea);
// Toggle shrinking / grow
if( GUI.Button(new Rect( 5.0f, area.y + 50.0f, 50.0f, 50.0f), "Toggle\nGrow")) { grow = !grow; }
}
// Note this function will only be work inside an OnGUI method or inside of another method used by OnGUI
private void DrawCenteredText(string textToDraw, Rect textArea)
{
// Get the style we are using for the text
GUIStyle getStyle = GUI.skin.GetStyle("Label");
// Store text alignment
TextAnchor storeAlignment = getStyle.alignment;
getStyle.alignment = TextAnchor.MiddleCenter;
// Create the content object to prevent duplicate 'new GUIContent(textToDraw)' calls
GUIContent textContent = new GUIContent(textToDraw);
// Figure out the width of the text without clipping it
float textWidth = getStyle.CalcSize(textContent).x;
// Figure out the height of the text with clipping
float textHeight = getStyle.CalcHeight(textContent, textArea.width);
// Figure out the average line width
float lineCount = (textHeight / getStyle.lineHeight) - 0.25f; // Modify 0.25f for fine tuning
float averageLineWidth = textWidth / lineCount;
// Go through and construct the centered text
string resultText = "";
string centeredLine = "";
float currentLineWidth = 0.0f;
string[] wordsInText = textToDraw.Split(' ');
for(int i = 0; i < wordsInText.Length; i++)
{
float wordSize = getStyle.CalcSize(new GUIContent(wordsInText[i])).x;
// Add the line if the word will make it go over
if(currentLineWidth + wordSize > averageLineWidth)
{
// Add the line to the result
resultText += centeredLine + "\n";
// Reset line and width
centeredLine = "";
currentLineWidth = 0.0f;
}
currentLineWidth += wordSize;
centeredLine += wordsInText[i] + " ";
}
// Add the line to the result
resultText += centeredLine;
// Draw the text
GUI.Label(textArea, resultText);
// Restore alignment
getStyle.alignment = storeAlignment;
}
}
What Does The Code Do?
My approach was to find out how wide text being displayed is along with how many lines the text is being displayed over and then figure out an average line width and add a new line to any line that will be larger than the average line width.
Knowing that the code should be somewhat self explanatory (I hope).
Thanks alot for this really great answer. I was thinking of a similar solution, and I love that you have made it work!
I am gonna have a go at it now, using your code as a base. I will tell you how it went!
Hi again. Just thought I should post an update and say thank you again.
I didnt use your actual code in the end, but it was a great help in writing my own javascript. It basically does the same thing like yours and works in a very similar way, just slightly adapted to fit with my specific needs. I also changed so it doesnt have to run inside a GUI function to save some resources, ins$$anonymous$$d you need to manually enter the maximum line width you want. It works fine for me as my maximum line width always stays the same. But you can probably make that automatic too if you want.
Anyway, big thanks again!
And if someone find themselves here looking for an answer to the same problem I had, the solution above by Coderdood works fine, and its not very difficult to adjust it if you need, or convert it to javascript.
Your answer
Follow this Question
Related Questions
Using "fonts" that are actually images for a multi-outline effect. 2 Answers
Unity GUI text displaying as noise 1 Answer
Text rendering bug. Shows black squares. -1 Answers
iOS performance: GUItext? want to use text string, but how to instantiate and edit it runtime? 0 Answers
GUI Label Width & Height 0 Answers