Flutter

외부 탭할시 키보드는 내려가는데 텍스트필드 포커싱 해제가 안되었던 이슈

flutter developer 2025. 2. 28. 16:54

이름을 입력하고 생년월일을 피커뷰를 띄웠다가 바깥부분을 눌러 피커뷰를 내리면 키보드가 갑자기 다시 올라와버리는 이슈가 발생했다.


🧐 문제원인

문제 발생 플로우를 살펴보자면 위와 같다. 요점은 텍스트필드 포커싱이 유지된채로 바텀시트가 올라와버려 바텀시트가 닫히자마자 바로 유지되었던 텍스트 필드 포커싱 때문에 불필요하게 키보드가 올라오는 것이었다.


🥲 문제 해결 1차 시도 (실패)

처음에는 외부 탭했을 때 키보드가 사라지는 코드를 모든 텍스트필드마다 작성해주는게 중복된다고 생각해서 애초에 최상위 MaterialApp 위젯에서  키보드 외부를 탭하면 포커싱을 해제하는 코드를 적었다. 이때 HitTestBehavior.opaque 를 주어 다른 위젯이 터치이벤트를 가져가더라도 상위 위젯이 이벤트를 받아 포커싱을 해제하게끔 코드를 넣어주었다. 

부가설명: HitTestBehavior 란?

https://github.com/flutter/flutter/issues/74733

 

Flutter에서 HitTestBehavior는 터치 이벤트(gesture)가 위젯의 영역을 초과하여 전달될지, 무시될지, 혹은 캡처될지를 결정하는 역할을 수행한다. 이때 사진처럼 HitTestBehavior는 3가지 옵션이 있다.

deferToChild (기본값) 자식 위젯이 터치 이벤트를 처리할 수 있으면 전달. 없으면 부모가 처리
opaque 현재 위젯이 이벤트를 무조건 가로채고 이벤트를 소비 (자식 위젯이 이벤트를 받지 못함)
translucent 이벤트가 현재 위젯과 자식 위젯 모두에 전달됨 (중첩 이벤트 가능)
  • deferToChild: 부모가 "이거 네가 처리할래?" 하고 자식에게 묻는다. 자식이 처리하면 부모는 관여하지 않음.
  • opaque: 부모가 "내가 다 처리할 거야" 하고 가로챔. 자식은 이벤트를 받을 수 없음.
  • translucent: 부모가 "나도 받을 거고, 너도 받을 거야" 하는 것. 즉, 이벤트가 부모-자식 모두 전달됨.

하지만 이렇게 조치를 취했음에도 위 짤처럼 키보드가 내려가고 피커뷰로 생일을 탭한뒤 피커뷰가 내려가면 다시 자동으로 키보드가 올라와버려서 포커싱 해제가 제대로 안되는 문제가 있었다...ㅠ


😎 문제 해결 2차 시도 (성공)

https://stackoverflow.com/questions/51652897/how-to-hide-soft-input-keyboard-on-flutter-after-clicking-outside-textfield-anyw

스택오버플로우 선생님의 도움을 받아 텍스트필드 자체내에서 포커싱을 해제하는 코드를 넣어보았다. 

 

이렇게 해서야 내가 원하는대로 텍스트 필드 포커싱이 정상적으로 해제되었다. 왜 이전 해결방법이 안먹혔을까를 생각해보면 텍스트필드 포커스와 키보드 포커스가 서로 달라서 material app에서 포커싱 해제코드를 주면 가장 최상위 포커스인 키보드 해제 포커싱만 내려가고 텍스트필드 포커싱이 여전히 남아있어서 생겼던 이슈였다. 외부 탭할시 텍스트필드 포커스를 해제하는 코드는 어쩔 수 없이 매번 한 줄씩 입력해줘야겠구나라는 결론을 얻었다.