Reputation: 799
I have this simple structure inside a Canvas:
Now, it works pretty well, when the text gets out of boundaries, the UI-Image expands. But since I have a Layout Group as a parent to my TMP Text, I get an error inside the Text, in the Content Size Fitter, saying that 'The parent has a a type of layout group component...'. And as a result, the image height sometimes doesn't update when I the text changes (doesn't grow or shrink, only after I refresh or save the project).
Am I doing something wrong here?
Upvotes: 14
Views: 24270
Reputation: 59
Follow the steps below to achieve your UI design goal..
Horizontal Layout Group
to your container image
component and enable Width
of Control Child Size
Content Size Fitter
to your container image
component and set Horizontal Fit
to Preferred Size
You don't need to add any component to your text
component.
You can also add currency icon as show below.
Upvotes: 1
Reputation: 3
The simplest solution, if suddenly someone else is relevant.
Create a standard ScrollView, remove "Content" from it and add text instead of content (do not forget to add your text to the Content field in ScrollRect). Next, add ContentSizeFittier to the text.enter image description here
Upvotes: 0
Reputation: 21
made a custom script duplicated from the original contentSizeFitter component in which i added a bool called applyToParent , if "true" & the parent has a rectTransform component , the parent will scale along the current object. you can even add a list of recttransforms variable which you can make them follow the same size as well! screenshot
using UnityEngine;
using UnityEngine.EventSystems;
namespace UnityEngine.UI
{
[AddComponentMenu("Layout/Custom Content Size Fitter", 888)]
[ExecuteAlways]
[RequireComponent(typeof(RectTransform))]
/// <summary>
/// Resizes a RectTransform to fit the size of its content & the ability to modify the size of the parent as well
/// </summary>
/// <remarks>
/// The ContentSizeFitter can be used on GameObjects that have one or more ILayoutElement components, such as Text, Image, HorizontalLayoutGroup, VerticalLayoutGroup, and GridLayoutGroup.
/// </remarks>
public class CustomContentSizeFitter : UIBehaviour, ILayoutSelfController
{
/// <summary>
/// The size fit modes avaliable to use.
/// </summary>
public enum FitMode
{
/// <summary>
/// Don't perform any resizing.
/// </summary>
Unconstrained,
/// <summary>
/// Resize to the minimum size of the content.
/// </summary>
MinSize,
/// <summary>
/// Resize to the preferred size of the content.
/// </summary>
PreferredSize
}
[SerializeField] protected FitMode m_HorizontalFit = FitMode.Unconstrained;
/// <summary>
/// The fit mode to use to determine the width.
/// </summary>
public FitMode horizontalFit { get { return m_HorizontalFit; } set { if (SetPropertyUtility2.SetStruct(ref m_HorizontalFit, value)) SetDirty(); } }
[SerializeField] protected FitMode m_VerticalFit = FitMode.Unconstrained;
/// <summary>
/// The fit mode to use to determine the height.
/// </summary>
public FitMode verticalFit { get { return m_VerticalFit; } set { if (SetPropertyUtility2.SetStruct(ref m_VerticalFit, value)) SetDirty(); } }
private DrivenRectTransformTracker m_Tracker;
protected CustomContentSizeFitter()
{}
protected override void OnEnable()
{
base.OnEnable();
SetDirty();
}
protected override void OnDisable()
{
m_Tracker.Clear();
LayoutRebuilder.MarkLayoutForRebuild(rectTransform);
base.OnDisable();
}
protected override void OnRectTransformDimensionsChange()
{
SetDirty();
}
public virtual void SetLayoutHorizontal()
{
m_Tracker.Clear();
HandleSelfFittingAlongAxis(0);
}
/// <summary>
/// Calculate and apply the vertical component of the size to the RectTransform
/// </summary>
public virtual void SetLayoutVertical()
{
HandleSelfFittingAlongAxis(1);
}
[System.NonSerialized] private RectTransform m_Rect;
[System.NonSerialized] private RectTransform m_parentRect;
private RectTransform rectTransform
{
get
{
if (m_Rect == null)
m_Rect = GetComponent<RectTransform>();
return m_Rect;
}
}
private RectTransform parentRectTransform
{
get
{
if (m_parentRect == null)
m_parentRect = rectTransform.parent.GetComponent<RectTransform>();
return m_parentRect;
}
}
private void HandleSelfFittingAlongAxis(int axis)
{
FitMode fitting = (axis == 0 ? horizontalFit : verticalFit);
if (fitting == FitMode.Unconstrained)
{
// Keep a reference to the tracked transform, but don't control its properties:
m_Tracker.Add(this, rectTransform, DrivenTransformProperties.None);
return;
}
m_Tracker.Add(this, rectTransform, (axis == 0 ? DrivenTransformProperties.SizeDeltaX : DrivenTransformProperties.SizeDeltaY));
// Set size to min or preferred size
if (fitting == FitMode.MinSize)
rectTransform.SetSizeWithCurrentAnchors((RectTransform.Axis)axis, LayoutUtility.GetMinSize(m_Rect, axis));
else
rectTransform.SetSizeWithCurrentAnchors((RectTransform.Axis)axis, LayoutUtility.GetPreferredSize(m_Rect, axis));
if(applyToParent && parentRectTransform != null )
{
if(fitting == FitMode.MinSize )
parentRectTransform.SetSizeWithCurrentAnchors((RectTransform.Axis)axis, LayoutUtility.GetMinSize(m_Rect, axis));
else
parentRectTransform.SetSizeWithCurrentAnchors((RectTransform.Axis)axis, LayoutUtility.GetPreferredSize(m_Rect, axis));
}
}
public bool applyToParent = true;
protected void SetDirty()
{
if (!IsActive())
return;
LayoutRebuilder.MarkLayoutForRebuild(rectTransform);
}
#if UNITY_EDITOR
protected override void OnValidate()
{
SetDirty();
}
#endif
}
public static class SetPropertyUtility2
{
public static bool SetColor(ref Color currentValue, Color newValue)
{
if (currentValue.r == newValue.r && currentValue.g == newValue.g && currentValue.b == newValue.b && currentValue.a == newValue.a)
return false;
currentValue = newValue;
return true;
}
public static bool SetStruct<T>(ref T currentValue, T newValue) where T: struct
{
if (currentValue.Equals(newValue))
return false;
currentValue = newValue;
return true;
}
public static bool SetClass<T>(ref T currentValue, T newValue) where T: class
{
if ((currentValue == null && newValue == null) || (currentValue != null && currentValue.Equals(newValue)))
return false;
currentValue = newValue;
return true;
}
}
}
Upvotes: 1
Reputation: 2012
I've been haunted by this problems for over 1 year, finally got it done in a proper way.
The solution is very simple:
Upvotes: 11
Reputation: 551
I will convert this to answer since I'm going to attach images. I did something similar to this for a chat feature.
Make the parent have the content size fitter and set either the horizontal or vertical fit to preferred size.
Let its immediate child be the background, and add a layout element to it to control its minimum size. Also add a layout group to it to control the text that you will put as a child to it.
[EDIT]
1. I changed the Parent's layout group to VerticalLayoutGroup
.
2. I made a duplicate of the game object "Background" but with different texts to that you can see how the ContentSizeFitter
and VerticalLayoutGroup
controls the size of the children.
In the screenshots above, I never adjusted anything on the rect transform. I just changed the text, and as you can see, the background of each text/dialog/message also adjusted.
Upvotes: 24