Flutter學(xué)習(xí)筆記--仿閑魚底部導(dǎo)航欄帶有中間凸起圖標

image

霸圖鎮(zhèn)樓

仿閑魚底部導(dǎo)航欄帶有中間凸起圖標

需求情景: 需要實現(xiàn)一個類似閑魚APP的底部導(dǎo)航欄的實現(xiàn)

Demo地址 : https://github.com/hanlin19900610/flutter_bottom_navigation_bar

要實現(xiàn)的效果如圖
image

好的,下面開始上代碼了:

一. 在main.dart文件中,定義APP的入口信息
import 'package:flutter/material.dart';import 'pages/MainPage.dart';void main() => runApp(LightLanguageClient());class LightLanguageClient extends StatelessWidget{    @override
  Widget build(BuildContext context) {        return MaterialApp(
      title: 'Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue
      ),
      home: MainPage(),
    );
  }
}
二. 我們需要定義三個頁面,功能類似Android的Fragment,分別為HomePage.dart, AssistantPage.dart,MinePage.dart, 這三個頁面的代碼很簡單:
import 'package:flutter/material.dart';class HomePage extends StatefulWidget{    @override
  State<StatefulWidget> createState() {        return _HomePageState();
  }
}class _HomePageState extends State<HomePage>{   @override
  Widget build(BuildContext context) {        return MaterialApp(
      home: Scaffold(
        body: Center(
          child: Text('這是首頁'),
        ),
      ),
    );
  }
}

這個三個頁面的代碼都一樣就沒有都貼出來

三.現(xiàn)在我們就需要去創(chuàng)建我們的主頁了,”MainPage.dart”文件
第一步,我們先去實現(xiàn)一個最簡單的底部導(dǎo)航欄
import 'package:flutter/material.dart';import 'HomePage.dart';import 'AssistantPage.dart';import 'MinePage.dart';class MainPage extends StatefulWidget {    @override
  State<StatefulWidget> createState() {        return _MainPage();
  }
}class _MainPage extends State<MainPage> with SingleTickerProviderStateMixin {
  PageController pageController;    int page = 0;    @override
  Widget build(BuildContext context) {        return MaterialApp(
      home: Scaffold(
        body: new PageView(
          children: <Widget>[HomePage(), AssistantPage(), MinePage()],
          controller: pageController,
          onPageChanged: onPageChanged,
      ),
      bottomNavigationBar: BottomNavigationBar(
        items: [
          BottomNavigationBarItem(icon: Icon(Icons.home), title: Text('首頁')),
          BottomNavigationBarItem(icon: Icon(Icons.assessment), title: Text('助手')),
          BottomNavigationBarItem(icon: Icon(Icons.person), title: Text('我的')),
        ],
        onTap: onTap,
        currentIndex: page,
      ),
    ));
  }    @override
  void initState() {        super.initState();
    pageController = PageController(initialPage: this.page);
  }    @override
  void dispose() {    super.dispose();
    pageController.dispose();   
  }        void onTap(int index) {
    pageController.animateToPage(index,
        duration: const Duration(milliseconds: 300), curve: Curves.ease);
  }      void onPageChanged(int page) {
    setState(() {            this.page = page;
    });
  }
}
在MainPage.dart中我們用到了幾個控件:
1. PageView : 此控件類似Android的ViewPager,把之前創(chuàng)建的3個頁面一次添加進去,之后需要給PageView設(shè)置一個控制器-PageController,給PageView設(shè)置一個onPageChanged頁面切換監(jiān)聽方法,此方法的功能類似與Android中ViewPager中的OnPageChangeListener里的監(jiān)聽方法
2. BottomNavigationBar :此控件主要用于配置底部導(dǎo)航欄,詳細用法請參見官方文檔,在此控件的使用中,我們需要設(shè)置三個屬性,
  1. items: 添加底部導(dǎo)航欄的每個Item

  2. onTap: 為底部導(dǎo)航欄設(shè)置點擊事件

  3. currentIndex: 為底部導(dǎo)航設(shè)置當前選中項

image

四.我們要實現(xiàn)仿閑魚的底部導(dǎo)航欄,需要重構(gòu)一下底部導(dǎo)航欄,

重構(gòu)方案:
1.把中間的文字去掉
2.在BottomNavigationBar控件的中上的位置放入一個圖片
3.重構(gòu)底部導(dǎo)航的事件方法
4.禁止PageView的滑動事件
現(xiàn)在開始重構(gòu):
1.要在BottomNavigationBar上面覆蓋一個圖片,我們需要用到一個布局Widget—-Stack,類似于Framelayout
class _MainPage extends State<MainPage> with SingleTickerProviderStateMixin {
  PageController pageController;   int page = 0;  //添加圖片地址,需要動態(tài)更換圖片
  String bigImg = 'images/home_green.png';   @override
  Widget build(BuildContext context) {        return MaterialApp(
      home: Scaffold(
      body: new PageView(
        children: <Widget>[HomePage(), AssistantPage(), MinePage()],
        controller: pageController,
        onPageChanged: onPageChanged,
      ),      //重構(gòu)bottomNavigationBar
      bottomNavigationBar: Stack(
        children: <Widget>[
          Align(
            alignment: Alignment.bottomCenter,
            child: BottomNavigationBar(
              items: [
                BottomNavigationBarItem(icon: Icon(Icons.home), title: Text('首頁')),
                BottomNavigationBarItem(icon: Icon(Icons.assessment), title: Text('')),
                BottomNavigationBarItem(icon: Icon(Icons.person), title: Text('我的')),
              ],
              onTap: onTap,
              currentIndex: page,
            ),
          ),
          Align(
            alignment: Alignment.bottomCenter,
            child: InkWell(
              child: new Image.asset(bigImg,width: 80.0,height: 80.0,),
              onTap:onBigImgTap,
            ),
          )
        ],
      )
    ));
  }    @override
  void initState() {        super.initState();
    pageController = PageController(initialPage: this.page);
  }    @override
  void dispose() {    super.dispose();
    pageController.dispose();    
  }  //修改bottomNavigationBar的點擊事件
  void onTap(int index) {        if (index != 1) {
      setState(() {                this.bigImg = 'images/home_green.png';
      });
    }
    pageController.animateToPage(index,
        duration: const Duration(milliseconds: 300), curve: Curves.ease);
  }  //添加圖片的點擊事件
  void onBigImgTap() {
    setState(() {            this.page = 1;            this.bigImg = 'images/icon_home.png';
      onTap(1);
    });
  }    void onPageChanged(int page) {
    setState(() {            this.page = page;
    });
  }
}

重構(gòu)完成之后,效果圖如下,我們發(fā)現(xiàn)這并不是我們想要的,底部導(dǎo)航欄我們是實現(xiàn)了,但是PageView被遮蓋了

image
PageView被遮蓋的解決辦法,我們給Stack添加一個可以指定高度的父級—Container,修改的代碼如下:
bottomNavigationBar: Container(
            height: 100.0,
            child: Stack(
              children: <Widget>[
                Align(
                  alignment: Alignment.bottomCenter,
                  child: BottomNavigationBar(
                    items: [
                      BottomNavigationBarItem(
                          icon: Icon(Icons.home), title: Text('首頁')),
                      BottomNavigationBarItem(
                          icon: Icon(Icons.accessibility_new), title: Text('')),
                      BottomNavigationBarItem(
                          icon: Icon(Icons.person), title: Text('我的')),
                    ],
                    onTap: onTap,
                    currentIndex: page,
                  ),
                ),
                Align(
                    alignment: Alignment.bottomCenter,
                    child: Padding(
                      padding: const EdgeInsets.only(bottom: 10.0),
                      child: InkWell(
                        child: new Image.asset(
                          bigImg,
                          width: 80.0,
                          height: 80.0,
                        ),
                        onTap: onBigImgTap,
                      ),
                    )),
              ],
            ),
          )
然后我們需要禁止PageView的滑動,我們只需要在給PageView設(shè)置一個屬性就好了
physics: NeverScrollableScrollPhysics(),
在運行Flutter項目的時候出現(xiàn)了一個問題,運行時會出現(xiàn)一段時間的白屏,解決辦法:

解決方案很簡單,Android原生的白屏問題可以通過為 Launcher Activity 設(shè)置 windowBackground 解決,而 Flutter 也是基于此辦法,同時優(yōu)化了 Flutter 初始化階段的白屏問題(覆蓋一個launchView)坞靶,只用兩步設(shè)置便能解決 Flutter 中白屏問題。

在項目的 android/app/src/main/res/mipmap-xhdpi/ 目錄下添加閃屏圖片直晨;

打開 android/app/src/main/res/drawable/launch_background.xml 文件汗销,這個文件就是閃屏的背景文件衙傀,具體如何設(shè)置可以查閱 Android Drawable跟束,我在 demo 中的設(shè)置如下:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:drawable="@android:color/background_dark" />

  <!-- You can insert your own image assets here -->
  <item
    android:bottom="84dp">
    <bitmap
      android:src="@mipmap/launch_image" />
  </item>
</layer-list>

如此一來,我們就完成了,文章開始提出的需求了.

Demo地址 : https://github.com/hanlin19900610/flutter_bottom_navigation_bar

剛開始接觸Flutter,代碼寫的有些混亂,可能有些問題考慮不是很深入,有不足之處,還請各位大佬指出

推薦閱讀

1. Flutter中文網(wǎng) https://flutterchina.club/
2. 阿韋大神的Github https://github.com/AweiLoveAndroid/Flutter-learning
3. Flutter學(xué)習(xí)筆記 - 底部導(dǎo)航欄 https://blog.csdn.net/u011045726/article/details/79583423
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末莺奸,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子冀宴,更是在濱河造成了極大的恐慌灭贷,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件略贮,死亡現(xiàn)場離奇詭異甚疟,居然都是意外死亡,警方通過查閱死者的電腦和手機逃延,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門古拴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人真友,你說我怎么就攤上這事〗襞粒” “怎么了盔然?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長是嗜。 經(jīng)常有香客問我愈案,道長,這世上最難降的妖魔是什么鹅搪? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任站绪,我火速辦了婚禮,結(jié)果婚禮上丽柿,老公的妹妹穿的比我還像新娘恢准。我一直安慰自己,他們只是感情好甫题,可當我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布馁筐。 她就那樣靜靜地躺著,像睡著了一般坠非。 火紅的嫁衣襯著肌膚如雪敏沉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天,我揣著相機與錄音盟迟,去河邊找鬼秋泳。 笑死,一個胖子當著我的面吹牛攒菠,可吹牛的內(nèi)容都是我干的迫皱。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼要尔,長吁一口氣:“原來是場噩夢啊……” “哼舍杜!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起赵辕,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤既绩,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后还惠,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體饲握,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年蚕键,在試婚紗的時候發(fā)現(xiàn)自己被綠了救欧。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡锣光,死狀恐怖笆怠,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情誊爹,我是刑警寧澤蹬刷,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站频丘,受9級特大地震影響办成,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜搂漠,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一迂卢、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧桐汤,春花似錦而克、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至馆截,卻和暖如春充活,著一層夾襖步出監(jiān)牢的瞬間蜂莉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工混卵, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留映穗,地道東北人。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓幕随,卻偏偏與公主長得像蚁滋,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子赘淮,可洞房花燭夜當晚...
    茶點故事閱讀 44,614評論 2 353

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