Как заставить поле ввода TextMeshPro настроить свою область raycast на основе его текста?

Я создаю пользовательский интерфейс для своей игры. Я уже создал простые элементы, такие как анимированные кнопки и многофункциональные переключатели, но у меня возникла проблема с полями ввода.

Вот как это выглядит сейчас.

введите здесь описание изображения


Моя цель

Область приема Raycast должна быть того же размера, что и текст.

Поворот текста должен быть (0,5, 0,5), потому что анимация меняет свой масштаб. Неприятно, когда длинный текст масштабируется не по центру. Область Raycast не должна зависеть от масштаба.


Мои попытки

введите здесь описание изображения

input-32 имеет элемент Layout Element с Flexible Width, равным 1, поэтому он должен заполнять все доступное пространство. Текстовая область имеет Группу горизонтального макета (см. рисунок). Внутри находится разделитель со значением Flexible Width равным 1, заполнитель и текст.

Теперь это работает:

введите здесь описание изображения

Выделение не на месте, а текст иногда неконтролируемо летит влево. Кажется, что поле ввода не ожидает наличия здесь других элементов, кроме текста и заполнителя, и работает так, как будто их нет.

Хорошо, тогда поместите разделитель непосредственно под input-32. Однако поведение точно такое же.

Я выяснил, что поле разрывается, когда я добавляю Подбор размера содержимого к текстовому элементу. Но как контролировать его ширину, от которой зависит рейкастинг? Вероятно, мне следует не изменять размер текста, а переопределить его raycasting, но я не знаю, как это сделать.


Должен признаться, я не понимаю, как поля ввода TextMeshPro работают на низком уровне, и поэтому мои попытки терпят неудачу. Вы можете мне помочь или хотя бы подсказать?


person trollingchar    schedule 11.05.2019    source источник
comment
Итак, из любопытства, если поле ввода содержит пустую строку (""), потому что оно либо было пустым пользователем, либо каким-либо иным образом заполнено строкой нулевой длины, какой ширины должна быть кликабельная область?   -  person Draco18s no longer trusts SE    schedule 12.05.2019
comment
@ Draco18s У него должна быть минимальная ширина, иначе на него нельзя будет нажать.   -  person trollingchar    schedule 12.05.2019


Ответы (1)


Я попробовал несколько комбинаций ContentSizeFitter и HorizontalLayoutGroup, как и вы, и это не сработало. Я также попытался сделать установщик нестандартного размера. В конце концов, я создал простой компонент, который просто изменяет размер текстового поля в соответствии с предпочтительным размером текста в каждом кадре. Его можно немного оптимизировать, но в моих тестах он работает довольно хорошо. Я думаю, что удаление изменения размера из системы компоновки пользовательского интерфейса устраняет проблемы с кареткой — поскольку каретка перемещается в системе компоновки, и две вещи борются друг с другом.

Единственная проблема, которую я заметил при таком подходе, заключается в том, что пробел в конце ввода не влияет на «предпочтительный размер» текста (не совсем уверен, почему), поэтому текстовое поле не расширяется, чтобы показать это.

Вам также, вероятно, следует удалить компонент RectMask2D в игровом объекте «Текстовая область», так как оставление его там отрезает половину каретки (и не требуется в вашем случае).

Добавьте этот скрипт к вашему объекту с включенным TMP_InputField:

using TMPro;
using UnityEngine;
using UnityEngine.UI;

public class ResizeInputToMatchText : MonoBehaviour
{
    private RectTransform m_Rect;
    private RectTransform m_inputFieldRect;

    private RectTransform rectTransform
    {
        get
        {
            if (m_Rect == null)
                m_Rect = GetComponent<RectTransform>();
            return m_Rect;
        }
    }

    private RectTransform inputFieldTextRectTransform
    {
        get
        {
            if (m_inputFieldRect == null)
                m_inputFieldRect = GetComponent<TMP_InputField>().textComponent.rectTransform;
            return m_inputFieldRect;
        }
    }

    private void Update()
    {
        rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, LayoutUtility.GetPreferredSize(inputFieldTextRectTransform, 0));
        inputFieldTextRectTransform.localPosition = Vector3.zero; // stops the text scrolling sideways - it doesn't need to
    }
}
person eAi    schedule 11.05.2019
comment
Спасибо, я попробую это. - person trollingchar; 11.05.2019
comment
Хорошо, я попробовал это, но я думаю, что у меня неправильная настройка компонентов на объектах. Мой текст выровнен по центру, и когда я его выбираю, он быстро трясется. Какая установка компонентов должна быть у меня? Кстати, спасибо за подсказку о LayoutUtility. - person trollingchar; 12.05.2019