Flutter領(lǐng)航系列篇02

上一回 Flutter領(lǐng)航系列篇01 我們對Flutter進行了基本的介紹察蹲。
學了基礎(chǔ)控件Scaffold和Text,還學了一個無狀態(tài)組件StatelessWidget催训,通過這幾個組件構(gòu)建了一個應(yīng)用的基本界面洽议。
這一回我們接著上一回完善側(cè)邊抽屜界面,把導(dǎo)航加上漫拭,順便把導(dǎo)航玩兒出一點新花樣來亚兄。

1. 有/無狀態(tài)控件:

我們先簡單講下上回留下的控件狀態(tài)話題,讓大伙兒對控件狀態(tài)有個大致的印象采驻。
在Flutter中控件按狀態(tài)劃分审胚,可以分為兩類:

  • StatelessWidget,表示無狀態(tài)的控件礼旅。
    1. 表示純展示型的控件
    2. 無狀態(tài)內(nèi)部必須有一個build函數(shù)膳叨,用來渲染UI
    3. 每一個項目必須有一個MaterialApp
  • StatefulWidget,表示有狀態(tài)的控件
    1. 打個比方痘系,如果需要私有數(shù)據(jù)菲嘴,例如:
      請求返回的數(shù)據(jù),那就需要聲明有狀態(tài)的控件

按照這個分法汰翠,大伙兒可以看出來咱們目前代碼繼承的是無狀態(tài)控件龄坪。
好,咱們先熱熱身复唤,敲個小代碼:

actions: <Widget>[
  IconButton(
    icon: Icon(Icons.search),
    onPressed: () {}
  )
],

把這段代碼健田,加入AppBar()。
按下R鍵刷新一下佛纫,可以看到界面的右上角出現(xiàn)了一個搜索小圖標妓局,挺有意思吧。

2. 抽屜界面:

接下來呈宇,咱們把上回的抽屜界面(drawer)完善一下跟磨。
這里我們需要講細一點:

  1. listView控件:往drawer()里加入listView控件
  2. children屬性:listview里有一個children屬性,是一個控件數(shù)組攒盈,布局元素就放在這個數(shù)組里邊兒。
  3. UserAccountsDrawerHeader控件:
    • 這里我們可以選擇往children控件數(shù)組里邊兒放入UserAccountsDrawerHeader()控件哎榴。
    • UserAccountsDrawerHeader()控件里邊兒有兩個必填屬性:accountEmail型豁、accountName
    • 如果有頭像需求僵蛛,還可以選擇加入一個currentAccountPicture屬性,如果頭像需要是圓形的迎变,那么代碼如下:
currentAccountPicture:CircleAvatar(
  backgroundImage: NetworkImage('[https://qcloud.dpfile.com/pc/bMbudG0HNlcgJ9mCH9uT_KG-8Lkov5fWOq0Vw93525g-OrTcCi-L0gXpZGLYEEcFTYGVDmosZWTLal1WbWRW3A.jpg](https://qcloud.dpfile.com/pc/bMbudG0HNlcgJ9mCH9uT_KG-8Lkov5fWOq0Vw93525g-OrTcCi-L0gXpZGLYEEcFTYGVDmosZWTLal1WbWRW3A.jpg)')
)充尉,

這里一一解釋一下:

  • CircleAvatar:表示圓形頭像
  • backgroundImage:背景圖
  • NetworkImage:表示是網(wǎng)絡(luò)圖片,這里我在網(wǎng)上隨便找了張圖

這個時候大家不妨運行試試看衣形,可以看到效果如下:

avatar

目前的背景是藍色驼侠,若是期望再加個背景圖的話,可以再加一段兒背景圖谆吴。
代碼如下:

decoration: BoxDecoration(
  image: DecorationImage(
    fix: BoxFix.cover,
    image: NetworkImage('https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=3672957379,325248742&fm=26&gp=0.jpg')
  )
),
  • decoration 屬性對當前控件的做裝飾美化的倒源,他有一個BoxDecoration盒子裝飾器,這里邊兒的image就是背景圖片句狼。
  • fit 屬性是控制填充模式的笋熬,BoxFix.cover 讓圖片適配到容器邊緣。
    如果不明白腻菇,注釋掉胳螟,對比一下效果就知道了。

好啦筹吐,這個時候糖耸,我們接著加入ListTitle()控件,代碼如下:

ListTile(title: Text('我喜歡的'), trailing: Icon(Icons.favorite)),
ListTile(title: Text('我收藏的'), trailing: Icon(Icons.fastfood)),
Divider(),
ListTile(title: Text('個人信息'), trailing: Icon(Icons.face))
  • ListTile 控件就是每一項丘薛,trailing看英文意思也知道是后面的項嘉竟,icon組件就不用說了吧。
  • Divider 看英文意思也知道是分割線啦榔袋。
3. 小Tips:
  1. 大家可以看到左上角時間6:35那個地方周拐,是留白的。
    如果不想留白的話凰兑,可以往child: ListView()里邊兒放一段兒
    padding:EdgeInsets.all(0)妥粟,
    這里padding的參數(shù)不能是數(shù)值,不能像前端寫css一樣直接padding:0
  2. 加了背景圖之后吏够,可以看到字是黑色的勾给,效果不太明顯」可以在text組件里調(diào)整顏色播急,例如:
var color = TextStyle(color: Colors.white);
UserAccountsDrawerHeader(accountEmail: Text('data@data.com', style: color),accountName: Text('飛狐', style: color),
側(cè)邊欄

整體代碼如下:

import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var color = TextStyle(color: Colors.white);
    var avatar = 'https://qcloud.dpfile.com/pc/bMbudG0HNlcgJ9mCH9uT_KG-8Lkov5fWOq0Vw93525g-OrTcCi-L0gXpZGLYEEcFTYGVDmosZWTLal1WbWRW3A.jpg';
    var bgImage = 'https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=3672957379,325248742&fm=26&gp=0.jpg';
    return MaterialApp(
      title: '南帝',
      theme: ThemeData(primarySwatch: Colors.lightBlue),
      home: Scaffold(
        appBar: AppBar(
          title: Text('北丐'),
          actions: <Widget>[
            IconButton(icon: Icon(Icons.search),onPressed: () {})
          ],
        ),
        body: Center(child: Text('中神通')),
        floatingActionButton: FloatingActionButton(onPressed: () {},child: Text('東邪')),
        drawer: Drawer(
          child: ListView(
            padding: EdgeInsets.all(0),
            children: <Widget>[
              UserAccountsDrawerHeader(accountEmail: Text('data@data.com', style: color),accountName: Text('飛狐', style: color),
              currentAccountPicture: 
                CircleAvatar(backgroundImage: NetworkImage(avatar)),
                decoration: BoxDecoration(
                  image: DecorationImage(
                    fit: BoxFit.cover,
                    image: NetworkImage(bgImage)
                  )
                ),
              ),
              ListTile(title: Text('我喜歡的'), trailing: Icon(Icons.favorite)),
              ListTile(title: Text('我收藏的'), trailing: Icon(Icons.fastfood)),
              Divider(),
              ListTile(title: Text('個人信息'), trailing: Icon(Icons.face))
            ],
          )
        ),
      ),
    );
  }
}

側(cè)邊欄就告一段落啦,接下來售睹,我們開始寫導(dǎo)航欄

4. 底部導(dǎo)航前奏-代碼拆分

底部的導(dǎo)航實現(xiàn)其實挺簡單桩警。不過在寫導(dǎo)航之前,咱得先改下結(jié)構(gòu)昌妹。
目的是把 home 控件拎出來捶枢,使其獨立成一個類握截,代碼如下:

import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '周伯通',
      theme: ThemeData(primarySwatch: Colors.lightBlue),
      home: MyHomePage()
    );
  }
}
class MyHomePage extends StatelessWidget {
  // 省略Scaffold的代碼咯...
}

可以看到,主要就兩個步驟:

  1. 新寫一個 MyHomePage 類
  2. 把 Scaffold 拆分過去
5. 底部導(dǎo)航實現(xiàn)

底部導(dǎo)航的實現(xiàn)有3個動作:

  • 新增底部導(dǎo)航區(qū)域控件(bottomNavigationBar)烂叔,步驟如下:
    1. 位置放置與 drawer 控件同級
    2. 新增 Container 容器
    3. 往 Container 容器里添加 decoration 修飾容器谨胞,比如背景色
    4. 高度屬性 height
    5. child 屬性為 TabBar 組件
  • 新增 DefaultTabController,步驟如下:
    1. 把 Scaffold 控件作為子節(jié)點賦值給 child
    2. 同時增加一個 length 屬性蒜鸡,該屬性值表示導(dǎo)航欄的 item 項長度胯努,如下:

DefaultTabController(length: 5, child: Scaffold())

  • body 屬性改為 TabBarView,放置的就是內(nèi)容層

至此逢防,整個完成叶沛,代碼如下:

import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '周伯通',
      theme: ThemeData(primarySwatch: Colors.lightBlue),
      home: MyHomePage()
    );
  }
}
class MyHomePage extends StatelessWidget {
  var color = TextStyle(color: Colors.white);
  var avatar = 'https://qcloud.dpfile.com/pc/bMbudG0HNlcgJ9mCH9uT_KG-8Lkov5fWOq0Vw93525g-OrTcCi-L0gXpZGLYEEcFTYGVDmosZWTLal1WbWRW3A.jpg';
  var bgImage = 'https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=3672957379,325248742&fm=26&gp=0.jpg';
  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: 5,
      child: Scaffold(
        appBar: AppBar(
          title: Text('北丐'),
          actions: <Widget>[
            IconButton(icon: Icon(Icons.search),onPressed: () {})
          ],
        ),
        body: TabBarView(
          children: <Widget>[
            Text('金融'),
            Text('醫(yī)療'),
            Text('中間'),
            Text('量化'),
            Text('我的')
          ],
        ),
        floatingActionButton: FloatingActionButton(onPressed: () {}, child: Text('東邪')),
        drawer: Drawer(
          child: ListView(
            padding: EdgeInsets.all(0),
            children: <Widget>[
              UserAccountsDrawerHeader(accountEmail: Text('data@data.com', style: color),accountName: Text('飛狐', style: color),
              currentAccountPicture: 
                CircleAvatar(backgroundImage: NetworkImage(avatar)),
                decoration: BoxDecoration(
                  image: DecorationImage(
                    fit: BoxFit.cover,
                    image: NetworkImage(bgImage)
                  )
                ),
              ),
              ListTile(title: Text('我喜歡的'), trailing: Icon(Icons.favorite)),
              ListTile(title: Text('我收藏的'), trailing: Icon(Icons.fastfood)),
              Divider(),
              ListTile(title: Text('個人信息'), trailing: Icon(Icons.face))
            ],
          )
        ),
        bottomNavigationBar: Container(
          decoration: BoxDecoration(color: Colors.lightBlue),
          height: 60,
          child: TabBar(
            labelStyle: TextStyle(height: 0.5, fontSize: 12),
            tabs: <Widget>[
              Tab(icon: Icon(Icons.memory), text: '醫(yī)療'),
              Tab(icon: Icon(Icons.money_off), text: '金融'),
              Tab(icon: Icon(Icons.add_circle, size: 52, color: Colors.white)),
              Tab(icon: Icon(Icons.high_quality), text: '量化'),
              Tab(icon: Icon(Icons.my_location), text: '我的')
            ],
          ),
        ),
      ),
    );
  }
}

大家可以運行看看,導(dǎo)航部分效果如下:


導(dǎo)航欄
6. 小彩蛋-底部導(dǎo)航凹凸效果

有些APP,導(dǎo)航欄中間部分是有凹凸效果的,其實也不難實現(xiàn)匆瓜。
飛狐在這里把部分代碼給大家演示一下涯肩,具體封裝成一個很好的控件就是個細活兒了。
替換 bottomNavigationBar,代碼如下:

        bottomNavigationBar: BottomAppBar(
          child: SizedBox(
            height: 60,
            child: Row(
              mainAxisSize: MainAxisSize.max,
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              children: <Widget>[
                Expanded(child: Tab(icon: Icon(Icons.memory), text: '醫(yī)療',), flex: 1),
                Expanded(child: Tab(icon: Icon(Icons.money_off), text: '金融',), flex: 2,),
                Expanded(child: Tab(icon: Icon(Icons.high_quality), text: '量化',), flex: 2),
                Expanded(child: Tab(icon: Icon(Icons.my_location), text: '我的',), flex: 1),
              ],
            ),
          ),
          shape: CircularNotchedRectangle(),
          color: Colors.lightBlueAccent,
        ),

關(guān)鍵點,shape 就是凹陷代碼部分。
還沒完约巷,接著把 floatingActionButton 部分代碼替換如下:

floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
floatingActionButton: FloatingActionButton(onPressed: () {}, child: Icon(Icons.add)),

關(guān)鍵點,floatingActionButtonLocation 讓浮動圖標居中至導(dǎo)航欄中部旱捧。
好啦独郎,大家刷新看效果吧。

導(dǎo)航欄凹凸效果

這一回我們講的控件有點多枚赡,難度適中氓癌,需要小伙伴兒們好好消化一下。
復(fù)盤一下贫橙,這一回我們實現(xiàn)了區(qū)分了組件狀態(tài)贪婉,抽屜界面,導(dǎo)航欄卢肃。
下一篇我們會講到內(nèi)容列表的實現(xiàn)疲迂。

好啦,下回見莫湘。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末尤蒿,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子幅垮,更是在濱河造成了極大的恐慌腰池,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異巩螃,居然都是意外死亡演怎,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門避乏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人甘桑,你說我怎么就攤上這事拍皮。” “怎么了跑杭?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵铆帽,是天一觀的道長。 經(jīng)常有香客問我德谅,道長爹橱,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任窄做,我火速辦了婚禮愧驱,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘椭盏。我一直安慰自己组砚,他們只是感情好,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布掏颊。 她就那樣靜靜地躺著糟红,像睡著了一般。 火紅的嫁衣襯著肌膚如雪乌叶。 梳的紋絲不亂的頭發(fā)上盆偿,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天,我揣著相機與錄音准浴,去河邊找鬼事扭。 笑死,一個胖子當著我的面吹牛兄裂,可吹牛的內(nèi)容都是我干的句旱。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼晰奖,長吁一口氣:“原來是場噩夢啊……” “哼谈撒!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起匾南,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤啃匿,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體溯乒,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡夹厌,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了裆悄。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片矛纹。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖光稼,靈堂內(nèi)的尸體忽然破棺而出或南,到底是詐尸還是另有隱情,我是刑警寧澤艾君,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布采够,位于F島的核電站,受9級特大地震影響冰垄,放射性物質(zhì)發(fā)生泄漏蹬癌。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一虹茶、第九天 我趴在偏房一處隱蔽的房頂上張望逝薪。 院中可真熱鬧,春花似錦写烤、人聲如沸翼闽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽感局。三九已至,卻和暖如春暂衡,著一層夾襖步出監(jiān)牢的瞬間询微,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工狂巢, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留撑毛,地道東北人。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓唧领,卻偏偏與公主長得像藻雌,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子斩个,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容