點燈坊

失くすものさえない今が強くなるチャンスよ

ModalBottomSheet 顯示由下方彈出 Modal

Sam Xiao's Avatar 2024-10-29

ModalButtonSheet 為手機風格的下拉選單,可自行設計所顯示的 UI。

Version

Flutter 3.24

Flutter

overview01

  • Android 與 iOS 都成功使用 ModalBottomSheet 顯示由下方彈出的 Modal

ModalBottomSheet

import 'package:flutter/material.dart';

class Home extends StatefulWidget {
  const Home({super.key});

  
  State<Home> createState() => _Home();
}

class _Home extends State<Home> {
  var _selectedText = '';

  ListTile buildListTile(
    BuildContext context,
    String text,
    IconData icon,
  ) {
    return ListTile(
      leading: const Icon(Icons.photo),
      title: Text(text),
      onTap: () {
        setState(() => _selectedText = text);
        Navigator.pop(context);
      },
    );
  }

  void _showModalBottomSheet(BuildContext context) {
    var modalBottomSheet = Container(
      padding: const EdgeInsets.all(16.0),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          buildListTile(context, 'Photo', Icons.photo),
          buildListTile(context, 'Music', Icons.music_note),
          buildListTile(context, 'Video', Icons.videocam),
        ],
      ),
    );

    showModalBottomSheet(
      context: context,
      shape: const RoundedRectangleBorder(
        borderRadius: BorderRadius.vertical(
          top: Radius.circular(16),
        ),
      ),
      builder: (BuildContext context) => modalBottomSheet,
    );
  }

  
  Widget build(BuildContext context) {
    var appBar = AppBar(
      title: const Text('ModalBottomSheet'),
    );

    var elevatedButton = ElevatedButton(
      onPressed: () => _showModalBottomSheet(context),
      child: const Text('Show Bottom Sheet'),
    );

    var body = Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [elevatedButton, Text(_selectedText)],
      ),
    );

    return Scaffold(
      appBar: appBar,
      body: body,
    );
  }
}

Line 11

var _selectedText = '';
  • _selectedText:儲存用戶所選擇的項目

Line 58

var elevatedButton = ElevatedButton(
  onPressed: () => _showModalBottomSheet(context),
  child: const Text('Show Bottom Sheet'),
);
  • onPress():當用戶按下 ElevatedButton 時,將 context 傳入自訂的 showModalBottonSheet()

Line 28

void _showModalBottomSheet(BuildContext context) {
  var modalBottomSheet = Container(
    padding: const EdgeInsets.all(16.0),
    child: Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        buildListTile(context, 'Photo', Icons.photo),
        buildListTile(context, 'Music', Icons.music_note),
        buildListTile(context, 'Video', Icons.videocam),
      ],
    ),
  );

  showModalBottomSheet(
    builder: (BuildContext context) => modalBottomSheet,
  );
}
  • modalBottomSheet:定義 ModalBottomSheet 所顯示的 UI
  • showModalBottomSheet():呼叫 Flutter 內建的 showModalBottomSheet() 顯示 ModalBottomSheet

Line 49

showModalBottomSheet(
  context: context,
  shape: const RoundedRectangleBorder(
    borderRadius: BorderRadius.vertical(
      top: Radius.circular(16),
    ),
  ),
  builder: (BuildContext context) => modalBottomSheet,
);
  • 呼叫 Flutter 內建的 showModalBottomSheet() 顯示 ModalBottomSheet
  • builder():定義 ModelBottomSheet 的 UI

Line 29

var modalBottomSheet = Container(
  padding: const EdgeInsets.all(16.0),
  child: Column(
    mainAxisSize: MainAxisSize.min,
    children: [
      buildListTile(context, 'Photo', Icons.photo),
      buildListTile(context, 'Music', Icons.music_note),
      buildListTile(context, 'Video', Icons.videocam),
    ],
  ),
);
  • 定義 ModalBottomSheet 的 UI

Line 13

ListTile buildListTile(
  BuildContext context,
  String text,
  IconData icon,
) {
  return ListTile(
    leading: const Icon(Icons.photo),
    title: Text(text),
    onTap: () {
      setState(() => _selectedText = text);
      Navigator.pop(context);
    },
  );
}
  • ListTileListView 的每個選項
    • leading:顯示一開始的 icon
    • title:設定顯示文字
    • onTap():當點擊時觸發,以 Navigator.pop(context) 關閉 ModalBottomSheet

Conclusion

  • ModalBottomSheet 屬於 Feedback 類 widget,因此必須使用 showModalBottomSheet() 顯示由下方彈出 Modal