Flutter Key Input Error) 텍스트필드의 한글 입력 시 자음 모음이 분리되어 입력되는 현상 해결 방법

요약

이 포스팅은 플러터에서 프로그래밍 로직 오류로 발생하는 자음 모음 분리 현상을 다룬 것입니다.

의외로 한컴 오피스의 한글 소프트웨어에서 자음과 모음이 분리 현상으로 유입되는 분들이 많네요.

윈도우에서 자음과 모음이 분리되는 현상에 대한 해결 방법은,

아래의 포스팅의 '윈도우에서 전각/반각 변환하기' 챕터에서 확인 가능합니다.


Error

플러터로 앱을 개발하던 도중,
안드로이드 에뮬레이터에서 텍스트필드에 입력한 한글이 이상하게 자꾸 자음과 모음이 분리되어 입력되었다.
'ㅁㅏㅊㅣ ㅇㅣㄹㅓㅎㄱㅔ' 마치 이렇게 말이다.
한국 플러터 개발자 커뮤니티에서도 확인해 본 결과,
안드로이드 뿐만 아니라 iOS에서도 발생하는 것을 확인하였고
이 또한 텍스트필드 입력시 한글이 자꾸 이상하게 써진다는 내용이였다.
답변들은 대부분 버그라고 하며 제대로된 해결 방법을 찾지 못하고 있던 찰나
내 경우엔 정말 간단한 실수로 인해 발생되는 현상이라는 것을 깨닫고 말았다...
이 포스팅은 안드로이드만 사용한 한정된 환경이며,

코드 설계 자체의 문제이므로 해결이 되지않고 지속적으로 문제가 발생한다면 진짜 자체적 버그일수도 있다.

<한글의 자음과 모음이 분리되어 입력되는 현상>


원인

안드로이드, iOS, 윈도우 이 플랫폼들에 의한 문제가 아니다.
이는 단순히 텍스트필드의 값을 onChanged를 통해 실시간으로 값을 동기화(상태변환)해주기 때문에
텍스트필드의 위젯이 리렌더링되어 마치 자음과 모음이 분리되어 보이는 현상이다.
보통 이런 코드는 사용자가 입력한 값을 실시간으로 받아 처리하도록 설계가 되어 있을텐데
onChanged에서 setState를 주석 처리 해보고 자음과 모음이 분리되지 않는다면 이와 같은 증상인 것이다.

return TextField(
    controller: textController,
    onChanged: (value) {
      // 주석 처리하고 한글의 자음과 모음이 분리되는지 확인해보자.
      //setState(() => textController.text = value);
    });
}
반응형

해결 방법

이제 원인은 알았다.
그런데 이 상태 변환 부분(setState)을 주석 처리를 하게 되면,
내가 원하는 '사용자의 입력 값을 실시간으로 받는' 의 조건을 만족하지 못하게 된다.
어떻게 해야할까?
 
우선 내가 작성한 자음과 모음이 분리되는 코드를 살펴보자.

  // 텍스트 컨트롤러 생성
  TextEditingController textController = TextEditingController();

  Widget _buildArea() {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          // 텍스트필드 위젯
          TextField(
              controller: textController,
              onChanged: (value) {
                // 입력한 값을 컨트롤러에 업데이트
                setState(() => textController.text = value);
              }),
          // 사용자가 입력한 텍스트 보여주기
          Text("텍스트필드의 입력 값 : ${textController.text}"),
        ],
      ),
    );
  }

사용자가 텍스트필드의 텍스트를 입력하면,

  1. TextEditingController의 값을 입력한 값으로 업데이트하고
  2. 그 값을 컨트롤러의 .text 속성을 통해 텍스트 위젯에 내용을 표시해주는

방식이다.
 
여기서 두 가지의 힌트를 얻을 수 있다.
하나, 텍스트필드의 입력 값은 컨트롤러의 .text 속성을 통해 확인 가능하다.
둘, setState를 통해 관련된 위젯이 다시 렌더링 된다.
 
다시 위의 코드 확인해보자.
onChanged를 통해 value의 파라미터 값을 컨트롤러에 업데이트한다.
그렇게 되면 텍스트필드의 컨트롤러로 되어 있는 TextEditingController로 인하여 텍스트필드는 다시 렌더링이 된다.
즉, 입력중인 자음 혹은 모음이 입력 완료 상태가 되어 분리되는 것처럼 보이는 현상이 발생하는 것이다.
그렇다면 텍스트필드의 컨트롤러가 변화되지 않도록 코드를 변경해보자.
 

  • 텍스트필드의 값 변경(onChanged > setState)
    • 기존 : 컨트롤러에 변경된 값을 업데이트하여 텍스트 위젯으로 내용 출력
    • 변경 : 변경된 값을 문자열 변수에 업데이트하여 텍스트 위젯으로 내용 출력
    • 이렇게 하면 컨트롤러의 상태 변환이 일어나지 않기 때문에 텍스트필드 위젯이 다시 렌더링 되지 않게 된다.
  // 텍스트 컨트롤러 생성
  TextEditingController textController = TextEditingController();

  // 사용자가 입력한 값을 저장하는 변수
  String textContent = "";

  Widget _buildArea() {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          // 텍스트필드 위젯
          TextField(
              controller: textController,
              onChanged: (value) {
                /* 기존 : 값을 컨트롤러에 업데이트 */
                //setState(() => textController.text = value);
                /* 변경 : 값을 문자열 변수에 업데이트 */
                setState(() => textContent = textController.text);
              }),
          // 사용자가 입력한 텍스트 보여주기
          Text("텍스트필드의 입력 값 : $textContent"),
        ],
      ),
    );
  }