这个答案是假设你使用的是原生的TouchScreenKeyboard。
您可以做的是添加一个图像作为垂直布局组的最后一个条目(我们称之为“缓冲区”),它的 alpha 设置为 0(使其不可见)并且它的高度设置为 0。这个将使您的布局组看起来不变。
然后,当您打开键盘时,将此“缓冲区”图像的高度设置为键盘的高度。由于内容大小调整器和垂直布局组,表单的输入字段将被推到键盘上方,而键盘“后面”将是空图像。
在 iOS 上很容易获得键盘的高度TouchScreenKeyboard.area.height 应该可以解决问题。然而,在 Android 上,这将返回一个空矩形。 This answer 答案解释了如何获取 Android 键盘的高度。
完全实现它看起来像这样(仅在 Android 上测试过,但也应该适用于 iOS)。请注意,我正在使用之前链接的答案中的方法来获取 Android 键盘高度。
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
public class KeyboardSize : MonoBehaviour
{
[SerializeField] private RectTransform bufferImage;
private float height = -1;
/// <summary>
/// Open the keyboard and start a coroutine that gets the height of the keyboard
/// </summary>
public void OpenKeyboard()
{
TouchScreenKeyboard.Open("");
StartCoroutine(GetKeyboardHeight());
}
/// <summary>
/// Set the height of the "buffer" image back to zero when the keyboard closes so that the content size fitter shrinks to its original size
/// </summary>
public void CloseKeyboard()
{
bufferImage.GetComponent<RectTransform>().sizeDelta = Vector2.zero;
}
/// <summary>
/// Get the height of the keyboarding depending on the platform
/// </summary>
public IEnumerator GetKeyboardHeight()
{
//Wait half a second to ensure the keyboard is fully opened
yield return new WaitForSeconds(0.5f);
#if UNITY_IOS
//On iOS we can use the native TouchScreenKeyboard.area.height
height = TouchScreenKeyboard.area.height;
#elif UNITY_ANDROID
//On Android TouchScreenKeyboard.area.height returns 0, so we get it from an AndroidJavaObject instead.
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);
height = Screen.height - Rct.Call<int>("height");
}
}
#endif
//Set the height of our "buffer" image to the height of the keyboard, pushing it up.
bufferImage.sizeDelta = new Vector2(1, height);
}
StartCoroutine(CalculateNormalizedPosition());
}
private IEnumerator CalculateNormalizedPosition()
{
yield return new WaitForEndOfFrame();
//Get the new total height of the content gameobject
var newContentHeight = contentParent.sizeDelta.y;
//Get the local y position of the selected input
var selectedInputHeight = InputH.lastSelectedInput.transform.localPosition.y;
//Get the normalized position of the selected input
var selectedInputfieldHeightNormalized = 1 - selectedInputHeight / -newContentHeight;
//Assign the button's normalized position to the scroll rect's normalized position
scrollRect.verticalNormalizedPosition = selectedInputfieldHeightNormalized;
}
我已经编辑了您的InputH,通过添加一个静态游戏对象来跟踪最后选择的输入,该对象在单击输入字段时分配给如下:
public class InputH : MonoBehaviour, IPointerClickHandler
{
private GameObject canvas;
//We can use a static GameObject to track the last selected input
public static GameObject lastSelectedInput;
// Start is called before the first frame update
void Start()
{
// Your start is unaltered
}
public void OnPointerClick(PointerEventData eventData)
{
KeyboardSize ks = canvas.GetComponent<KeyboardSize>();
if (!ks.IsKeyboardOpened())
{
ks.OpenKeyboard();
//Assign the clicked button to the lastSelectedInput to be used inside KeyboardSize.cs
lastSelectedInput = gameObject;
}
else
{
print("Keyboard is already opened");
}
}
为了(至少我的解决方案)正常工作,还必须做的另一件事是,我必须将“内容”游戏对象上的锚点更改为 top center,而不是您使用的 stretch。