Flutter入門進階之旅(十六)Scaffold 腳手架

在本欄的前面章節的學習中,咱們基本上把Flutter中全部的經常使用佈局、組件包括多頁面跳轉路由都介紹過了,細心的讀者可能會發如今前面的課程中咱們每次新建一個Flutter Page的時候都會在根佈局的build方法中直接return一個Scaffold而後,再經過配置Scaffold中的相關屬性來快速的渲染頁面佈局:沒錯Scaffold的出現就是爲了幫助咱們實現基本的 Material Design 佈局結構,簡化咱們頁面開發工做,咱們能夠形象的把Scaffold理解爲頁面搭建的腳手架java

課程學習目標

瞭解並掌握Scaffold中提供的快速搭建頁面的腳手架方法
  • appBar: 顯示在界面頂部的一個菜單導航欄
  • body:頁面中顯示主要內容的區域,可任意指定Widget
  • floatingActionButton: 懸浮按鈕(相似原生Android中的floatingActionButton)
  • drawer、endDrawer:分別用於在左右兩側邊欄展現抽屜菜單
  • bottomNavigationBar:顯示在底部的導航欄按鈕欄

在Flutter腳手架中給咱們提供了上述用於快速構建頁面的經常使用屬性,開發者可根據本身的頁面需求,選擇性的引入不一樣屬性達到定製出不一樣UI呈現的目的,關於Scaffold中的其餘屬性,我就不逐個講解了,下面我結合代碼跟你們一塊測試下上述經常使用方法。git

Scaffold課程完整效果圖

在這裏插入圖片描述
下面我拆分每一部分組件,詳細對Scaffold中經常使用方法作講解說明。

1. appBar

在前面的每一節課程中咱們均可以找到appBar的身影,可是因爲以前的課程重點不在appBar上,因此咱們並無對appBar展開過多的介紹,就僅僅是做爲展現頁面標題使用。github

咱們先來看看Scaffold源碼中對appBar的解釋說明:一個展現在Scaffold頂部的APP Bar數組

/// An app bar to display at the top of the scaffold.
  final PreferredSizeWidget appBar;
複製代碼

一般咱們會給根據不一樣的業務場景設置不一樣的AppBar,關於AppBar的構造方法大部分屬性讀者均可以根據屬性名自解釋,我就不貼出來贅述了,下面我舉幾個經常使用的例子app

1.1 設置Title
appBar: AppBar(
          title: Text("Scaffold 腳手架"),
         ),
複製代碼

標題居中:less

appBar: AppBar(
          title: Text("Scaffold 腳手架"),
          centerTitle: true,
         ),
複製代碼

默認標題位置
標題居中

1.2設置左上角返回按鈕

從上面的代碼以及圖片中咱們看到Scaffold中默認爲咱們在appBar上指定了一個返回的箭頭,點擊箭頭返回上一頁,固然咱們能夠經過leading屬性自定義左上角的圖標,可是當咱們指定了leading點擊事件就須要咱們本身單獨處理了,也就是說,指定了leading以後,咱們就沒辦法在點擊箭頭的時候結束當前頁,可是咱們能夠本身實現這一操做。ide

appBar: AppBar(
          leading: GestureDetector(child: Icon(Icons.print),onTap: (){
            Navigator.of(context).pop();
          }),  //添加leading以後須要重寫點擊事件喚
          title: Text("Scaffold 腳手架"),
          centerTitle: true,
         ),
      
複製代碼

自定義左側按鈕點擊事件

1.3 右側溢出菜單

在Flutter中咱們經過Appbar的 actions屬性設置菜單項,通常重要的菜單選項咱們會直接放在右邊bar上顯示,非重要功能選項咱們會經過PopupMenuButton以三個小點的形式放進摺疊菜單裏,下面咱們結合源碼看下效果圖,讀者一看便知。佈局

appBar: AppBar(
          leading: GestureDetector(child: Icon(Icons.print),onTap: (){
            Navigator.of(context).pop();
          }),  //添加leading以後須要重寫點擊事件喚起抽屜菜單
          title: Text("Scaffold 腳手架"),
          actions: <Widget>[
            IconButton(icon: Icon(Icons.message), onPressed: () {}),
            IconButton(icon: Icon(Icons.access_alarm), onPressed: () {}),
            PopupMenuButton(
                onSelected: (String value) {
                  print('-----------------$value');
                },
                itemBuilder: (BuildContext context) => [
                      new PopupMenuItem(value: "選項一的內容", child: new Text("選項一")),
                      new PopupMenuItem(value: "選項二的內容", child: new Text("選項二")),
                      new PopupMenuItem(value: "選項三的內容", child: new Text("選項三")),
                    ])
          ],
          ),
複製代碼

右側菜單

1.4 標題欄底部TabBar

在原生Android中咱們很熟悉的就是利用TabLayout設置標題欄下方的tab切換效果,在Flutter中咱們經過給AppBar的bottom屬性設置TabBar來完成這一效果。學習

bottom: TabBar(
            controller: _tabController,
            tabs: topTabLists
                .map((element) => Tab(
                      text: element,
                    ))
                .toList(),
// onTap: (index) => {},
          )),
複製代碼

使用TabBar必須傳入controller屬性,咱們經過initState()方法初始化_tabController測試

@override
  void initState() {
    super.initState();
    //初始化頂部TabController
    _tabController = TabController(length: topTabLists.length, vsync: this);
  }
複製代碼

在這裏插入圖片描述
Tab屬性設置icon圖標+文字

bottom: TabBar(
            controller: _tabController,
            tabs: topTabLists
                .map((element) => Tab(
                      text: element,
                      icon: Icon(Icons.print),
                    ))
                .toList(),
// onTap: (index) => {},
          )),
          
複製代碼

在這裏插入圖片描述

2.body部分

根據Scaffold頁面佈局的上下順序,下面咱們講解第二部分body部分。關於body部分在前面的課程中,咱們使用了不少次了,也沒什麼須要特別說的地方,這裏我就不展開介紹了,body做爲一個頁面的主要視圖部分,能夠傳入任意指定的Widget,可現實在屏幕中央,這裏我就不過多贅述了。

body: Container(
        child: Text("內容區域"),
      ),
複製代碼

3.抽屜菜單

在文章開題的時候,我提到了抽屜菜單能夠經過drawer、endDrawer指定左右兩側打開的抽屜菜單。下面咱們就來看下效果。

左側抽屜

drawer: MyDrawer(), //MyDrawer詳細代碼在下面
複製代碼

右側抽屜

endDrawer: MyDrawer(), //MyDrawer詳細代碼在下面
複製代碼

左側抽屜
右側抽屜
上述抽屜相關的 MyDrawer代碼以下

class MyDrawer extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Drawer(
        child: Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[
        Padding(
          padding: const EdgeInsets.only(top: 88.0, bottom: 30.0),
          child: Row(
            children: <Widget>[
              Padding(
                padding: const EdgeInsets.symmetric(horizontal: 16.0),
                child: ClipOval(
                  child: Image.network(
                    "https://avatar.csdn.net/6/0/6/3_xieluoxixi.jpg",
                    width: 60,
                  ),
                ),
              ),
              Text(
                "謝棟",
                style: TextStyle(fontWeight: FontWeight.bold),
              )
            ],
          ),
        ),
        Expanded(
          child: ListView(
            children: <Widget>[
              ListTile(
                leading: const Icon(Icons.settings), title: const Text('我的設置'), ), ListTile( leading: const Icon(Icons.live_help), title: const Text('幫助說明'), ), ListTile( leading: const Icon(Icons.settings), title: const Text('我的設置'), ), ListTile( leading: const Icon(Icons.live_help), title: const Text('幫助說明'), ), ], ), ) ], ));
  }
}
複製代碼

4.floatingActionButton

floatingActionButton在前面講解Button章節中咱們講解過,知識點也比較簡單,就是在頁面佈局快速構建出一個懸浮按鈕。

floatingActionButton: FloatingActionButton(
        onPressed: (){
          print("---------");
        },
        child: Icon(Icons.add),
      ),
複製代碼

在這裏插入圖片描述
咱們能夠經過在Scaffold腳手架中指定floatingActionButtonLocation來指定floatingActionButton顯示的位置。
在這裏插入圖片描述
各個位置屬性基本見名知意,我就不逐個寫效果圖展現了,下面只貼上一個懸停在底部導航欄上的樣式。

floatingActionButtonLocation:
          FloatingActionButtonLocation.centerDocked, //設置FloatingActionButton的位置
    );
複製代碼

在這裏插入圖片描述

5.底部導航欄 bottomNavigationBar

bottomNavigationBar的使用場景還比較多,通常咱們的多頁面app都會經過底部的Tab來切換App首頁展現的不一樣內容,在Flutter的Scaffold中爲咱們提供了快捷用於構建底部Tab的方法,咱們經過給BottomNavigationBar的Items屬性設置須要展現的BottomNavigationBarItem數組便可。

bottomNavigationBar: BottomNavigationBar(
        //不設置該屬性多於三個不顯示顏色
        type: BottomNavigationBarType.fixed,
        items: [
          BottomNavigationBarItem(icon: Icon(Icons.home), title: Text("首頁")),
          BottomNavigationBarItem(icon: Icon(Icons.message), title: Text("消息")),
          BottomNavigationBarItem(
              icon: Icon(Icons.add_a_photo), title: Text("動態")),
          BottomNavigationBarItem(icon: Icon(Icons.person), title: Text("個人"))
        ],
        currentIndex: _currentBottomIndex,
        fixedColor: Colors.blue,
        onTap: (index) => _onBottomTabChange(index),
      ),
複製代碼

在這裏插入圖片描述
這裏有個細節須要說一下,有讀者私下裏問我說設置了bottomNavigationBar的屬性其中tab爲三個的時候能夠正常顯示,可是 多於三個就變成白色了,不能正常顯示
正常顯示
顯示白色,切換效果不明顯

這裏我從源碼角度上給讀者解讀一下。

/// If [fixedColor] is null then the theme's primary color,
  /// [ThemeData.primaryColor], is used. However if [BottomNavigationBar.type] is
  /// [BottomNavigationBarType.shifting] then [fixedColor] is ignored.
  BottomNavigationBar({
    Key key,
    @required this.items,
    this.onTap,
    this.currentIndex = 0,
    BottomNavigationBarType type,
    this.fixedColor,
    this.iconSize = 24.0,
  }) : assert(items != null),
       assert(items.length >= 2),
       assert(
        items.every((BottomNavigationBarItem item) => item.title != null) == true,
        'Every item must have a non-null title',
       ),
       assert(0 <= currentIndex && currentIndex < items.length),
       assert(iconSize != null),
       type = type ?? (items.length <= 3 ? BottomNavigationBarType.fixed : BottomNavigationBarType.shifting),
       super(key: key);
複製代碼

在這裏插入圖片描述
從源碼上的這段標紅線的地方,咱們能夠讀到,當 BottomNavigationBar中的items數量小於等於3時,type爲BottomNavigationBarType.fixed,大於3則爲BottomNavigationBarType.shifting,因此咱們只需在代碼中重載type屬性,大於3個的時候設置type值爲 BottomNavigationBarType.fixed便可。我在一開始的代碼註釋中也解釋了這個問題。

UI小特效 在實現底部導航欄時,Flutter還爲咱們提供了一個Material組件中的相似‘"鑲嵌"效果,使用BottomAppBar配合FloatingActionButton完成,文字描述可能雲裏霧裏的。

一圖勝千言

懸浮按鈕鑲嵌在Bar上

//與FloatingActionButton配合實現"打洞"效果
      bottomNavigationBar: BottomAppBar(
        color: Colors.white,
        shape: CircularNotchedRectangle(), // 底部導航欄打一個圓形的洞
        child: Row(
          children: [
            Tab(text: "首頁", icon: Icon(Icons.home)),
            Tab(text: "消息", icon: Icon(Icons.message)),
            Tab(text: "動態", icon: Icon(Icons.add_a_photo)),
            Tab(text: "個人", icon: Icon(Icons.person)),

          ],
          mainAxisAlignment: MainAxisAlignment.spaceAround, //均分底部導航欄橫向空間
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => _onFabClick,
        child: Icon(Icons.add),
      ),
      floatingActionButtonLocation:
          FloatingActionButtonLocation.centerDocked, //設置FloatingActionButton的位置
    );
    
複製代碼

雖然咱們在上面藉助BottomNavigationBar也實現了相似的效果,可是前者是直接壓在導航欄上面的,然後者是嵌入進去的,效果更逼真。讀者可對比下方的效果圖。

直接壓在導航欄上
懸浮按鈕鑲嵌在Bar上
限於篇幅問題,本篇博文的完整代碼我就不在此貼出來了,有須要的讀者能夠去個人github下載源碼: ScaffoldPage.dart
相關文章
相關標籤/搜索