👉一、前言及知识点
我发现在实际开发过程中,输入框不能像Text组件一样,简单的挂载自动布局组件,设置一下参数就可以实现自适应大小。
因为你会发现如下图的Bug:
bug1:快速输入多行时光标位置与输入位置不一致,而且有时候还“跑到”输入框外;
bug2:框选内容时出现“穿帮”效果;
bug3:子物体text扩充大小时,父物体inputfield扩充的大小跟text不同步。
原因分析:实践发现,导致以上bug是输入框受到了其子物体Placeholder的影响,父物体的自动布局组件会延迟一帧调用。
知识点1:添加自动布局的组件会延迟一帧生效,所以在输入框内容改变时需要显示调用LayoutRebuilder.ForceRebuildLayoutlmmediate(RectTransform layoutRoot)方法实时刷新自动布局组件。
知识点2:RectTransform.SetSizeWithCurrentAnchors (Animations.Axis axis, float size)方法:使RectTransform计算的矩形在指定的轴上为给定的大小。 此方法通过当前锚定生成给定的大小。 如果父对象RectTransform改变大小,则矩形的大小可能会改变。 如果要保留大小,则应该将RectTransform锚设为不拉伸,或者在父对象大小发生变化时再次调用此方法。
👉二、解决方法及原理
在输入框InputField组件下添加一个空物体,并给空物体添加子物体Text组件,然后给空物体添加自动布局组件,并设置好参数。最后我们去写脚本,当输入框输入文字时,用代码控制空物体布局组件 实时刷新,并将其宽高赋值给输入框宽高即可。
👉三、实战步骤
Setp1:新建一个InputField组件,将其LineType属性改为Multi Line Newline;新建一个空物体作为其子物体,并命名为layout;新建Text组件作为layout子物体,并删除其默认文本。
Setp2:给layout空物体添加【Vertical Layout Group】组件,并将其属性child controls size和child force expand都勾选上;添加【Content size fitter】组件,并将其属性Horizontal fit和Vertical fit均设置为Perferred Size。你会发现layout的宽高都变为0了,这时需要添加【Layout Element】组件,并设置一下其最小宽高分别为为100,50。如下图:
Setp3:最重要的细节:需要将layout的子物体的内边距设置跟输入框的文本组件一样,要不然后面你运行的时候会发现如下图bug:两个文本位置不一样
可以看到输入框的text组件内边距为:
所以我们要设置layout的布局组件的padding为:
Set4:接下来就是写脚本去控制输入框自适应效果了。
👉四、脚本代码控制自适应
新建AutoResizeInput脚本,写入以下代码,挂载到输入框InputField即可。
public class AutoResizeInput : MonoBehaviour {
private InputField input;//输入框
private VerticalLayoutGroup layout;//布局组件
private Text layoutContent;//layout的子物体文本
private LayoutElement layoutElement;//布局元素
/// <summary>
/// 初始化获取各个组件
/// </summary>
private void Awake()
{
input = GetComponent<InputField>();
layout =transform.Find("layout").GetComponent<VerticalLayoutGroup>();
layoutContent = layout.gameObject.GetComponentInChildren<Text>();
layoutElement = layout.gameObject.GetComponent<LayoutElement>();
input.onValueChanged.AddListener(OnChangeInputValue);
}
/// <summary>
/// 输入时实时刷新输入框宽高,实现自适应
/// </summary>
/// <param name="value"></param>
public void OnChangeInputValue(string value)
{
input.text = value;
layoutContent.text = value;
LayoutRebuilder.ForceRebuildLayoutImmediate(layout.transform as RectTransform);//实时刷新布局组件
RectTransform rect = transform as RectTransform;
rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal,
Mathf.Max(layoutElement.minWidth, (layout.transform as RectTransform).rect.width));//将输入框在水平轴的宽设置为layout物体的宽,保持同步
rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical,
Mathf.Max(layoutElement.minHeight, (layout.transform as RectTransform).rect.height));//将输入框在竖直轴的高设置为layout物体的高,保持同步
}
}