💻 개발/Flutter

[Flutter] ModalBottomSheet가 키보드에 의해 가려지는 현상

고도고도 2022. 8. 9. 16:08

블로그 내의 게시물은 PC 버전에 최적화 되어 있습니다.

 

오늘은 ModalBttomSheet를 사용하면서 발생했던 문제에 대해 적어보려고 합니다.

 

ModalBottomSheet에 TextField를 사용하여 키보드로 사용자의 입력을 받으려고 했습니다. 하지만 ModalBottomSheet가 팝업된 키보드의 높이만큼 올라가지 않아서 ModalBottomSheet가 키보드에 가려지는 현상이 발생했습니다.

 

아래와 같은 상황입니다.

키보드가 팝업되면서 ModalBottomSheet를 가려 사용자가 입력한 텍스트를 확인할 수 없는 문제가 발생했습니다.

 

ModalBottomSheet가 키보드에 의해 가려지는 현상

우선 ModalBottomSheet의 속성에 대해 분석했습니다.

그러던 중 isScrollControlled를 발견했고 Default로 false로 되어 있는 것을 발견하고 이를 true로 수정했습니다. 하지만 여전히 문제는 해결되지 않았습니다.

 

해결 방법을 고민하던 중 문득 이런 생각이 떠올랐습니다. 키보드에 의해 가려진 크기만큼 margin이나 padding을 주면 되지 않을까하는 생각이 들었고 이를 적용했습니다. 우선 margin은 이미 사용 중이었기에 padding으로 접근했습니다.

 showModalBottomSheet<void>(
        isScrollControlled: true,
        context: context,
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(16),
        ),
        builder: (context) {
          return Container(
            height: 130,
            margin: const EdgeInsets.all(16),
            padding: EdgeInsets.only(
              bottom: MediaQuery.of(context).viewInsets.bottom,
            ),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                const Text("지역명만 간단하게 입력해주세요.\n'판교동'을 등록하고 싶다면 '판교'를 입력해주세요."),
                const SizedBox(height: 8),
                const TextField(
                  decoration: InputDecoration(
                    hintText: "관심 지역을 입력해주세요.",
                  ),
                ),
                const SizedBox(height: 16),
                InkWell(
                    onTap: () {},
                    child: Container(
                      alignment: Alignment.center,
                      height: 50,
                      width: double.infinity,
                      decoration: BoxDecoration(
                        borderRadius: BorderRadius.circular(16),
                        color: Colors.blue,
                      ),
                      child: const Text(
                        "입력 완료",
                        style: TextStyle(
                            fontSize: 16, fontWeight: FontWeight.bold),
                        textAlign: TextAlign.center,
                      ),
                    )),
              ],
            ),
          );
        });

 

키보드에 의해 가려진 크기를 가져오기 위해선 MediaQuery.of(context).viewInsets.bottom을 사용하면 됩니다. 이해를 돕기 위해 키보드가 올라오기 전, 후의 MediaQuery.of(context).viewInsets.bottom를 출력했습니다.

I/flutter (13569): 0.0 (키보드가 올라오기 전의 출력 결과)
I/flutter (13569): 250.9090909090909 (키보드가 올라온 후의 출력 결과)

 

이렇게 해결될 줄 알았지만 문제는 해결되지 않았고, 키보드에 의해 가려진 크기보다 작은 Container였기에 Padding을 주면 Container 영역을 벗어나는 것이였습니다.  그래서 Container 크기를 키보드의 크기보다 크게 수정했고(기존 130에서 400) 그 결과 ModalBottomSheet가 키보드에 가려지는 문제를 해결할 수 있었습니다.

 

하지만 여전히 문제가 하나 남아있습니다. Container의 height를 400으로 준 탓에 여백이 너무 많았습니다. 그렇다고 height를 지정하지 않으면 최대 크기로 설정되어 ModalBottomSheet가 화면 전체를 덮어버리는 상황이 발생했습니다. 

 

Container의 height를 명시적으로 지정하지 않고 이 문제를 해결할 수 있는 방법을 찾던 도중 Column의 mainAxisSize 속성을 알게됐습니다. Container의 height 대신 Column.mainAxisSize를 mainAxisSize.min을 지정함으로써 Container가 최대 크기를 갖는 것을 방지하고 viewInsets.bottom에 의해 화면이 위로 밀려났을 때도 Column.mainAxisSize + Padding만큼의 height를 가지도록 했습니다.

 

최종 코드는 아래와 같습니다.

showModalBottomSheet<void>(
        isScrollControlled: true,
        context: context,
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(16),
        ),
        builder: (context) {
          return Container(
            padding: EdgeInsets.only(
              bottom: MediaQuery.of(context).viewInsets.bottom,
            ),
            margin: const EdgeInsets.all(16),
            child: Column(
              mainAxisSize: MainAxisSize.min,
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                const Text("지역명만 간단하게 입력해주세요.\n'판교동'을 등록하고 싶다면 '판교'를 입력해주세요."),
                const SizedBox(height: 8),
                const TextField(
                  decoration: InputDecoration(
                    hintText: "관심 지역을 입력해주세요.",
                  ),
                ),
                const SizedBox(height: 16),
                InkWell(
                  onTap: () {},
                  child: Container(
                    alignment: Alignment.center,
                    height: 50,
                    width: double.infinity,
                    decoration: BoxDecoration(
                      borderRadius: BorderRadius.circular(16),
                      color: Colors.blue,
                    ),
                    child: const Text(
                      "입력 완료",
                      style:
                          TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
                      textAlign: TextAlign.center,
                    ),
                  ),
                ),
              ],
            ),
          );
        });

이로써 ModalBottomSheet가 키보드에 가려지는 문제를 해결했습니다. 키보드에 의해 다른 UI가 가려지는 현상은 개발을 진행함에 있어서 자주 접하게 될 문제라고 생각합니다.