Flutter 並沒有提供 DropdownBottomSheet
顯示下方彈出選單,必須自行使用 ModalBottomSheet
與 ListView
實現。
Version
Flutter 3.24
Flutter
- Android 與 iOS 都成功使用
DropdownBottomSheet
顯示由下方彈出的選單
DropBottomSheet
import 'package:flutter/material.dart';
class Home extends StatefulWidget {
const Home({super.key});
State<Home> createState() => _Home();
}
class _Home extends State<Home> {
var _selectedText = 'Select Option';
ListTile buildListTile(
BuildContext context,
String text,
) {
return ListTile(
title: Text(text),
onTap: () {
setState(() => _selectedText = text);
Navigator.pop(context);
},
);
}
void _showModalBottomSheet(BuildContext context) {
showModalBottomSheet(
context: context,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(16),
),
),
builder: (BuildContext context) => ListView(
shrinkWrap: true,
children: [
buildListTile(context, 'Option 1'),
buildListTile(context, 'Option 2'),
buildListTile(context, 'Option 3'),
],
),
);
}
Widget build(BuildContext context) {
var appBar = AppBar(title: const Text('DropdownBottomSheet'));
var dropdownBottomSheet = GestureDetector(
onTap: () => _showModalBottomSheet(context),
child: Container(
margin: const EdgeInsets.all(16.0),
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 12.0),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(8.0),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(_selectedText),
const Icon(Icons.arrow_drop_down),
],
),
),
);
return Scaffold(
appBar: appBar,
body: dropdownBottomSheet,
);
}
}
Line 11
var _selectedText = 'Select Option';
_selectedText
:儲存用戶所選擇的項目
Line 49
var dropdownBottomSheet = GestureDetector(
onTap: () => _showModalBottomSheet(context),
child: Container(
margin: const EdgeInsets.all(16.0),
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 12.0),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(8.0),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(_selectedText),
const Icon(Icons.arrow_drop_down),
],
),
),
);
GestureDetector
:包裹整個Container
,當Container
被點擊時會觸發onTap()
onTap()
:馬上呼叫_showModalBottomSheet()
Line 58
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(_selectedText),
const Icon(Icons.arrow_drop_down),
],
),
- 上方的下拉選單,其實是用
Text
與Icon
組合出來的
Line 23
void _showModalBottomSheet(BuildContext context) {
showModalBottomSheet(
context: context,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(16),
),
),
builder: (BuildContext context) => ListView(
shrinkWrap: true,
children: [
buildListTile(context, 'Option 1'),
buildListTile(context, 'Option 2'),
buildListTile(context, 'Option 3'),
],
),
);
}
- 呼叫
showModalBottomSheet()
顯示ModalBottomSheet
。
Line 34
builder: (BuildContext context) => ListView(
shrinkWrap: true,
children: [
buildListTile(context, 'Option 1'),
buildListTile(context, 'Option 2'),
buildListTile(context, 'Option 3'),
],
),
builder()
:ModelBottomSheet
實際 UI 之處,可在這裡刻任何自己的 UIListView
:建立選單shrinkWarp
:ListView
會根據內容縮小,而不會佔據整個可用空間buildListTile()
:建立ListTile
Line 13
ListTile buildListTile(
BuildContext context,
String text,
) {
return ListTile(
title: Text(text),
onTap: () {
setState(() => _selectedText = text);
Navigator.pop(context);
},
);
}
ListTile
:ListView
的每個選項title
:設定顯示文字onTap()
:當點擊時觸發,以Navigator.pop(context)
關閉ModalBottomSheet
Conclusion
- 上方的下拉選單並不是
DropdownButton
,而是用Text
與Icon
模擬出來而已 - 下方則藉由
ModalBottomSheet
與ListView
搭配模擬出選單