본문 바로가기

일::개발

Flutter: select box input 만들기

이렇게 생긴 select input을 만들고 싶을 때 일단 DropdownButton으로 시도해보자.

표시되는 값은 '비공개', '남성', '여성' 으로 하고 설정되는 값은 각각 null, 'M', 'F' 를 받기로 한다.

Container(
	child: Column(
    	children: [
        ......,
        DropdownButton<String?>(
              items:
                  [null, 'M', 'F'].map<DropdownMenuItem<String?>>((String? i) {
                return DropdownMenuItem<String?>(
                  value: i,
                  child: Text({'M': '남성', 'F': '여성'}[i] ?? '비공개'),
                );
              }).toList(),
            )
		],
	)
)

 

비활성화 상태로 동작하지 않는다. onChanged 콜백을 넣어주자.

            DropdownButton<String?>(
              onChanged: (String? newValue) {
                print(newValue);
              },
              items:
                  [null, 'M', 'F'].map<DropdownMenuItem<String?>>((String? i) {
                return DropdownMenuItem<String?>(
                  value: i,
                  child: Text({'M': '남성', 'F': '여성'}[i] ?? '비공개'),
                );
              }).toList(),
            )

이제 클릭하면 선택할 수 있는 옵션이 나타난다.

 

 

성별을 입력하라는 label을 바로 위에 표시하고 싶은데, DropdownButton에는 labelTetxt parameter가 없다. 텍스트 위젯으로 표시해본다.

 

            Text("성별", style: TextStyle(fontSize: 15, color: Color(0xffcfcfcf))),
            DropdownButton<String?>(
              onChanged: (String? newValue) {
                print(newValue);
              },
              items:
                  [null, 'M', 'F'].map<DropdownMenuItem<String?>>((String? i) {
                return DropdownMenuItem<String?>(
                  value: i,
                  child: Text({'M': '남성', 'F': '여성'}[i] ?? '비공개'),
                );
              }).toList(),
            )

왼쪽 정렬하고 DropdownButton은 화면에 꽉 차게 그리고 싶다. '성별' 텍스트와 DropdownButton 사이는 좀 더 붙이고 싶다.

 

Column에

    crossAxisAlignment: CrossAxisAlignment.start,

옵션을 주면 왼쪽 정렬이 되는데, label과 버튼의 간격을 줄이고 DropdownButton을 화면 전체로 만드는 것이 쉽지 않다.

 

미묘하게 원하는 모양이 나오지 않는다.

DropdownButton 대신 decoration parameter가 있는 DropdownButtonFormField 를 써보자.

 

            DropdownButtonFormField<String?>(
              decoration: InputDecoration(
                labelText: '성별',
                labelStyle: TextStyle(fontSize: 15, color: Color(0xffcfcfcf)),
              ),
              onChanged: (String? newValue) {
                print(newValue);
              },
              items:
                  [null, 'M', 'F'].map<DropdownMenuItem<String?>>((String? i) {
                return DropdownMenuItem<String?>(
                  value: i,
                  child: Text({'M': '남성', 'F': '여성'}[i] ?? '비공개'),
                );
              }).toList(),
            )

decoration parameter를 제외하면 DropdownButton과 동일하다.

'남성' 을 선택했을 때는 label이 정상적으로 표시되는데, '비공개'를 선택하면 label과 Dropdown이 겹쳐서 보인다.

value가 null 일 때 값이 입력되지 않은 것으로 인식해서 label을 크게 보여주게 동작하기 때문이다.

value를 [null, 'M', 'F] 대신 ['', 'M', 'F'] 로 설정하거나

'비공개' 의 value를 '' 로, 기본값을 '' 로 설정

value가 null일 때의 text를 '' 로 선택하면 이상하지 않게 보인다.

null일 때 공백문자 표시

혹은 label이 움직이지 않도록 decoration에 floatingLabelBehavior: FloatingLabelBehavior.always, 옵션을 주면 된다.

 

            DropdownButtonFormField<String?>(
              decoration: InputDecoration(
                labelText: '성별',
                floatingLabelBehavior: FloatingLabelBehavior.always,
                labelStyle: TextStyle(fontSize: 15, color: Color(0xffcfcfcf)),
              ),
              // underline: Container(height: 1.4, color: Color(0xffc0c0c0)),
              onChanged: (String? newValue) {
                print(newValue);
              },
              items:
                  [null, 'M', 'F'].map<DropdownMenuItem<String?>>((String? i) {
                return DropdownMenuItem<String?>(
                  value: i,
                  child: Text({'M': '남성', 'F': '여성'}[i] ?? '비공개'),
                );
              }).toList(),
            )