TextMeshPro的TMP_InputField注册onValueChanged回调之后,如果使用复制粘贴,则onValueChanged会在每个字符上调用。
通过源码可见:
case KeyCode.V:
{
if (ctrlOnly)
{
Append(clipboard);
return EditState.Continue;
}
break;
}
//-------------------------------------------------
/// <summary>
/// Append the specified text to the end of the current.
/// </summary>
protected virtual void Append(string input)
{
if (m_ReadOnly)
return;
if (InPlaceEditing() == false)
return;
for (int i = 0, imax = input.Length; i < imax; ++i)
{
char c = input[i];
if (c >= ' ' || c == '\t' || c == '\r' || c == '\n')
{
Append(c);
}
}
}
解决办法,是继承TMP_InputField,然后重写Append(string)方法。
/// <summary>
/// Appends string (clipboard) to the text and just calls the onValueChanged once.
/// The original onValueChanged is called per char, not once per string.
/// </summary>
protected override void Append(string input)
{
if (this.onValueChanged != null)
{
var onChangeEvent = this.onValueChanged;
this.onValueChanged = null;
base.Append(input);
this.onValueChanged = onChangeEvent;
// update the lineCount for onValueChanged
this.UpdateLabel();
this.onValueChanged.Invoke(this.text);
}
else
{
base.Append(input);
}
}
这里有两个问题,值得指出:
- 重写方式是,禁用onValueChanged,调用父类Append(string),再恢复onValueChanged。
- 调用onValueChanged之前,需要UpdateLabel(),因为粘帖大段文本,会触发行数的改变,如果不调用更新,这在onValueChanged中无法正确检测到,lineCount的改变。