You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 14:36:22