본문 바로가기

Unity3D/C#

유니티 TMP InputField Enter 로 보내기 · 입력 끝 처리 (onSubmit, onEndEdit, onValueChanged 차이)

반응형

INPUT onSubmit

 

유니티 TMP InputField 에서 Enter 를 눌렀을 때만 처리하려면 onSubmit 을 씁니다. onEndEdit 은 Enter 말고도 다른 곳을 클릭하거나 Esc 를 눌러 입력이 끝날 때마다 불리고, onValueChanged 는 글자가 바뀔 때마다 불립니다.

 

input.onValueChanged.AddListener(text => Debug.Log("바뀜 " + text));   // 글자가 바뀔 때마다
input.onSubmit.AddListener(text => Debug.Log("보냄 " + text));         // Enter · 모바일 키보드 완료
input.onEndEdit.AddListener(text => Debug.Log("끝 " + text));          // Enter · 다른 곳 클릭 · Esc

 

채팅창, 검색창, 닉네임 입력처럼 글자를 받는 화면은 「언제 처리할지」 가 중요합니다. 채팅을 onEndEdit 에 연결하면 입력칸 밖을 클릭만 해도 메시지가 나가 버립니다. 이 블로그의 예전 글 UI InputField 기본 기능 할당 in Script 는 예전 InputField 로 contentType 과 lineType 을 정하고 onValueChanged · onEndEdit 을 붙이는 예제였습니다. 이번 글에서는 TMP_InputField 로 Enter 를 누르면 메시지가 쌓이고, 입력칸이 비워진 뒤 바로 이어서 칠 수 있는 채팅 입력칸을 만들겠습니다. 세 이벤트가 언제 불리는지도 함께 정리하겠습니다.

 

C# (UNITY 3D)

 

채팅 입력칸 웹 데모 — Enter 를 누르면 onSubmit 으로 메시지가 쌓이고, 다른 곳을 클릭하면 onEndEdit 만 불려 보내지 않고, Esc 는 입력 시작 때 글자로 되돌린다

▲ 아래 ChatInput 의 동작을 옮긴 웹 데모입니다(Unity 화면 아님). 이벤트가 불리는 순서는 TMP_InputField 소스와 같습니다.

 

Enter 를 누르면 onSubmit 이 먼저 불려 메시지가 올라가고 입력칸이 비워진 뒤 onEndEdit 이 불립니다. 다른 곳을 클릭하면 onEndEdit 만 불려 메시지는 나가지 않습니다. Esc 를 누르면 입력을 시작할 때의 글자로 되돌아갑니다.

 

1. 준비 — 입력칸 하나와 글자 둘

 

Hierarchy 에서 UI (Canvas) > Input Field - TextMeshPro 로 입력칸을, UI (Canvas) > Text - TextMeshPro 로 대화 내용과 글자 수를 보여 줄 글자 둘을 만듭니다(예전 버전 메뉴는 UI > …). ChatInput 은 입력칸 오브젝트에 직접 붙이고, text_log 칸에 대화 글자를, text_count 칸에 글자 수 글자를 끌어다 넣습니다.

 

using UnityEngine;
using TMPro;

 

TMP_InputField 와 TMP_Text 를 쓰기 위해 TMPro 를 사용합니다. 이번 코드는 Image 나 Button 을 쓰지 않아 UnityEngine.UI 는 필요 없습니다.

 

2. 채팅 입력칸 코드

 

using UnityEngine;
using TMPro;

//CodeFinder 코드파인더
//From https://codefinder.janndk.com/
[RequireComponent(typeof(TMP_InputField))]
public class ChatInput : MonoBehaviour
{
    public TMP_Text text_log;             // 보낸 말을 쌓아 보여 줄 글자
    public TMP_Text text_count;           // 「12/30」 처럼 글자 수를 보여 줄 글자

    TMP_InputField input_chat;

    void Awake()
    {
        input_chat = GetComponent<TMP_InputField>();
    }

    void Start()
    {
        input_chat.characterLimit = 30;                                  // 30자까지만
        input_chat.lineType = TMP_InputField.LineType.SingleLine;        // Enter 는 줄바꿈이 아니라 보내기

        input_chat.onValueChanged.RemoveAllListeners();
        input_chat.onValueChanged.AddListener(Update_Count);             // 글자가 바뀔 때마다
        input_chat.onSubmit.RemoveAllListeners();
        input_chat.onSubmit.AddListener(Send_Message);                   // Enter 를 눌렀을 때만

        Update_Count(input_chat.text);
    }

    void Update_Count(string text)
    {
        if (text_count != null)
            text_count.text = text.Length + "/" + input_chat.characterLimit;
    }

    void Send_Message(string text)
    {
        string message = text.Trim();
        if (message.Length == 0)
            return;                                                      // 빈 칸 · 공백만이면 안 보냄

        if (text_log != null)
            text_log.text += message + "\n";

        input_chat.text = "";                                            // 비우면 onValueChanged 도 불려 0/30
        input_chat.ActivateInputField();                                 // 이어서 바로 칠 수 있게 다시 포커스
    }
}

 

Play 하면 글자 수 칸에 「0/30」 이 보이고, 칠 때마다 숫자가 올라갑니다. Enter 를 누르면 앞뒤 공백을 지운 메시지가 대화 글자에 한 줄 쌓이고 입력칸은 비워집니다. 공백만 넣고 Enter 를 누르면 아무것도 쌓이지 않습니다.

이 스크립트는 Unity 6000.6.3f1 에서 컴파일 오류 없이 들어갔고, 배치 모드에서 onSubmit 에 「 안녕하세요 」 를 넣으니 대화 글자에 「안녕하세요」 가 쌓이고 입력칸은 빈칸, 글자 수는 「0/30」 이 되었습니다. 다시 포커스가 잡히는 것은 Game 창에서 확인하지 못했습니다. TMP_InputField 소스를 보면 ActivateInputField 는 다음 LateUpdate 에 입력칸을 다시 열도록 예약하는 함수라, Enter 로 입력칸이 닫힌 뒤에 다시 열립니다.

 

변수(variable)
text_log(TMP_Text) : 보낸 메시지를 한 줄씩 쌓아 보여 줄 글자
text_count(TMP_Text) : 지금 글자 수와 최대 글자 수를 보여 줄 글자
input_chat(TMP_InputField) : 같은 오브젝트의 입력칸

 

함수(function)
Update_Count : 글자가 바뀔 때 불려 「5/30」 처럼 글자 수를 보여 줍니다.
Send_Message : Enter 를 누를 때 불려 메시지를 쌓고 입력칸을 비웁니다.

 

3. onValueChanged · onSubmit · onEndEdit 은 언제 불리나

 

TMP_InputField 이벤트가 불리는 때 — 글자를 칠 때 onValueChanged, Enter 와 모바일 완료는 onSubmit 다음 onEndEdit, 다른 곳 클릭은 onEndEdit 만, Esc 는 글자를 되돌린 뒤 onEndEdit

 

Enter 로 끝내면 onSubmit 다음에 onEndEdit 이 불립니다. 모바일 키보드의 완료 버튼도 같은 길을 탑니다. 다른 곳을 클릭하면 onEndEdit 만 불립니다. Esc 를 눌러도 onSubmit 은 불리지 않습니다. Esc 는 Restore On ESC Key 가 켜져 있으면(기본값) 입력을 시작할 때의 글자로 되돌리고(글자가 바뀌어 있었다면 이때 onValueChanged 가 불립니다), 그 글자를 onEndEdit 에 넘깁니다.

Line Type 이 Multi Line Newline 이면 Enter 는 줄바꿈이 되어 onSubmit 이 불리지 않습니다. 채팅처럼 Enter 로 보내려면 Single Line 이나 Multi Line Submit 으로 둡니다.

 

4. 어떻게 끝내든 저장할 값은 onEndEdit

 

input_name.onEndEdit.AddListener(text =>
{
    PlayerPrefs.SetString("nickname", text.Trim());
});

 

닉네임이나 설정값처럼 사용자가 Enter 를 누르지 않고 다른 곳을 눌러도 저장되어야 하는 값은 onEndEdit 이 맞습니다. 반대로 채팅 전송, 검색 실행처럼 「보내기」 의 뜻이 있는 동작은 onSubmit 에 둡니다.

 

5. 입력이 이상할 때 — 자주 하는 실수

 

onSubmit 과 onEndEdit 에 둘 다 연결했더니 onEndEdit 이 빈 글자를 받는다
onSubmit 안에서 입력칸을 비우면 그 뒤에 불리는 onEndEdit 은 비워진 글자를 받습니다. 배치 모드에서 불러 보니 onSubmit("msg") → onValueChanged("") → onEndEdit("") 순서였습니다. 보낸 메시지는 onSubmit 쪽에서 처리합니다.

 

input_age.contentType = TMP_InputField.ContentType.IntegerNumber;
input_age.onEndEdit.AddListener(text =>
{
    if (int.TryParse(text, out int age))
        Debug.Log("나이 " + age);
});

 

숫자만 받게 했는데 글자가 들어 있다
contentType 과 characterLimit 은 사용자가 칠 때만 걸립니다. 코드로 text 에 「12a3」 이나 40자짜리 글을 넣으면 그대로 들어가는 것을 확인했습니다. 빈칸도 올 수 있으니 숫자로 쓸 때는 int.TryParse 로 한 번 더 확인합니다.

 

함께 보기: 예전 InputField 로 contentType · lineType 을 정하는 기본 예제는 예전 글 UI InputField 기본 기능 할당 in Script 에 있습니다.

 

TMP_InputField 동작은 Unity 공식 문서 TMP_InputField (uGUI) 와 Unity 6000.6.3f1 의 ugui 패키지 소스를 기준으로 적었습니다.

 

 

반응형

Google Play 및 Google Play 로고는 Google LLC의 상표입니다.