Flutter 並沒有提供 DropdownBottomSheet
顯示兩層選單,必須自行使用 ModalBottomSheet
、ListView
與 Padding
實現。
Version
Flutter 3.24
Flutter
- Android 與 iOS 都成功使用
DropdownBottomSheet
顯示兩層選單
DropdownBottomSheet
import 'package:flutter/material.dart';
class Home extends StatefulWidget {
const Home({super.key});
State<Home> createState() => _Home();
}
class _Home extends State<Home> {
String _selectedText = 'Select Option';
void _showModalBottomSheet(BuildContext context) {
showModalBottomSheet(
context: context,
isScrollControlled: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
),
builder: (BuildContext context) {
var deviceHeight = MediaQuery.of(context).size.height;
return SizedBox(
height: deviceHeight * 0.4,
child: ListView(
shrinkWrap: true,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ListTile(
title: const Text(
'Option 1',
style: TextStyle(fontWeight: FontWeight.bold),
),
onTap: () {
setState(() => _selectedText = 'Option 1');
Navigator.pop(context);
},
),
Padding(
padding: const EdgeInsets.only(left: 32.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ListTile(
title: const Text('Option 1.1'),
onTap: () {
setState(() => _selectedText = 'Option 1.1');
Navigator.pop(context);
},
),
ListTile(
title: const Text('Option 1.2'),
onTap: () {
setState(() => _selectedText = 'Option 1.2');
Navigator.pop(context);
},
),
],
),
),
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ListTile(
title: const Text(
'Option 2',
style: TextStyle(fontWeight: FontWeight.bold),
),
onTap: () {
setState(() => _selectedText = 'Option 2');
Navigator.pop(context);
},
),
Padding(
padding: const EdgeInsets.only(left: 32.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ListTile(
title: const Text('Option 2.1'),
onTap: () {
setState(() => _selectedText = 'Option 2.1');
Navigator.pop(context);
},
),
ListTile(
title: const Text('Option 2.2'),
onTap: () {
setState(() => _selectedText = 'Option 2.2');
Navigator.pop(context);
},
),
ListTile(
title: const Text('Option 2.3'),
onTap: () {
setState(() => _selectedText = 'Option 2.3');
Navigator.pop(context);
},
),
],
),
),
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ListTile(
title: const Text(
'Option 3',
style: TextStyle(fontWeight: FontWeight.bold),
),
onTap: () {
setState(() => _selectedText = 'Option 3');
Navigator.pop(context);
},
),
Padding(
padding: const EdgeInsets.only(left: 32.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ListTile(
title: const Text('Option 3.1'),
onTap: () {
setState(() => _selectedText = 'Option 3.1');
Navigator.pop(context);
},
),
ListTile(
title: const Text('Option 3.2'),
onTap: () {
setState(() => _selectedText = 'Option 3.2');
Navigator.pop(context);
},
),
],
),
),
],
),
],
),
);
},
);
}
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 27
ListTile(
title: const Text(
'Option 1',
style: TextStyle(fontWeight: FontWeight.bold),
),
onTap: () {
setState(() => _selectedText = 'Option 1');
Navigator.pop(context);
},
),
ListTile
:第一層選單,使用ListTile
即可,特別加上粗體
識別
Line 35
Padding(
padding: const EdgeInsets.only(left: 32.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ListTile(
title: const Text('Option 1.1'),
onTap: () {
setState(() => _selectedText = 'Option 1.1');
Navigator.pop(context);
},
),
],
),
)
Padding
:第二層選單只要加上Padding
即可
Conclusion
- 由於
ModalBottomSheet
的builder()
非常靈活,可以自行以Padding
實現兩層選單