Flutter - 搭建一個(gè)底部導(dǎo)航

  • 建立導(dǎo)航組件
  • 理解有狀態(tài)組件和無狀態(tài)組件
  • VScode 添加Awesome Flutter Snippets 插件 - 快速生成頁面代碼
  • 數(shù)組..add() 方法
  • onTap() 底部導(dǎo)航點(diǎn)擊事件
  • currentIndex 底部導(dǎo)航組件選擇高亮

我們經(jīng)吃剖可以發(fā)現(xiàn)移動(dòng)端的布局形式,喜歡在底部有一個(gè)類型的導(dǎo)航,一般包括首頁,分類,購物車以及個(gè)人中心的選項(xiàng)卡,當(dāng)點(diǎn)擊時(shí)分別跳進(jìn)不同的頁面,以京東為例:


IMG_2040.PNG

首先,我們需要建立一個(gè)主頁面:

import 'package:flutter/material.dart';
import 'BottomNavigationWidget.dart';
void mian(){
  runApp(MyApp());
}
class MyApp extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'beline App',
      theme: ThemeData.light(), //- 主題顏色
      home: BottomNavgationWidget()
    );
  }
}

主頁面中,我們在MaterialApp組件中使用了theme的屬性,是主題屬性,那么參數(shù)ThemeData.light是一個(gè)亮色.還有其他屬性可以參考API
這里我們新建了一個(gè)組件BottomNavigationWidget.dart,直接在home中放置.
接下來,我們需要建立BottomNavigationWidget.dart這里需要了解一下無狀態(tài)組件(Stateless widget)和有狀態(tài)組件(Stateless widget)

無狀態(tài)組件 or 有狀態(tài)組件

我們前面寫的class都是繼承自StatelessWidget無狀態(tài)組件.這里先對狀態(tài)組件做一個(gè)簡單的區(qū)分,后續(xù)會詳細(xì)講

  1. Stateful widget可以擁有狀態(tài)亲桥,這些狀態(tài)在widget生命周期中是可以變的辽慕,而Stateless widget是不可變的。
  2. Stateful widget至少由兩個(gè)類組成:
    • 一個(gè)StatefulWidget類苟跪。
    • 一個(gè) State類; StatefulWidget類本身是不變的锣披,但是State類中持有的狀態(tài)在widget生命周期中可能會發(fā)生變化精续。

_BottomNavgationWidgetState類是BottomNavgationWidget類對應(yīng)的狀態(tài)類. _BottomNavgationWidgetState類中并沒有build方法,取而代之的是婚脱,build方法被挪到了BottomNavgationWidget方法中

Awesome Flutter Snippets 插件 - 快速生成頁面代碼

這里如果我們安裝了VScode插件Awesome Flutter Snippets就可以通過命令stful直接生成
這里把插件的圖也截出來,避免下載錯(cuò)誤

image.png

接下來我們需要在_BottomNavgationWidgetState中寫我們的地步導(dǎo)航,和普通的類的寫法并沒有特別的區(qū)別,我們需要retuen一個(gè)Scaffold(),里面裝一個(gè)bottomNavigationBar: BottomNavigationBar(),這個(gè)就是底部導(dǎo)航組件,然后通過items中傳入widget數(shù)組,每個(gè)對應(yīng)一個(gè)下面的導(dǎo)航按鈕BottomNavigationBarItem().可以分別設(shè)置icons()圖標(biāo)和title屬性.

bottomNavigationBar: BottomNavigationBar(
        items: [
          BottomNavigationBarItem(
            icon: Icon(
              Icons.home,
              color: Colors.blue,
            ),
            title: Text(
              '首頁',
              style:TextStyle(color: Colors.blue)
            )
          ),
        ]
      ),

完整代碼如下:

import 'package:flutter/material.dart';

//- 動(dòng)態(tài)Widget stful
class BottomNavgationWidget extends StatefulWidget {
  @override
  _BottomNavgationWidgetState createState() => _BottomNavgationWidgetState();
}

class _BottomNavgationWidgetState extends State<BottomNavgationWidget> {
  final _BottomNavgationColor = Colors.blue;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      bottomNavigationBar: BottomNavigationBar(
        items: [
          BottomNavigationBarItem(
            icon: Icon(
              Icons.home,
              color: _BottomNavgationColor,
            ),
            title: Text(
              '首頁',
              style:TextStyle(color: _BottomNavgationColor)
            )
          ),
          BottomNavigationBarItem(
            icon: Icon(
              Icons.donut_large,
              color: _BottomNavgationColor,
            ),
            title: Text(
              '分類',
              style:TextStyle(color: _BottomNavgationColor)
            )
          ),
          BottomNavigationBarItem(
            icon: Icon(
              Icons.search,
              color: _BottomNavgationColor,
            ),
            title: Text(
              '發(fā)現(xiàn)',
              style:TextStyle(color: _BottomNavgationColor)
            )
          ),
          BottomNavigationBarItem(
            icon: Icon(
              Icons.shop,
              color: _BottomNavgationColor,
            ),
            title: Text(
              '購物車',
              style:TextStyle(color: _BottomNavgationColor)
            )
          ),
          BottomNavigationBarItem(
            icon: Icon(
              Icons.account_circle,
              color: _BottomNavgationColor,
            ),
            title: Text(
              '我的',
              style:TextStyle(color: _BottomNavgationColor)
            )
          )
        ]
      ),
    );
  }
}

然后我們運(yùn)行虛擬機(jī),看一下底部導(dǎo)航欄的效果:


image.png

..add() 方法

我們前面已經(jīng)把底部導(dǎo)航已經(jīng)顯示出來了,還不能點(diǎn)擊.我們需要簡單的建5個(gè)頁面,用于底部導(dǎo)航的跳轉(zhuǎn).
5個(gè)簡單的頁面都類似下面的結(jié)構(gòu),只是簡單的一個(gè)Text組件用于區(qū)分頁面
home.dart

import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Home Pages')),
      body: Center(
        child: Text('Home Pages'),
      )
    );
  }
}

把這5個(gè)頁面分別引入底部組件的dart

import 'pages/home.dart';
import 'pages/shop.dart';
import 'pages/usercenter.dart';
import 'pages/faxian.dart';
import 'pages/fenlei.dart';

先在State類中聲明一個(gè)list數(shù)組,此時(shí)我們可以使用..add()方法,分別把各個(gè)組件添加到pagelist變量中

void initState() {
    //- 通過..add()方法添加各個(gè)組件到pagelist
    pagelist
      ..add(HomeScreen())
      ..add(FenLeiScreen())
      ..add(FaxianScreen())
      ..add(ShopScreen())
      ..add(UserCenterScreen());
      super.initState();
  }

onTap() 底部導(dǎo)航點(diǎn)擊事件

我們前面已經(jīng)把各個(gè)頁面引入到底部導(dǎo)航菜單,這個(gè)時(shí)候,我們需要進(jìn)行切換功能.
首先,在State類中聲明一個(gè)變量_currentIndex用于存放指定使用pagelist變量中的組件
然后通過給底部導(dǎo)航欄添加事件,這里需要傳入index,獲取點(diǎn)擊的是第幾個(gè),并賦值給_currentIndex變量

onTap: (int index) {
  setState(() {
    _currentIndex = index;
  });
},

我們在前面引入了底部導(dǎo)航,并沒有引入body,此時(shí)有頁面了,我們可以加上,并通過下標(biāo)返回pagelist中存放的頁面組件顯示的body上

body: pagelist[_currentIndex],

_currentIndex 底部導(dǎo)航組件選擇高亮

在底部導(dǎo)航組件中有一個(gè)屬性,當(dāng)你選中這個(gè)組件的時(shí)候,會有選中樣式

currentIndex: _currentIndex,

完整代碼:


import 'package:flutter/material.dart';
import 'pages/home.dart';
import 'pages/shop.dart';
import 'pages/usercenter.dart';
import 'pages/faxian.dart';
import 'pages/fenlei.dart';

//- 動(dòng)態(tài)Widget stful
class BottomNavgationWidget extends StatefulWidget {
  @override
  _BottomNavgationWidgetState createState() => _BottomNavgationWidgetState();
}

class _BottomNavgationWidgetState extends State<BottomNavgationWidget> {
  final _BottomNavgationColor = Colors.blue;
  int _currentIndex = 0;
  List<Widget> pagelist = List();
  @override
  void initState() {
    //- 通過..add()方法添加各個(gè)組件到pagelist
    pagelist
      ..add(HomeScreen())
      ..add(FenLeiScreen())
      ..add(FaxianScreen())
      ..add(ShopScreen())
      ..add(UserCenterScreen());
      super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: pagelist[_currentIndex],
      bottomNavigationBar: BottomNavigationBar(
        items: [
          BottomNavigationBarItem(
            icon: Icon(
              Icons.home,
              color: _BottomNavgationColor,
            ),
            title: Text(
              '首頁',
              style:TextStyle(color: _BottomNavgationColor)
            )
          ),
          BottomNavigationBarItem(
            icon: Icon(
              Icons.donut_large,
              color: _BottomNavgationColor,
            ),
            title: Text(
              '分類',
              style:TextStyle(color: _BottomNavgationColor)
            )
          ),
          BottomNavigationBarItem(
            icon: Icon(
              Icons.search,
              color: _BottomNavgationColor,
            ),
            title: Text(
              '發(fā)現(xiàn)',
              style:TextStyle(color: _BottomNavgationColor)
            )
          ),
          BottomNavigationBarItem(
            icon: Icon(
              Icons.shop,
              color: _BottomNavgationColor,
            ),
            title: Text(
              '購物車',
              style:TextStyle(color: _BottomNavgationColor)
            )
          ),
          BottomNavigationBarItem(
            icon: Icon(
              Icons.account_circle,
              color: _BottomNavgationColor,
            ),
            title: Text(
              '我的',
              style:TextStyle(color: _BottomNavgationColor)
            )
          )
        ],
        currentIndex: _currentIndex,
        onTap: (int index) {
          setState(() {
            _currentIndex = index;
          });
        },
      ),
    );
  }
}
image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末今魔,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子障贸,更是在濱河造成了極大的恐慌错森,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件篮洁,死亡現(xiàn)場離奇詭異涩维,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)袁波,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進(jìn)店門瓦阐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人锋叨,你說我怎么就攤上這事垄分。” “怎么了娃磺?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵薄湿,是天一觀的道長。 經(jīng)常有香客問我偷卧,道長豺瘤,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任听诸,我火速辦了婚禮坐求,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘晌梨。我一直安慰自己桥嗤,他們只是感情好须妻,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著泛领,像睡著了一般荒吏。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上渊鞋,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天绰更,我揣著相機(jī)與錄音,去河邊找鬼锡宋。 笑死儡湾,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的执俩。 我是一名探鬼主播徐钠,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼奠滑!你這毒婦竟也來了丹皱?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤宋税,失蹤者是張志新(化名)和其女友劉穎摊崭,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體杰赛,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡呢簸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了乏屯。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片根时。...
    茶點(diǎn)故事閱讀 40,680評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖辰晕,靈堂內(nèi)的尸體忽然破棺而出蛤迎,到底是詐尸還是另有隱情,我是刑警寧澤含友,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布替裆,位于F島的核電站,受9級特大地震影響窘问,放射性物質(zhì)發(fā)生泄漏辆童。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一惠赫、第九天 我趴在偏房一處隱蔽的房頂上張望把鉴。 院中可真熱鬧,春花似錦儿咱、人聲如沸庭砍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽怠缸。三九已至峰搪,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間凯旭,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工使套, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留罐呼,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓侦高,卻偏偏與公主長得像嫉柴,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子奉呛,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評論 2 361

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