Unity中如何制作放置时触发文本输入提示的GameObject(移动端)
Unity移动端可放置文本框放置后唤起输入实现方案
整个功能拆成「可放置对象的放置成功判定」和「放置成功后的输入引导唤起」两部分实现,逻辑解耦后后续调整交互更方便,以下是可直接落地的实现步骤:
1. 基础对象搭建
- 创建UI对象作为文本框载体,依次添加组件:
RectTransform、CanvasGroup、Image(作为文本框背景)、TMP_Text(初始显示占位文字,比如"待输入")、TMP_InputField(初始状态设为禁用,避免拖拽时误触) - 做一个引导提示子对象(比如带指向箭头的气泡,文字写"请输入内容"),初始设为隐藏
- 在场景内划定合法放置区域,给区域对象加
CanvasGroup、Image(可设为全透明不显示),将对象层级设为自定义的PlaceableArea层 - 给Canvas挂
GraphicRaycaster组件,确保UI事件检测正常
2. 拖拽放置逻辑实现
直接用UGUI自带的事件接口实现拖拽,不用自己写坐标转换逻辑,能自动适配全分辨率。给文本框对象挂以下脚本:
using UnityEngine; using UnityEngine.EventSystems; using System; using System.Collections.Generic; public class PlaceableTextBox : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler { public LayerMask placeableLayer; // 放置成功的对外事件 public event Action OnPlacedSuccess; private RectTransform rectTransform; private CanvasGroup canvasGroup; private Vector2 originPos; private void Awake() { rectTransform = GetComponent<RectTransform>(); canvasGroup = GetComponent<CanvasGroup>(); originPos = rectTransform.anchoredPosition; } public void OnBeginDrag(PointerEventData eventData) { // 拖拽时关闭自身射线阻挡,否则检测不到下方放置区域 canvasGroup.blocksRaycasts = false; } public void OnDrag(PointerEventData eventData) { rectTransform.position = eventData.position; } public void OnEndDrag(PointerEventData eventData) { canvasGroup.blocksRaycasts = true; if (CheckInPlaceableArea()) { OnPlacedSuccess?.Invoke(); } else { // 不在合法区域就回弹到初始位置 rectTransform.anchoredPosition = originPos; } } private bool CheckInPlaceableArea() { List<RaycastResult> results = new List<RaycastResult>(); EventSystem.current.RaycastAll(new PointerEventData(EventSystem.current){ position = rectTransform.position }, results); foreach (var res in results) { if (((1 << res.gameObject.layer) & placeableLayer) != 0) { return true; } } return false; } }
脚本挂好后,把Inspector上的placeableLayer字段选成之前创建的PlaceableArea层即可。
3. 输入引导逻辑实现
给文本框对象再挂以下脚本,把对应引用拖到序列化字段上:
using TMPro; using UnityEngine; public class InputTrigger : MonoBehaviour { [SerializeField] private TMP_InputField inputField; [SerializeField] private GameObject guideTip; private PlaceableTextBox placeableBox; private void Awake() { placeableBox = GetComponent<PlaceableTextBox>(); inputField.enabled = false; guideTip.SetActive(false); placeableBox.OnPlacedSuccess += HandlePlaceSuccess; } private void HandlePlaceSuccess() { // 显示引导提示,1秒后自动隐藏 guideTip.SetActive(true); Invoke(nameof(HideGuide), 1f); // 延迟0.1秒激活输入框,避免和拖拽抬手事件冲突 Invoke(nameof(ActiveInput), 0.1f); } private void HideGuide() { guideTip.SetActive(false); } private void ActiveInput() { inputField.enabled = true; inputField.Select(); inputField.ActivateInputField(); // 调用这个方法才会自动唤起移动端软键盘 } private void OnDestroy() { placeableBox.OnPlacedSuccess -= HandlePlaceSuccess; } }
注意:不要省掉激活输入框的0.1秒延迟,这是实测踩过的坑——如果在拖拽结束的第一帧直接激活输入框,Unity事件系统会把拖拽的抬手操作识别为输入框外点击,直接触发失焦,导致软键盘闪一下就收起。
移动端适配踩坑提示
- 如果是3D场景内的世界空间文本框,把Canvas上的
GraphicRaycaster换成PhysicsRaycaster,放置检测逻辑换成3D射线检测即可,输入唤起逻辑完全通用 - 安卓端如果出现软键盘弹起把UI顶飞的问题,把
CanvasScaler组件的Screen Match Mode设为Expand即可 - 不需要额外写移动端软键盘的唤起/收起逻辑,
TMP_InputField已经做了全平台适配,直接调用API就行
内容的提问来源于stack exchange,提问作者RobotBoa
相关产品推荐
相关产品推荐

