我们实际开发出来的聊天系统,有时候会出现这样一个现象,点击InputField会弹出手机系统的键盘,键盘的弹出会遮住InputField甚至频道里面的消息。为了解决游戏聊天视图被这个系统键盘遮挡的问题,最直接的思路就是,输入框根据键盘的高度来做适应,意思就是说,根据键盘的高度,动态改变游戏聊天视图的高度。
目前市面上比较有名的游戏,如手游《龙珠》是这么做的。我参与的项目同样遇到这样的需求,采用了同样的方法。接下来就介绍下我的实现。
如何获取键盘的高度?
安卓上实现
获取到unity这个主Activity,然后getView获取到安卓层的view组件信息,getWindowVisibleDisplayFrame的结果
就是这个键盘视图的高度
/// <summary>
/// 获取安卓平台上键盘的高度
/// </summary>
/// <returns></returns>
public int GetKeyboardHeight() {
using (AndroidJavaClass UnityClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer")) {
AndroidJavaObject View = UnityClass.GetStatic<AndroidJavaObject>("currentActivity").
Get<AndroidJavaObject>("mUnityPlayer").Call<AndroidJavaObject>("getView");
using (AndroidJavaObject Rct = new AndroidJavaObject("android.graphics.Rect")) {
View.Call("getWindowVisibleDisplayFrame", Rct);
return Screen.height - Rct.Call<int>("height");
}
}
}
IOS上实现
IOS上就比较简单了,直接利用Unity的一个API,叫TouchScreenKeyboard,相关的API信息在这里查看:https://docs.unity3d.com/ScriptReference/TouchScreenKeyboard.html 。文档中明确说明了这个接口是安卓、IOS等移动平台获取键盘的Native层接口,TouchScreenKeyboard.area这个静态属性返回的是键盘覆盖区域部分的rect信息。所以我们直接利用这个信息就可以获取到这个键盘的高度,起始点等信息。
public float IOSGetKeyboardHeight() {
return TouchScreenKeyboard.area.height;
}
为什么安卓上不直接用TouchScreenKeyboard.area呢?
答案是这个area在安卓上不可用。
官方文档上明确说了,“Returns zero-Rect on Android.”。我看了一下,一直到5.6版本这个接口还是说的返货的是zero-Rect。
完整功能脚本
有一点需要注意的是不同平台的Screen.height不一样,注意适配这个问题,注意这一句 float keyboardHeight = AndroidGetKeyboardHeight()*RESOULUTION_HEIGHT/Screen.height;
using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// 移动设备输入框的自适应组件
/// </summary>
public class ChatViewAdaptMobileKeyBoard : MonoBehaviour {
public InputField _inputField;
/// <summary>
/// 自适应(弹出输入框后整体抬高)的面板的初始位置
/// </summary>
private Vector2 _adaptPanelOriginPos;
private RectTransform _adaptPanelRt;
private float RESOULUTION_HEIGHT = 1280F;
public static ChatViewAdaptMobileKeyBoard Create(GameObject attachRoot, InputField inputField) {
ChatViewAdaptMobileKeyBoard instance = null;
instance = attachRoot.AddComponent<ChatViewAdaptMobileKeyBoard>();
instance._inputField = inputField;
return instance;
}
private void Start() {
Debuger.Log("ChatViewAdaptMobileKeyBoard.start()");
_inputField.onEndEdit.AddListener(OnEndEdit);
_inputField.onValueChanged.AddListener(OnValueChanged);
_adaptPanelRt = transform.Find("TabControl/Panels").GetComponent<RectTransform>();
_adaptPanelOriginPos = _adaptPanelRt.anchoredPosition;
}
private void Update() {
if (_inputField.isFocused) {
if (Application.platform == RuntimePlatform.Android) {
float keyboardHeight = AndroidGetKeyboardHeight()*RESOULUTION_HEIGHT/Screen.height;
Debug.LogFormat("安卓平台检测到InputField.isFocused为真,获取键盘高度:{0}, Screen.height:{1}", keyboardHeight, Screen.height);
_adaptPanelRt.anchoredPosition = Vector3.up * (keyboardHeight);
}
else if (Application.platform == RuntimePlatform.IPhonePlayer) {
float keyboardHeight = IOSGetKeyboardHeight() * RESOULUTION_HEIGHT / Screen.height;
Debuger.LogFormat("IOS平台检测到键盘高度:{0},Screen.height: {1}", keyboardHeight, Screen.height);
_adaptPanelRt.anchoredPosition = Vector3.up * keyboardHeight;
}
else {
//Editor或其他平台,测试用!
_adaptPanelRt.anchoredPosition = Vector3.up * 300f;
}
}
}
private void OnValueChanged(string arg0) { }
/// <summary>
/// 结束编辑事件,TouchScreenKeyboard.isFocused为false的时候
/// </summary>
/// <param name="currentInputString"></param>
private void OnEndEdit(string currentInputString) {
//Debuger.LogFormat("OnEndEdit, 输入内容:{0}, 结束时间:{1}", currentInputString, Time.realtimeSinceStartup);
_adaptPanelRt.anchoredPosition = _adaptPanelOriginPos;
}
/// <summary>
/// 获取安卓平台上键盘的高度
/// </summary>
/// <returns></returns>
public int AndroidGetKeyboardHeight() {
using (AndroidJavaClass UnityClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer")) {
AndroidJavaObject View = UnityClass.GetStatic<AndroidJavaObject>("currentActivity").
Get<AndroidJavaObject>("mUnityPlayer").Call<AndroidJavaObject>("getView");
using (AndroidJavaObject Rct = new AndroidJavaObject("android.graphics.Rect")) {
View.Call("getWindowVisibleDisplayFrame", Rct);
return Screen.height - Rct.Call<int>("height");
}
}
}
public float IOSGetKeyboardHeight() {
return TouchScreenKeyboard.area.height;
}
}