Flutter 基礎(五)Material 元件之 MaterialApp、Scaffold、AppBar

NiZerin發表於2019-06-10

Flutter基礎(五)Material元件之MaterialApp、Scaffold、AppBar

前言

在上一篇文章Flutter基礎(四)開發Flutter應用前需要掌握的Basics Widget,我們學習了Basics Widget,除了Basics Widget,我們還需要了解Material Components,也就是Material元件。它提供了實現Material Design準則的視覺、行為和動作的Widget。
官方將Material元件分為為幾個型別:

  • 應用程式結構和導航
  • Button
  • 輸入和選擇
  • 對話方塊,警告彈框和皮膚
  • 資訊顯示
  • 佈局

主要介紹應用程式結構和導航,會分為兩篇文章進行介紹,這一篇介紹應用程式結構和導航分類中的MaterialApp、Scaffold、AppBar。

1.MaterialApp

說到Material元件,不得不提到MaterialApp,它包含了許多Widget,這些Widget通常是實現Material Design的應用程式所必需的。
MaterialApp在此前的文章都用過,簡單的使用這裡就不介紹了,這裡主要介紹下路由。
移動App中通常通過全屏元素“螢幕”或“頁面”來顯示內容。在Flutter中,這些元素被稱為route(路由),它們由Navigator管理。Navigator不僅管理了一堆route,還提供管理堆疊的方法 Navigator.push 和 Navigator.pop,通過路由物件的進出棧來控制頁面的跳轉。

flutter路由的使用方式主要有兩種,一種是新建路由,一種是註冊路由。我們分別用這兩種方式寫例子:
首屏是第一個介面,通過第一個介面的按鈕跳轉到第二頁,點選第二頁的按鈕回到第一頁。

1.1 新建路由


import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
 return MaterialApp(
 title: 'Material Components',
 home: FirstPage(),
 );
 }
}

class FirstPage extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
 return Scaffold(
 appBar: AppBar(
 title: Text('第一頁'),
 ),
 body: Padding(
 padding: EdgeInsets.all(30.0),
 child: RaisedButton(
 child:  Text('跳轉到第二頁'),
 onPressed: () {
 Navigator.push(//1
 context,
 MaterialPageRoute(builder: (context) => SecondPage()),
 );
 },
 ),
 ),
 );
 }
}

class SecondPage extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
 return Scaffold(
 appBar: AppBar(
 title: Text('第二頁'),
 ),
 body: Padding(
 padding: EdgeInsets.all(30.0),
 child: RaisedButton(
 child: Text('回到上一頁'),
 onPressed: () {
 Navigator.pop(context);//2
 }),
 ),
 );
 }
}

註釋1處呼叫了Navigator.push,將新建的路由新增到Navigator管理的route堆疊的棧頂,這個路由我們可以自定義,但是建議使用MaterialPageRoute,它是一個模態路由,可以自適應各個平臺進行頁面替換,並提供了相應的頁面切換動畫。在Android平臺時,頁面進入動畫是向上滑動並淡出,退出是相反的動畫,如果是在iOS平臺 ,頁面進入動畫是從右側滑入,退出是相反的動畫。
點選’跳轉到第二頁’按鈕時會跳轉到SecondPage。註釋2處的Navigator.pop用於彈出route堆疊最頂層的Route。效果如下兩個圖所示。

1.2 註冊路由


import 'package:flutter/material.dart';
void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
 return MaterialApp(
 title: 'Material Components',
 home: FirstPage(),
 routes:  <String, WidgetBuilder>{//1
 '/first': (BuildContext context) => FirstPage(),
 '/second': (BuildContext context) => SecondPage(),
 },
 initialRoute: '/first' ,
 );
 }
}

class FirstPage extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
 return Scaffold(
 appBar: AppBar(
 title: Text('第一頁'),
 ),
 body: Padding(
 padding: EdgeInsets.all(30.0),
 child: RaisedButton(
 child: Text('跳轉到第二頁'),
 onPressed: () {
 Navigator.pushNamed(context, '/second');//2
 },
 ),
 ),
 );
 }
}

class SecondPage extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
 return Scaffold(
 appBar: AppBar(
 title: Text('第二頁'),
 ),
 body: Padding(
 padding: EdgeInsets.all(30.0),
 child: RaisedButton(
 child: Text('回到上一頁'),
 onPressed: () {
 Navigator.of(context).pop();
 }),
 ),
 );
 }
}

通過註釋1處的routes用於初始化一個路由列表,當推送路由時,將在routes中查詢路徑名稱,如果名稱存在,則關聯的WidgetBuilder用於構造MaterialPageRoute。註釋2處的Navigator.pushNamed和Navigator.push作用類似,只不過pushNamed的引數為路由的名稱。

2. Scaffold

Scaffold同樣屬於Material元件,它實現了Material Design的基本佈局結構,因此它經常會作為MaterialApp的子Widget, Scaffold會自動填充可用的空間,這通常意味著它將佔據整個視窗或螢幕,並且Scaffold會自動適配螢幕。我們的佈局就是在Scaffold中進行編寫的。


import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
 // This widget is the root of your application.
 @override
 Widget build(BuildContext context) {
 return MaterialApp(
 home: Scaffold(
 appBar: AppBar(
 title: Text('Scaffold示例'),
 ),
 body: Padding(
 padding: EdgeInsets.all(30.0),
 child: Text('Scaffold'),
 ),
 bottomNavigationBar: BottomAppBar(
 child: Container(height: 50),
 ),
 drawer: Drawer(
 child: Center(
 child: Text('抽屜'),
 ),
 ),
 floatingActionButton: FloatingActionButton(
 child: Icon(Icons.add),
 ),
 ),
 );
 }
}

Scaffold的屬性有很多,例子中用了幾個屬性:

  • appBar:用於設定頂部的標題欄。
  • body:顯示Scaffold的主要內容。
  • bottomNavigationBar:用於設定Scaffold的底部導航欄,
  • drawer:用於設定抽屜效果。
  • floatingActionButton:用於設定位於右下角的按鈕。

效果如下所示:

可以看到在AppBar上有個抽屜的按鈕,點選按鈕就會滑出抽屜。

3. AppBar

AppBar由toolbar和其他的可選Widget組成,比如TabBar和FlexibleSpaceBar。
AppBar會在頂部顯示leading、title、actions等內容,底部bottom通常顯示TabBar,下圖展示了這些內容的位置分佈。


import 'package:flutter/material.dart';

void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
 return MaterialApp(
 home: MyScaffld(),
 );
 }
}

class MyScaffld extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
 return Scaffold(
 appBar: AppBar(
 title: Text('AppBar示例'),
 leading: FlutterLogo(colors: Colors.lightGreen),
 actions: <Widget>[
 IconButton(
 icon: Icon(Icons.share),
 onPressed: () {
 print('新增按鈕');
 },
 ),
 ],
 ),
 );
 }
}

這次沒有把所有程式碼寫在MyApp類中,而是將Scaffld的定義放在了MyScaffld類中。

上面程式碼的Widget樹如下所示,遵守Material Design準則的flutter應用的Widget樹大致也是如此。

總結

本文總結了Material元件中的三種Widget,可以說它們是使用Material元件時最常使用的Widget,常用到我們可能會忽略它們。由於篇幅原因,會在下一篇介紹Material元件的其他Widget。


By: Laravel-China 寧澤林
MyBlog: nizer.in

相關文章