NGUI的UIInput限制输入字节数

UIInput有个字段是"Character Limit",它决定了输入字符数目的上限。每个字符不论是中文还是英文,都算1个字符。

有个很常见的需求是根据字节数限制输入长度,英文数字算1个字节,中文算2个字节。我们需要修改UIInput以实现该功能,网上有相关的处理代码,可惜随着NGUI更新已经过时,我只好重新写了一个修改实现,并分享出来。因为整个文件过长,本文只提到修改的地方。

打开文件 UIInput,首先添加变量 byteLimit,它就是我们需要配置的字节数。把它放到 characterLimit 的下面

public int byteLimit = 0;

接下来添加计算字节数的方法,注意用UTF-8格式不能直接得到字节数

// 获得字符串的字节数,中文2字节,英文1字节
// 用UTF8格式(中文3字符,英文1字符)迂回计算长度,再计算得到正确结果
protected int GetStringByteLength(string str)
{
	return (Encoding.UTF8.GetByteCount(str) + str.Length) / 2;
}

我们可以查看characterLimit在哪里被调用,在这些地方也处理byteLimit,首先是Validate()方法,修改如下

public string Validate (string val)
{
	if (string.IsNullOrEmpty(val)) return "";

	StringBuilder sb = new StringBuilder(val.Length);

	for (int i = 0; i < val.Length; ++i)
	{
		char c = val[i];
		if (onValidate != null) c = onValidate(sb.ToString(), sb.Length, c);
		else if (validation != Validation.None) c = Validate(sb.ToString(), sb.Length, c);
		if (c != 0) sb.Append(c);
	}

	string result = null;
	if (characterLimit > 0 && sb.Length > characterLimit)
		result = sb.ToString(0, characterLimit);

	// 检查 ByteLimit
	if (byteLimit > 0)
	{
		result = result ?? sb.ToString();
		if (result.Length == 0) // 空串直接放行
		{
			return result;
		}
		if (GetStringByteLength(result.Substring(0, 1)) > byteLimit) // 如果第一个字符就超了,直接结束
		{
			return "";
		}
		if (GetStringByteLength(result) <= byteLimit) // 如果最后一个字节也没超,直接放行
		{
			return result;
		}

		// 用二分法找到超和不超的边界位置
		int l = 0;
		int r = result.Length - 1;
		int m = (l + r) / 2;
		while (m != l)
		{
			if (GetStringByteLength(result.Substring(0, m + 1)) > byteLimit)
			{
				r = m;
			}
			else
			{
				l = m;
			}
			m = (l + r) / 2;
		}
		if (GetStringByteLength(result.Substring(0, m + 1)) > byteLimit)
		{
			result = result.Substring(0, m);
		}
		else
		{
			result = result.Substring(0, m + 1);
		}
	}
	return result ?? sb.ToString();
}

再修改 Insert() 方法就完成了

protected virtual void Insert (string text)
{
	string left = GetLeftText();
	string right = GetRightText();
	int rl = right.Length;
	int lbl = GetStringByteLength(left);
	int rbl = GetStringByteLength(right);

	StringBuilder sb = new StringBuilder(left.Length + right.Length + text.Length);
	sb.Append(left);

	// Append the new text
	for (int i = 0, imax = text.Length; i < imax; ++i)
	{
		// If we have an input validator, validate the input first
		char c = text[i];

		if (c == '\b')
		{
			DoBackspace();
			continue;
		}

		// Can't go past the character limit
		if (characterLimit > 0 && sb.Length + rl >= characterLimit) break;

		// Can't go past the byte limit
		if (byteLimit > 0 && GetStringByteLength(sb.ToString() + c) + rbl > byteLimit) break;

		if (onValidate != null) c = onValidate(sb.ToString(), sb.Length, c);
		else if (validation != Validation.None) c = Validate(sb.ToString(), sb.Length, c);

		// Append the character if it hasn't been invalidated
		if (c != 0) sb.Append(c);
	}

	// Advance the selection
	mSelectionStart = sb.Length;
	mSelectionEnd = mSelectionStart;

	// Append the text that follows it, ensuring that it's also validated after the inserted value
	for (int i = 0, imax = right.Length; i < imax; ++i)
	{
		char c = right[i];
		if (onValidate != null) c = onValidate(sb.ToString(), sb.Length, c);
		else if (validation != Validation.None) c = Validate(sb.ToString(), sb.Length, c);
		if (c != 0) sb.Append(c);
	}

	mValue = sb.ToString();
	UpdateLabel();
	ExecuteOnChange();
}

要在Inspector里显示byteLimit,所以我们最后要修改UIInputEditor的OnInspectorGUI()方法

public override void OnInspectorGUI ()
{
	UIInput input = target as UIInput;
	serializedObject.Update();
	GUILayout.Space(3f);
	NGUIEditorTools.SetLabelWidth(110f);
	//NGUIEditorTools.DrawProperty(serializedObject, "m_Script");

	EditorGUI.BeginDisabledGroup(serializedObject.isEditingMultipleObjects);
	SerializedProperty label = NGUIEditorTools.DrawProperty(serializedObject, "label");
	EditorGUI.EndDisabledGroup();

	EditorGUI.BeginDisabledGroup(label == null || label.objectReferenceValue == null);
	{
		if (Application.isPlaying) NGUIEditorTools.DrawPaddedProperty("Value", serializedObject, "mValue");
		else NGUIEditorTools.DrawPaddedProperty("Starting Value", serializedObject, "mValue");
		NGUIEditorTools.DrawPaddedProperty(serializedObject, "savedAs");
		NGUIEditorTools.DrawProperty("Active Text Color", serializedObject, "activeTextColor");

		EditorGUI.BeginDisabledGroup(serializedObject.isEditingMultipleObjects);
		{
			if (label != null && label.objectReferenceValue != null)
			{
				SerializedObject ob = new SerializedObject(label.objectReferenceValue);
				ob.Update();
				NGUIEditorTools.DrawProperty("Inactive Color", ob, "mColor");
				ob.ApplyModifiedProperties();
			}
			else EditorGUILayout.ColorField("Inactive Color", Color.white);
		}
		EditorGUI.EndDisabledGroup();

		NGUIEditorTools.DrawProperty("Caret Color", serializedObject, "caretColor");
		NGUIEditorTools.DrawProperty("Selection Color", serializedObject, "selectionColor");
		NGUIEditorTools.DrawPaddedProperty(serializedObject, "inputType");
		NGUIEditorTools.DrawPaddedProperty(serializedObject, "validation");
		NGUIEditorTools.DrawPaddedProperty("Mobile Keyboard", serializedObject, "keyboardType");
		NGUIEditorTools.DrawPaddedProperty("  Hide Input", serializedObject, "hideInput");
		NGUIEditorTools.DrawPaddedProperty(serializedObject, "onReturnKey");

		// Deprecated, use UIKeyNavigation instead.
		//NGUIEditorTools.DrawProperty(serializedObject, "selectOnTab");

		SerializedProperty sp = serializedObject.FindProperty("characterLimit");

		GUILayout.BeginHorizontal();

		if (sp.hasMultipleDifferentValues || input.characterLimit > 0)
		{
			EditorGUILayout.PropertyField(sp);
			NGUIEditorTools.DrawPadding();
		}
		else
		{
			EditorGUILayout.PropertyField(sp);
			GUILayout.Label("unlimited");
		}
		GUILayout.EndHorizontal();

		// Byte Limit
		SerializedProperty spbl = serializedObject.FindProperty("byteLimit");
		GUILayout.BeginHorizontal();
		if (spbl.hasMultipleDifferentValues || input.byteLimit > 0)
		{
			EditorGUILayout.PropertyField(spbl);
			NGUIEditorTools.DrawPadding();
		}
		else
		{
			EditorGUILayout.PropertyField(spbl);
			GUILayout.Label("unlimited");
		}
		GUILayout.EndHorizontal();

		NGUIEditorTools.SetLabelWidth(80f);
		EditorGUI.BeginDisabledGroup(serializedObject.isEditingMultipleObjects);
		NGUIEditorTools.DrawEvents("On Submit", input, input.onSubmit);
		NGUIEditorTools.DrawEvents("On Change", input, input.onChange);
		EditorGUI.EndDisabledGroup();
	}
	EditorGUI.EndDisabledGroup();
	serializedObject.ApplyModifiedProperties();
}

把上面的代码全部替换即可

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值