[flutter]showModalBottomSheet 最完整的 Flutter 範例

 showModalBottomSheet 用於在畫面底部彈出一個 模態(Modal)底部對話框,可用於顯示選項、表單或其他 UI 元件。


最基本的 showModalBottomSheet

import 'package:flutter/material.dart';
void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, home: HomeScreen(), ); } } class HomeScreen extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('BottomSheet 範例')), body: Center( child: ElevatedButton( onPressed: () { showModalBottomSheet( context: context, builder: (BuildContext context) { return Container( padding: EdgeInsets.all(16), height: 200, child: Column( children: [ Text('這是 Bottom Sheet', style: TextStyle(fontSize: 20)), SizedBox(height: 20), ElevatedButton( onPressed: () => Navigator.pop(context), child: Text('關閉'), ), ], ), ); }, ); }, child: Text('打開 BottomSheet'), ), ), ); } }

效果

  • 點擊按鈕後,彈出 底部對話框
  • 點擊「關閉」按鈕後,對話框關閉

讓 BottomSheet 可拖動(isScrollControlled

showModalBottomSheet(
context: context, isScrollControlled: true, // 允許全屏高度 builder: (BuildContext context) { return DraggableScrollableSheet( initialChildSize: 0.5, // 初始高度 50% minChildSize: 0.3, // 最小高度 30% maxChildSize: 0.9, // 最大高度 90% expand: false, builder: (_, scrollController) { return SingleChildScrollView( controller: scrollController, child: Container( padding: EdgeInsets.all(16), child: Column( children: [ Text('可拖動的 Bottom Sheet', style: TextStyle(fontSize: 20)), SizedBox(height: 20), ElevatedButton( onPressed: () => Navigator.pop(context), child: Text('關閉'), ), ], ), ), ); }, ); }, );

效果

  • 可拖動,可以往上拉高、往下拉關閉
  • isScrollControlled: trueBottomSheet 可調整高度

加入 ListView

如果 BottomSheet 裡面有很多內容,建議使用 ListView 來確保滾動正常:

showModalBottomSheet(
context: context, isScrollControlled: true, builder: (context) { return Container( height: MediaQuery.of(context).size.height * 0.7, // 70% 螢幕高度 padding: EdgeInsets.all(16), child: ListView.builder( itemCount: 20, itemBuilder: (context, index) { return ListTile( title: Text('選項 ${index + 1}'), onTap: () => Navigator.pop(context), ); }, ), ); }, );

效果

  • BottomSheet 內部可以 滾動
  • 適合 大量選項列表

自訂圓角樣式

可以使用 shape 設定圓角:

showModalBottomSheet(
context: context, shape: RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(20)), ), builder: (context) { return Container( padding: EdgeInsets.all(16), height: 250, child: Column( children: [ Text('帶圓角的 BottomSheet', style: TextStyle(fontSize: 20)), SizedBox(height: 20), ElevatedButton( onPressed: () => Navigator.pop(context), child: Text('關閉'), ), ], ), ); }, );

效果

  • 上方圓角設計,更美觀

全螢幕 BottomSheet

showModalBottomSheet(
context: context, isScrollControlled: true, // 允許全屏 builder: (context) { return Container( height: MediaQuery.of(context).size.height, // 設定全屏高度 padding: EdgeInsets.all(16), child: Column( children: [ Text('全屏 BottomSheet', style: TextStyle(fontSize: 20)), SizedBox(height: 20), ElevatedButton( onPressed: () => Navigator.pop(context), child: Text('關閉'), ), ], ), ); }, );

效果

  • BottomSheet 佔滿整個螢幕
  • 適用於 全屏選單或表單

返回 Future 獲取 BottomSheet 回傳值

如果要讓 BottomSheet 回傳值給主頁面,可以使用 await

Future<void> _openBottomSheet(BuildContext context) async {
final result = await showModalBottomSheet<String>( context: context, builder: (context) { return Container( padding: EdgeInsets.all(16), height: 250, child: Column( children: [ Text('請選擇一個選項', style: TextStyle(fontSize: 20)), SizedBox(height: 20), ElevatedButton( onPressed: () => Navigator.pop(context, '選擇 A'), child: Text('選擇 A'), ), ElevatedButton( onPressed: () => Navigator.pop(context, '選擇 B'), child: Text('選擇 B'), ), ], ), ); }, ); // 處理 BottomSheet 回傳的值 if (result != null) { ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("你選擇了: $result"))); } }

效果

  • Navigator.pop(context, '選擇 A') 回傳值
  • await 接收回傳值
  • 顯示 SnackBar 提示選擇結果

🚀 總結

功能實現方式
基本 BottomSheetshowModalBottomSheet(context: context, builder: ...)
可拖動 BottomSheetDraggableScrollableSheet
ListView 的 BottomSheetListView.builder()
設定圓角shape: RoundedRectangleBorder(...)
全屏 BottomSheetheight: MediaQuery.of(context).size.height
回傳數據await showModalBottomSheet() + Navigator.pop(context, value)

留言

這個網誌中的熱門文章

flutter 使用 ToastDialog 範例

[flutter]flutter如何防止GPS偽定位

ScaffoldMessenger 範例