滑動底盤 Bottom Sheet


Scaffold 有個 bottomSheet 特性,被設定的元件會自動隨底部可用空間滑動,通常會用來設定輸入欄位之類的元件,在鍵盤出現時,輸入欄位始終在鍵盤上面。例如:

import 'package:flutter/material.dart';

void main() => runApp(
  MaterialApp(
    home: Scaffold(
      appBar: AppBar(
        title: Text('Openhome.cc'),
      ),
      body: Column(
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          Center(
            child: Image.network('https://openhome.cc/Gossip/images/caterpillar.jpg')
          )
        ],
      ),
      bottomSheet: TextField(
        decoration: InputDecoration(
          labelText: '搜尋',
          hintText: '搜尋文件',
          prefixIcon: Icon(Icons.search),
        ),
      ),
    )
  )
);

執行結果如下:

滑動底盤 Bottom Sheet

比較一下跟底下範例有何不同:

import 'package:flutter/material.dart';

void main() => runApp(
  MaterialApp(
    home: Scaffold(
      appBar: AppBar(
        title: Text('Openhome.cc'),
      ),
      body: Column(
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          Center(
            child: Image.network('https://openhome.cc/Gossip/images/caterpillar.jpg')
          ),
          TextField(
            decoration: InputDecoration(
              labelText: '搜尋',
              hintText: '搜尋文件',
              prefixIcon: Icon(Icons.search),
            ),
          ),
        ],
      )
    )
  )
);

執行結果如下:

滑動底盤 Bottom Sheet

喔喔!可以看到輸入欄位並沒有隨著鍵盤往上滑,而由於空間不足以繪製完全部的元件,還會有超出範圍的警示黃線出現。

ScaffoldbottomSheet 特性是設定固定元件用的,如果想要動態地呈現滑動底盤,可以使用 showBottomSheet,例如:

import 'package:flutter/material.dart';

void main() => runApp(
  MaterialApp(
    home: Scaffold(
      appBar: AppBar(
        title: Text('Openhome.cc'),
      ),
      body: Body()
    )
  )
);

class Body extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.center,
      children: [
        Center(
          child: GestureDetector(
            child: Image.network('https://openhome.cc/Gossip/images/caterpillar.jpg'),
            onTap: () {
              // 顯示滑動底盤
              showBottomSheet(
                context: context,
                builder: (context) {
                  // 子元件
                  return Container(
                    height: 200,
                    color: Colors.lightGreen,
                    child: Center(
                      child: RaisedButton(
                        child: Text('關閉滑動底盤'),
                        // 彈出路由
                        onPressed: () => Navigator.pop(context),
                      ),
                    ),
                  );
                }
              );
            },
          )
        ),
      ]
    );
  }
}

從程式碼中可以看到,因為會使用路由堆疊來管理滑動底盤,要關閉底盤時必須彈出路由,另外也可以用拖曳的方式關閉底盤:

滑動底盤 Bottom Sheet

另外還有個 showModalBottomSheet,顧名思義就是獨佔式的滑動底盤,將上例中的 showBottomSheet 改為 showModalBottomSheet,就會有以下效果:

滑動底盤 Bottom Sheet