I have a string that can be anything and I have a text object in my scene which has a set width and a changeable height.
Is there a built-in function that counts how many rows my string would have in that text object so that I can adjust the height of it? I want to do this because I need a background only at the text and not anywhere else.
I want to do this because I need a background only at the text and not anywhere else.
It appears to me that this should be able to solve your problem:
In order to make a Rect Transform with a Text component on it fit the text content, add a Content Size Fitter component to the same Game Object which has the Text component. Then set both the Horizontal Fit and Vertical Fit dropdowns to the Preferred setting.
In your case you want to control the Horizontal but not the vertical, so try set the Vertical setting to "Preferred".
If this does not work directly on your text component you may want to make the text component a child of the grey panel box and then add the contentfitter to it as well.
Source: https://docs.unity3d.com/Manual/HOWTO-UIFitContentSize.html
Disclaimer: I didn't test this Component based attempt, but I believe it may be the solution or lead you closer to one.
While Doh09's answer is certainly accurrate, you can also query the UI.Text.preferredHeight property, asking the Text object how tall the text is and using that value to change the size of your background object yourself.
Of course, both answers assume you are using the New UI text and not TextMesh or OnGUI. If you are not using the New UI, then I suggest changing to using the New UI.
You can see an example usage of this in my own project here where I compute the text's desired width and height and modify the RectTransform until the object's preferred size is within a layout-preferred ratio. Here's one of the final sections (with some alterations to make it understandable):
Text t = <some Text object>
float height = t.preferredHeight;
float width = t.preferredWidth;
((RectTransform)tooltipGO.transform).SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, (width / 4) + 8);
((RectTransform)tooltipGO.transform).SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, (height / 4) + 7.5f);
The divide-by-four and offsets to account for relative scaling between the text and the background and some edge padding.
Related
Say you have a label. This label sits inside a container, lets say a TableLayoutPanel for argument. You dont always know the amount of text that the label will hold. It can be a few words or it can be a whole paragraph. You cant resize the TableLayoutPanel cell because its already at the perfect size.
You need a Big Font size for few words but a smaller Font size for larger pieces of text.
One problem though, the text can wrap.
How would one find the largest font size that would make the text fit snugly in the provided container?
I had to deactivate the text wrapping for starters.
I then got the size of the container in pixels. With that, i have the bounding box the font must fit in.
I then got the label size.
If the label is biger than the container, i incrementally made the font smaller.
If the label is smaller than the container, i incrementally made the font bigger.
I did this until the label fit inside the container. One issue though, the label can get very small if there are lots of text.
It took ages but I managed to figure out an elegant solution (kinda) and I wanted to share my "discoveries"
For starters, I re-enabled wrapping via the AutoSize (property this is important).
Then I got the height of the container, the width is no longer important.
I set the Anchor property to Top | Left | Right, meaning that the label will sit at the top and flow downwards.
Then I made the font size waaaaay too big for the text provided - it must overflow and hide text.
A sneaky quirk of this arrangement is that the label will overflow to outside the container but the overflowed text won't be visible. The size of the label will be exactly the height of the container, despite overflowing and having text missing. This same height can be used to our advantage.
If you then make the text smaller bit by bit, there will come to a point where the label height will no longer match its original height and get smaller. At that moment, you can stop because you have the perfect font size. The label will no longer overflow and the text will comfortably sit in the container.
Some code:
//get the height of the tabeLayoutPanel cell that serves as the container
float maxHeightClearance = tableLayoutPanelMain.RowStyles[4].Height;
//get the height of the label and save it for comparison later
float labelHeight = labelCourseName.Size.Height;
//for as long as the label height remains unchanged, it means that it is still too big
while(labelCourseName.Size.Height == labelHeight)
{
//slowly decrease the font size
labelCourseName.Font = new Font(labelCourseName.Font.Name, labelCourseName.Font.Size - 0.2f, labelCourseName.Font.Style, labelCourseName.Font.Unit);
//refresh the GUI to see if anything changed. This is nearly instantaneous
Application.DoEvents();
}
here is my problem:
I want to have a bunch of Text-GameObjects to be evenly distributed across the screen horizontally.
So I took a Layout-Group and added it onto a Panel, which is streched across the screen, with the following settings:
Panel Settings
(The Layout Element on the Panel is not important here, I think, but the Panel itself is controlled by another Object to stretch across the Screen)
Now, I add the Text-GameObjects via Script. That looks like that:
days[i].transform.SetParent(GameObject.Find("Day Panel").transform);
days[i].AddComponent<Text>();
days[i].transform.GetComponent<Text>().font = (Font)Resources.GetBuiltinResource(typeof(Font), "Arial.ttf");
days[i].transform.GetComponent<Text>().fontSize = 25;
days[i].transform.GetComponent<Text>().color = Color.black;
days[i].transform.GetComponent<Text>().alignment = TextAnchor.UpperCenter;
days[i].transform.GetComponent<Text>().text = shownDates[i].Day.ToString();
days[i].transform.localScale = new Vector3(1, 1, 1);
days[i].transform.localPosition = new Vector3(0, 0, 0);
Now I have the problem, that the width of the text-GameObjects is influenced by the length of the string I show with them. So if a text-GameObject has a 3-char-long string in it, it is wider than a text-GameObject next to it with a one-char-long string. But I need to distribute the width "fairly" between the Text-Objects, independently from what's inside.
I hope, that you can help me, Thanks :D
Making my comment an answer as it answers your question. You have two options to solve your issue.
The first I provided is not as robust and not modular that will work if you know the number of child objects at compile time. You can utilize the field minWidth of a LayoutElement. By setting this value as the width each element needs to be to evenly fill the space, the text object will be no smaller than the value you give it. However, if you ever add any new objects to your layout group at runtime or at any other time, you would need to recalculate these values so it is not a great solution.
The second solution which would allow for almost no work by you is to add an empty parent RectTransform to fill the space above the text object. With the layout group forcing the width and height to expand to the container, each RectTransform will fill the space evenly, while the childed text can be whatever size it needs to be. Here is the hierarchy setup of this solution:
And here is the solution working:
In the example, the parent objects are panels with Image components. I only did this to show that there is a divide between each object like you want. You can remove this component and still have the object retain its structure.
I want to create a plot that dynamically displays active elements as rectangles. I have achieved a first version that is actually ok using OxyPlot.Annotations.RectangleAnnotation which I add to myPlotModel.Annotations, you can see it in the image hereafter:
Example of wanted display
The thing is that after a while, the amount of drawn rectangles make the update not smooth as I update the shown timewindow (which is set to 15 seconds). I have already set a maximum of drawn elements that suffice to cover the displayed window (i.e. the rectangles get removed as they are too far in the past), but the rendering is still jerky. I draw the rectangles by allocating them to an equal fraction of the Y-axis, that is the third one from the top gets:
rowNumber= 3.0
minimumY = maximalY - maximalY / totalElements * rowNumber
maximumY = maximalY - maximalY / totalElements * (rowNumber + 1.0)
And the Y-axis is hidden.
My question:
Is there a smarter way of creating such a display that would be less computationally heavy, and therefore allow a smoother update? I do not have to stick to OxyPlot, it is simply the easiest way that I found to obtain what I wanted.
Thanks for your answers!
Technically, the answer to your question is "Yes".
There are a number of ways to do this.
You could have a vertical itemscontrol that had an itemscontrol in it's template. That could have a canvas as it's itemspresenter and you could bind canvas.top and canvas.left to properties in it's content. Template each into a rectangle and bind height and width.
And of course do something about the scale on the bottom and the column of activity labels or whatever you want to call them there.
Unless you're using an absolutely ancient machine, that'd just fly.
It's quite a lot of work but it would probably be quicker to write that than to search through a load of alternative packages and decide which was optimal.
So, I have a shape I'm programatically generating, when it has a small amount of text, it looks like this:
If I add a huge amount of text however, it flows out of the shape, like so:
What I want to do is to hide the overflow and to force the text to start from the top of the shape (currently the text starts from a position higher than the top of the shape)
I haven't found much information about this so far, here is the code I'm using for the text inside the shape:
var shape = slide.Shapes.AddShape(MsoAutoShapeType.msoShapeRectangle, left, top, width, height);
var textRange2 = shape.TextFrame.TextRange.InsertAfter(description);
textRange2.Font.Size = 10;
shape.TextFrame.TextRange.Paragraphs().ParagraphFormat.Alignment = PpParagraphAlignment.ppAlignLeft;
shape.TextFrame.TextRange.Paragraphs().Font.Name = "Consolas";
shape.TextFrame.TextRange.Paragraphs().Font.Color.RGB = foregroundColor;
One last thing, I know I could just limit the string, but this would impose problems for the user. I want him to be able to resize the shape manually if there is too much text, so that's a no-go. Basically, I just want the equivalent of the css overflow:hidden rule.
One option for some users may be to use the following:
shape.TextFrame.AutoSize = PpAutoSize.ppAutoSizeShapeToFitText;
This will resize the shape to fit the text, there should also be an option to resize TEXT to fit the shape instead (resizing of fonts), I can't seem to find the function however.
Thanks guys
So, apparently
shape.TextFrame.AutoSize
accepts an enumerable PpAutoSize which has PpAutoSize.ppAutoSizeShapeToFitText; that can be used
whereas
shape.TextFrame2.AutoSize
accepts an enumerable MsoAutoSize which has MsoAutoSize.msoAutoSizeTextToFitShape;
So basically, if you change the textframe you're using to TextFrame2 instead of TextFrame, you can have the text resize to fit the shape automagically.
shape.TextFrame2.AutoSize = MsoAutoSize.msoAutoSizeTextToFitShape;
In Powerpoint directly- there is an option to do this. Based on the placement in the menu, I would guess it is in the shape.TextFrame.AutoSize Property - maybe the "mixed" Option?
The PowerPoint object model is a huge mess - so it might be some other strane Property...
Is there any technique to calculate the height of text in AcroField?
In other words, I have a template PDF with a body section that I want to paste my long text into and I want to get the height of the text. If it overflows, insert a new page for rest of the text.
This will give height and width:
Vector curBaseline = renderInfo.GetBaseline().GetStartPoint();
Vector topRight = renderInfo.GetAscentLine().GetEndPoint();
iTextSharp.text.Rectangle rect = new iTextSharp.text.Rectangle(
curBaseline[Vector.I1], curBaseline[Vector.I2],
topRight[Vector.I1], topRight[Vector.I2]
);
Single curFontSize = rect.Height;
Just set your field to a font size of zero. This will automatically size the font so that the given text will fit into your field... within certain limits. I don't think it'll shrink below 6 points.
Another alternative would be to use a ColumnText and call myColText.go(true). This will "simulate" layout, letting you know what goes where without actually drawing anything to the PDF. Just whip up a columnText with the same dimensions, font&font-size as your field, and your results should be the same.
In fact, I believe iText's text field rendering code uses ColumnText internally. Yep, have a look at the source for TextField.getAppearance().
Note that the bounding box of your field isn't going to match the box the text is laid out into... you have to account for borer style & thickness. That's why I suggest you look at the source.