RectTransform coordinates according to TextMesh Pro text size - unity3d

I'm trying to create an InputField (TextMesh Pro) with a dynamic (its text content may vary) prefix.
This spectacular image should explain the goal.
https://imgur.com/a/qx1eXOa
So I set a TextMeshPro text to use as Prefix, and by script I was trying to "move" the TextArea accordingly.
The fact is, TextArea is a RectTransform, and I'm operating in a ScreenSpace render mode.
I was trying like this:
private TextMeshProGUI prefix;
private RecTransform textArea;
public void ChangePrefixTo(string newPrefix)
{
float oldWidth = prefix.preferredWidth;
prefix.text = newPrefix;
float newWidth = prefix.preferredWidth;
Vector2 newPos = new Vector2();
newPos.x = textArea.position.x + (newWidth - oldWidth);
newPos.y = textArea.position.y;
textArea.position = newPos;
}
, but the textArea gets shot into the stars.
How can I map the RectTransform position according to the size of a TextMeshPro text?
Thanks for the help and long live the whales

Instead of using a script to resize your prefix, you can group both of your elements in a Horizontal Layout Group, check only Width for Child Controls Size.
Add a Layout Element and set your Preferred Width to define the size of your TextArea.
The Prefix will scale according to his content, and it will push your text area as it grows.

Related

Unity - Updating Font Size tags in TMPro Stylesheet on runtime?

I have a style sheet set up in which I set up tags that set font size such as <size=23px>. Is it possible to somehow modify the stylesheet on runtime to change these sizes (even if I have to do it one by one)? It's for implementing a font size slider in the UI settings of the game (ideally I'd like to multiply each fontsize by a modifier).
Thank you
Edit: To clarify, I set the sizes via opening tags in the style sheets and I am looking to update these settings on runtime, NOT update the text size on the TextMeshProUGUI components!
I'm able to reference my default styleSheet directly. According to https://docs.unity3d.com/Packages/com.unity.textmeshpro#1.3/api/TMPro.TMP_StyleSheet.html "GetStyle" retrieves "the Style matching the HashCode" (or name if I give it a string parameter). Once I get the style, however, I have very limited choice: https://docs.unity3d.com/Packages/com.unity.textmeshpro#1.3/api/TMPro.TMP_Style.html?q=TMP_Style based on this, my best bet would be to query "styleOpeningDefinition".
I am able to get the opening tags via styleOpeningDefinition, and then find and replace the relevant number that denotes the size in the "<size="50px">" tag but it's a readonly property so I cant set it afterwards.
Here's the code:
TMP_Text text = GetComponent<TMP_Text>();
TMP_Style style = styleSheet.GetStyle("H1");
openingTags = style.styleOpeningDefinition;
string[] size = openingTags.Split("px><cspace=");
string _splitString = size[0].Replace("<size=", "");
float _currentSize = float.Parse(_splitString);
_currentSize *= multiplier;
string _newTags = "<size=" + _currentSize + "px>" + size[1];
style.styleOpeningDefinition = _newTags; //Property or indexer 'TMP_Style.styleOpeningDefinition' cannot be assigned to -- it is read only
style.RefreshStyle();
In Unity, you can use the UnityEngine.UI.Text component to change the font size of text elements on runtime. You can use the fontSize property of the Text component to change the font size.
using UnityEngine;
using UnityEngine.UI;
public class FontSizeModifier : MonoBehaviour
{
public Text text;
public float fontSizeModifier = 1f;
void Update()
{
text.fontSize = (int)(text.fontSize * fontSizeModifier);
}
}
This script will update the font size of the text element on every frame, multiplying the current font size by the fontSizeModifier variable.
You can use this script and attach it to the text element you want to modify, or you can create a list of texts and modify them all via a loop.

Growing menu with scrollbar

I hate to ask such a generic question but I'm really stuck and super hoping someone can help me along the way. Here is the situation:
I'm making the GUI for a mobile app, portrait mode. I'm using canvas scalers to scale my canvasses with a reference width of 1080. This means I effectively don't know the height of my screen space.
What I want to create is a menu with a variable amount of items. The menu must be anchored to the bottom (with an offset margin) and grow upwards. So far I've been able to manage this using VerticalLayoutGroup and anchoring the rect transform to the bottom.
But my last requirement is that if the content would grow too big, a scrollbar would appear. The definition of the content being too big is: if it would extend the (unknown) screen height ( minus the offset margin of course). I hope the following image illustrates this much clearer:
I have a unity project here: https://ufile.io/v31br
Did you give a try to scrollView? here it is: https://unity3d.com/learn/tutorials/topics/user-interface-ui/scroll-view
You can use your vertical layout inside it and you will probably want to deactivate horizontal scroll and delete the horizontal slider.
Via script you can check its rectTransform height and compare it to your container's size, when reached maxHeight you can start managing your item's sizes
I assume you use the ScrollRect component as it is the right component to use in your case.
You can check the screen height with the Screen.height property.
Once you know the screen height you can compare it with your rect height and toggle the scrollbar with the ScrollRect.vertical property. You may have to change the ScrollRect.verticalScrollbarVisibility to permanent in order to make it work for you.
The answer Dave posted was close, but the problem is that the scrollview doesn't expand. I fixed it eventually by stretching the scrollview and resizing the parent manually as items are added. I set the anchors to the maximum size and adjust the sizeDelta.
public class MenuScript : MonoBehaviour
{
public int MenuItemCount;
public GameObject MenuItemPrefab;
public Transform MenuItemParent;
private RectTransform _rectTransform;
void Start()
{
_rectTransform = GetComponent<RectTransform>();
for (var i = 0; i <= MenuItemCount; i++)
{
GameObject instance = Instantiate(MenuItemPrefab, MenuItemParent, false);
instance.GetComponent<Text>().text = instance.name = "Item " + i;
float size = instance.transform.GetComponent<RectTransform>().sizeDelta.y;
TryExpandBy(size + 10);
}
}
private void TryExpandBy(float size)
{
var deltaY = _rectTransform.sizeDelta.y + size;
if (deltaY > 0) deltaY = 0;
_rectTransform.sizeDelta = new Vector2(_rectTransform.sizeDelta.x, deltaY);
}
}

Display loaded UI Image in Container with native size

I want to display UI logo images in their aspect ratio but in proper size that fit within its container. Already all logo images as per aspect ratio but few are too big or small compare to requirements.
At present this kind of thing happening:
Here is the code that I am using:
private void ShowGamePlayLogoViewed ()
{
for (int i = 0; i < DataCollection.companyDetailsList.Count; i++) {
Company company = DataCollection.companyDetailsList [i];
if (company.ViewedCounter > 0) {
GameObject companyItemObj = Instantiate (companyItemPref, gridViewContainer) as GameObject;
CompanyItem companyItem = companyItemObj.GetComponent<CompanyItem> ();
companyItem.companyId = company.CompanyId;
companyItem.UpdateCompanyLogo (company.CompanyLogo);
companyItem.UpdateCompanyName (company.CompanyName);
}
}
}
public void UpdateCompanyLogo (Sprite logoSprite)
{
logoImage.sprite = logoSprite;
logoImage.SetNativeSize ();
}
As you are seeing, logos overlapping the container. I want to display properly them in their respective containers also in aspect ratio too.
Let me clarify one more thing: all logos loaded from web server and they all are dynamic at a time, based on server data it will appear in mobile screen.
I have found solution through Unity Forum and I want to say thanks to #Hosnkobf for reply.
Here is the exact reply that worked for me properly:
adjust the image game object inside unity so that it has the height you are looking for. also adjust the anchors so that it scales with different resolutions properly.
Add an "AspectRatioFitter" component to the object. Make it "Height controls width".
Instead of logoImage.SetNativeSize (); do the following:
float aspectRatio = logoSprite.rect.width / logoSprite.rect.height;
var fitter = logoImage.GetComponent<UnityEngine.UI.AspectRatioFitter>();
fitter.aspectRatio = aspectRatio;
I hope this become useful to other members :)

How to autosize text on a textmesh

How do you auto-size text on a textmesh.
I have dice, with six sides, that I want to put words on. The words will constantly be changing, so I need them to auto size based on the size of the cube, which doesn't change.
The dice are not UI elements and thus sit outside the canvas.
Here is how I am adding the text.
LocationSide1.GetComponent<TextMesh>().text = "1";
LocationSide2.GetComponent<TextMesh>().text = "2";
LocationSide3.GetComponent<TextMesh>().text = "3";
LocationSide4.GetComponent<TextMesh>().text = "4";
LocationSide5.GetComponent<TextMesh>().text = "5";
LocationSide6.GetComponent<TextMesh>().text = "6";
Imagine I want the dice to say "pickle" instead of the 6. The next role it might say "cantaloupe" then "pea". The text will change sizes.
Example how the text sticks over the edge.
The answer you seek can be found on another thread - http://answers.unity3d.com/questions/218222/how-to-calculate-a-textmesh-width-without-renderin.html
public class TextBehaviour : MonoBehaviour
{
public TextMesh textmesh;
void Start ()
{
Bounds bound = BoundOfTextMesh("New Text");
print ("Size X = "+bound.size.x +"Size Y = "+bound.size.y);// Size of X and Y or Vector2
}
Bounds BoundOfTextMesh(string textMeshName)
{
textmesh = GameObject.Find (textMeshName).GetComponent<TextMesh>();
return textmesh.renderer.bounds ;
}
}
TextMesh doesn't have an auto-sizing feature, so to resize the text to fit in its container, you would have to follow Scott Barnes' suggestion of manipulating the Renderer for the desired effect.
If you're looking for alternatives that have the effect you're looking for, you might consider TextMesh Pro. It's a free asset on the Unity store that has Auto-Sizing functionality. The text comes in both 2D UI and 3D Text formats, so it will work both inside and outside of canvases.
TextMesh Pro Auto-Sizing Video

Fake scrolling with JavaFX 8 ScrollPane

What I'm trying to do:
I'm trying to render a game board for a user using a canvas. The user
will be able to zoom.
Rendering the entire game board is impossible when the user is
zoomed in as the game board is very large. Instead I will render what
is onscreen every 1/30 sec.
I would like to create the illusion of the entire game board beings
inside a gui like the ScrollPane where the user can scroll with a
mouse.
In reality the ScrollPane will be linked to a single canvas exactly
the size of the viewport.
I'm not sure what the right way to go about this is. The scroll pane does not seem to have a property that allows you to pretend it has a large object in it. I could place a large canvas in the scroll pane but large canvases take up memory, as my crashes have suggested. Should I be using an AnchorPane or something? What's the proper way to do this?
It seems like putting an AnchorPane into the ScrollPane, setting that AnchorPane to the correct size (the size of the entire gameboard) works well to let the user scroll freely. From there all you have to do is put a canvas in the AnchorPane at the right place and keep moving it (and redrawing it) makes everything work out. To make it run smoothly I think you should render 100 to 500 pixels outside of the viewport of the ScrollPane. Here's some example code from my project:
public class GridViewPane {
/** ScrollPane that this grid exits in */
private ScrollPane gridScroll;
/** The anchor pane immediately inside of {#link #gridScroll}. The
* dimensions of this equals the dimensions of the {#link #can} if it was to
* render the entire grid at once */
private Pane gridView;
/** Exists in {#link #gridView} and is exactly the size of the viewport of
* {#link #gridScroll} */
private Canvas can;
/** A label the specifies what hex is currently moused-over */
private Label currentHexLabel;
public void update() {
// sets the canvas to the right size if needed
final Bounds viewportSize = gridScroll.getBoundsInLocal();
if (can == null || !can.getBoundsInLocal().equals(viewportSize)) {
can = new Canvas(viewportSize.getWidth(),
viewportSize.getHeight());
gc = can.getGraphicsContext2D();
}
// sets the anchorpane to the right size
final double[] dim = getPixleSizeOfGrid(w.columns(), w.rows(), r);
if (gridView == null) {
gridView = new AnchorPane();
gridScroll.setContent(gridView);
}
Bounds oldDim = gridView.getBoundsInLocal();
if (!(oldDim.getWidth() == dim[0]
&& oldDim.getHeight() == dim[1])) {
gridView.setPrefSize(dim[0], dim[1]);
}
// puts the canvas in the right position
if (!gridView.getChildren().contains(can))
gridView.getChildren().add(can);
double[] x = getXScreenRange();
double[] y = getYScreenRange();
can.relocate(x[0], y[0]);
// *********** Drawing Hexes ***********/
}
}