Flutter基礎(chǔ)(五)Material組件之MaterialApp、Scaffold、AppBar

本文首發(fā)于公眾號(hào)「劉望舒」

關(guān)聯(lián)系列
ReactNative入門系列
React Native組件
Flutter基礎(chǔ)系列

前言

在上一篇文章Flutter基礎(chǔ)(四)開發(fā)Flutter應(yīng)用前需要掌握的Basics Widget,我們學(xué)習(xí)了Basics Widget,除了Basics Widget,我們還需要了解Material Components,也就是Material組件。它提供了實(shí)現(xiàn)Material Design準(zhǔn)則的視覺、行為和動(dòng)作的Widget。
官方將Material組件分為為幾個(gè)類型:

  • 應(yīng)用程序結(jié)構(gòu)和導(dǎo)航
  • Button
  • 輸入和選擇
  • 對(duì)話框,警告彈框和面板
  • 信息顯示
  • 布局

主要介紹應(yīng)用程序結(jié)構(gòu)和導(dǎo)航,會(huì)分為兩篇文章進(jìn)行介紹,這一篇介紹應(yīng)用程序結(jié)構(gòu)和導(dǎo)航分類中的MaterialApp、Scaffold、AppBar。

1.MaterialApp

說到Material組件,不得不提到MaterialApp,它包含了許多Widget,這些Widget通常是實(shí)現(xiàn)Material Design的應(yīng)用程序所必需的。
MaterialApp在此前的文章都用過,簡(jiǎn)單的使用這里就不介紹了,這里簡(jiǎn)單介紹下路由。
在Android開發(fā)中我們使用Intent來進(jìn)行界面跳轉(zhuǎn),也稱之為原生路由,后來出現(xiàn)了一些路由框架,比如ARouter。
在Flutter中進(jìn)行界面跳轉(zhuǎn)的就是路由,路由用Route類來進(jìn)行表示,Navigator是對(duì)Route進(jìn)行管理的Widget。Navigator不僅管理了一堆route,還提供管理堆棧的方法 Navigator.push 和 Navigator.pop,通過路由對(duì)象的進(jìn)出棧來控制頁(yè)面的跳轉(zhuǎn)。

flutter路由的使用方式主要有兩種,一種是新建路由,一種是注冊(cè)路由。我們分別用這兩種方式寫例子:
首屏是第一個(gè)界面,通過第一個(gè)界面的按鈕跳轉(zhuǎn)到第二頁(yè),點(diǎn)擊第二頁(yè)的按鈕回到第一頁(yè)。

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('第一頁(yè)'),
      ),
      body: Padding(
        padding: EdgeInsets.all(30.0),
        child: RaisedButton(
          child:  Text('跳轉(zhuǎn)到第二頁(yè)'),
          onPressed: () {
            Navigator.push(//1
              context,
              MaterialPageRoute(builder: (context) => SecondPage()),
            );
          },
        ),
      ),
    );
  }
}

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

注釋1處調(diào)用了Navigator.push,將新建的路由添加到Navigator管理的route堆棧的棧頂,這個(gè)路由我們可以自定義,但是建議使用MaterialPageRoute,它是一個(gè)模態(tài)路由,可以自適應(yīng)各個(gè)平臺(tái)進(jìn)行頁(yè)面替換,并提供了相應(yīng)的頁(yè)面切換動(dòng)畫。在Android平臺(tái)時(shí),頁(yè)面進(jìn)入動(dòng)畫是向上滑動(dòng)并淡出,退出是相反的動(dòng)畫,如果是在iOS平臺(tái) ,頁(yè)面進(jìn)入動(dòng)畫是從右側(cè)滑入,退出是相反的動(dòng)畫。
點(diǎn)擊'跳轉(zhuǎn)到第二頁(yè)'按鈕時(shí)會(huì)跳轉(zhuǎn)到SecondPage。注釋2處的Navigator.pop用于彈出route堆棧最頂層的Route。效果如下兩個(gè)圖所示。

image
image

1.2 注冊(cè)路由

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('第一頁(yè)'),
      ),
      body: Padding(
        padding: EdgeInsets.all(30.0),
        child: RaisedButton(
          child: Text('跳轉(zhuǎn)到第二頁(yè)'),
          onPressed: () {
            Navigator.pushNamed(context, '/second');//2
          },
        ),
      ),
    );
  }
}

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

通過注釋1處的routes用于初始化一個(gè)路由列表,當(dāng)推送路由時(shí),將在routes中查找路徑名稱,如果名稱存在,則關(guān)聯(lián)的WidgetBuilder用于構(gòu)造MaterialPageRoute。注釋2處的Navigator.pushNamed和Navigator.push作用類似,只不過pushNamed的參數(shù)為路由的名稱。

2. Scaffold

Scaffold同樣屬于Material組件,它實(shí)現(xiàn)了Material Design的基本布局結(jié)構(gòu),因此它經(jīng)常會(huì)作為MaterialApp的子Widget, Scaffold會(huì)自動(dòng)填充可用的空間,這通常意味著它將占據(jù)整個(gè)窗口或屏幕,并且Scaffold會(huì)自動(dòng)適配屏幕。我們的布局就是在Scaffold中進(jìn)行編寫的。

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的屬性有很多,例子中用了幾個(gè)屬性:

  • appBar:用于設(shè)置頂部的標(biāo)題欄。
  • body:顯示Scaffold的主要內(nèi)容。
  • bottomNavigationBar:用于設(shè)置Scaffold的底部導(dǎo)航欄,
  • drawer:用于設(shè)置抽屜效果。
  • floatingActionButton:用于設(shè)置位于右下角的按鈕。

效果如下所示:


image

可以看到在AppBar上有個(gè)抽屜的按鈕,點(diǎn)擊按鈕就會(huì)滑出抽屜。

3. AppBar

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

image
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類中。

image

上面代碼的Widget樹如下所示,遵守Material Design準(zhǔn)則的flutter應(yīng)用的Widget樹大致也是如此。

image

總結(jié)

本文總結(jié)了Material組件中的三種Widget,可以說它們是使用Material組件時(shí)最常使用的Widget,常用到我們可能會(huì)忽略它們。由于篇幅原因,會(huì)在下一篇介紹Material組件的其他Widget。

Flutter基礎(chǔ)系列
Flutter基礎(chǔ)(一)移動(dòng)開發(fā)的跨平臺(tái)技術(shù)演進(jìn)
Flutter基礎(chǔ)(二)Flutter開發(fā)環(huán)境搭建和Hello World
Flutter基礎(chǔ)(三)Dart快速入門
Flutter基礎(chǔ)(四)開發(fā)Flutter應(yīng)用前需要掌握的Basic Widget
Flutter基礎(chǔ)(五)Material組件之MaterialApp、Scaffold、AppBar
Flutter基礎(chǔ)(六)Material組件之BottomNavigationBar、TabBar、Drawer
Flutter基礎(chǔ)(七)Scrolling Widget之ListView、GridView、PageView
Flutter基礎(chǔ)(八)手勢(shì)相關(guān)Widget:GestureDetector和Dismissible
Flutter基礎(chǔ)(九)資源和圖片
Flutter基礎(chǔ)(十)布局Widget快速入門
Flutter基礎(chǔ)(十一)網(wǎng)絡(luò)請(qǐng)求(Dio)與JSON數(shù)據(jù)解析
Flutter基礎(chǔ)(十二)路由(頁(yè)面跳轉(zhuǎn))與數(shù)據(jù)傳遞
Flutter基礎(chǔ)(十三)Flutter與Android的相互通信


<div align=center>這里不僅分享大前端、Android、Java等技術(shù),還有程序員成長(zhǎng)類文章。</div>
<div align=center><img src="https://user-gold-cdn.xitu.io/2019/7/10/16bd7d4e754df569?w=234&h=231&f=jpeg&s=34771" width="260"/></div>

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容