플러터에서 드랍다운 메뉴를 제공하는 위젯은 DropdownButton
, DropdownButtonFormField
두가지 입니다.
두 위젯은 UI 상으로는 거의 동일한 모습을 보입니다.
그렇다면 어떤 상황에 각각의 위젯을 사용할까요?
이해를 위해 예시를 살펴보도록 하겠습니다.
DropdownButton<String>(
value: dropdownValue,
onChanged: (String? newValue) {
setState(() {
dropdownValue = newValue!;
});
},
items: <String>['One', 'Two', 'Three', 'Four']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
)
해당 위젯은 4가지의 선택지 중 하나를 선택하는 옵션을 유저에게 제공합니다.
하지만 유저가 선택을 했는지 안했는지는 판단할 수 없습니다.
DropdownButtonFormField<String>(
value: dropdownValue,
onChanged: (String? newValue) {
setState(() {
dropdownValue = newValue!;
});
},
items: <String>['One', 'Two', 'Three', 'Four']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please select an option';
}
return null;
},
)
이와 반대로 DropdownButtonFormField는 validator 프로퍼티를 가지고 있습니다.
해당 프로퍼티를 통해, 만약 유저가 드랍다운 메뉴에 입력을 하지 않았을 경우, 경고문을 출력할 수 있습니다.
위의 예시의 경우 사용자가 아무 것도 선택하지 않았을 경우 ‘Please select an option’이 출력됩니다.
다음 단락에서는 해당 내용을 반영한 더 자세한 예시를 살펴보겠습니다.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: MyCustomForm(),
),
);
}
}
class MyCustomForm extends StatefulWidget {
const MyCustomForm({super.key});
MyCustomFormState createState() {
return MyCustomFormState();
}
}
class MyCustomFormState extends State<MyCustomForm> {
final _formKey = GlobalKey<FormState>();
String? dropdownValue;
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 16),
child: DropdownButtonFormField<String>(
value: dropdownValue,
icon: const Icon(Icons.arrow_downward),
decoration: InputDecoration(
labelText: 'Select an Option',
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
),
),
items: <String>['Option 1', 'Option 2', 'Option 3', 'Option 4']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: (String? newValue) {
setState(() {
dropdownValue = newValue!;
});
},
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please select an option';
}
return null;
},
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 16),
child: ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Processing Data')));
}
},
child: const Text('Submit'),
),
),
],
),
);
}
}