Flutter 創(chuàng)建底部導(dǎo)航的三種方式

Flutter創(chuàng)建底部導(dǎo)航的方式:推薦第三種

一、BottomNavigationBar + BottomNavigationBarItem

  • 優(yōu)缺點(diǎn):
    • 實(shí)現(xiàn)簡(jiǎn)單,代碼量很少基本就能完成
    • 不能調(diào)整item的文字和圖片間距
    • 每次切換頁(yè)面會(huì)重繪,不會(huì)保存之前的頁(yè)面狀態(tài)
具體實(shí)現(xiàn):
///根頁(yè)面
class MainPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return MainPageState();
  }
}

class MainPageState extends State <MainPage> {
  int currentIndex = 0;
  final items = [
    BottomNavigationBarItem(icon: Image(image: AssetImage('images/Home.png')), title: Text
      ('首頁(yè)'),activeIcon: Image(image:
    AssetImage
      ('images/HomeSelect'
        '.png'))),
    BottomNavigationBarItem(icon: Image(image: AssetImage('images/market_normal.png')),
        title:
    Text("行情"),activeIcon: Image(image: AssetImage('images/market_selected.png'))),
    BottomNavigationBarItem(icon: Image(image: AssetImage('images/transcation_normal.png')),
        title: Text
      ("交易"),activeIcon: Image
          (image:
        AssetImage('images/transcation_selected.png'),)),
    BottomNavigationBarItem(icon: Image(image: AssetImage('images/assets_normal.png')),
        title: Text
      ("資產(chǎn)"),activeIcon: Image(image:
        AssetImage('images/assets_selected.png'),)),
  ];
///4個(gè)tabbar頁(yè)面
  final bodyLists = [
    HomepageWidget(),
    MarketpageWidget(),
    TranscationpageWidget(),
    AssetspageWidget()
  ];
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold (
      appBar: AppBar(title: Text("切換"),),
      bottomNavigationBar: BottomNavigationBar(
        items: items,
        currentIndex: currentIndex,
        onTap: onTap,
        unselectedItemColor: prefix1.Color(0xFF989D9D),
        selectedItemColor: prefix1.Color(0xFF333333),
        type: BottomNavigationBarType.fixed,
      ),
      body: bodyLists[currentIndex],
    );
  }
  void onTap(int index) {
    setState(() {
      currentIndex = index;
    });
  }
}

每個(gè)子頁(yè)面代碼都是一樣的,主要是為了測(cè)試每個(gè)頁(yè)面的狀態(tài)

import 'package:flutter/material.dart';

class HomepageWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return HomepageWidgetState();
  }
}

class HomepageWidgetState extends State <HomepageWidget> {
  int count = 0;
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      body: Center(
        child: Text("首頁(yè) $count",style: TextStyle(color: Colors.blue),),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: addButtonClick,
        child: Icon(Icons.add),
      ),
    );
  }
  void addButtonClick() {
    setState(() {
      count ++;
    });
  }
}
Oct-23-2019 13-59-00.gif

如上圖,我們可以看到當(dāng)切換界面的時(shí)候,之前的狀態(tài)是被重置了的。那么下面介紹該如何保持狀態(tài)。

二、BottomNavigationBar +Stack + OffStage

  • 優(yōu)缺點(diǎn)
    • 能夠保存頁(yè)面的狀態(tài)
    • 程序初始化的時(shí)候所有的child都會(huì)執(zhí)行initState(有時(shí)候我們想要的效果是當(dāng)點(diǎn)擊tabbar的時(shí)候界面再去加載)
    • 使用BottomNavigationBarItem無(wú)法調(diào)整文字圖片間距
body: Stack(
        children: [
          _stackOffstage(0),
          _stackOffstage(1),
          _stackOffstage(2),
          _stackOffstage(3)
        ],
      ),

 //根據(jù)點(diǎn)擊的索引返回widget
  Widget _stackOffstage(int index) {
    return Offstage(
      //If false, the child is included in the tree as normal.
      offstage: currentIndex != index,
      child: TickerMode(
        child: bodyLists[index],
        //If true, then tickers in this subtree will tick.
        enabled: currentIndex == index,
      ),
    );
  }
Oct-23-2019 15-37-09.gif

三、使用PageView + AutomaticKeepAliveClientMixin

  • 優(yōu)點(diǎn)
    • 可以保存頁(yè)面狀態(tài)
    • 每次點(diǎn)擊才會(huì)初始化,而且只會(huì)初始化一次
    • push pop回來(lái)widgetState也不會(huì)重新initState
var pageController = PageController();

Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold (
      appBar: AppBar(title: Text("切換"),),
      bottomNavigationBar: BottomNavigationBar(
        items: items,
        currentIndex: currentIndex,
        onTap: onTap,
        unselectedItemColor: prefix1.Color(0xFF989D9D),
        selectedItemColor: prefix1.Color(0xFF333333),
        type: BottomNavigationBarType.fixed,
      ),
      body: PageView(
        controller: pageController,
        children: bodyLists,
        onPageChanged:pageControllerTap ,
        physics: NeverScrollableScrollPhysics(),
      ),
    );
  }

  void pageControllerTap(int index) {
    setState(() {
      currentIndex = index;
    });
  }
  void onTap(int index) {
    pageController.jumpToPage(index);
  }

其中子頁(yè)面的代碼,需要注意 AutomaticKeepAliveClientMixin, 重寫方法
wantKeepAlive ,這樣是讓頁(yè)面一直保存在內(nèi)存中。還有一個(gè)要注意的點(diǎn):super.build(context);,如果不寫,當(dāng)我們使用Navigator.push切換界面的時(shí)候,再pop回來(lái),HomepageWidgetState還是會(huì)執(zhí)行initState,加上super后就不會(huì)再有這個(gè)問題。

class HomepageWidgetState extends State <HomepageWidget> with AutomaticKeepAliveClientMixin {
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    print('HomepageWidgetState initState');
  }
  int count = 0;
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    super.build(context); //注意:每個(gè)子頁(yè)面要寫`super`
    return Scaffold(
      body: Center(
        child: Text("首頁(yè) $count",style: TextStyle(color: Colors.blue),),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: addButtonClick,
        child: Icon(Icons.add),
      ),
    );
  }
  void addButtonClick() {
    setState(() {
      count ++;
    });
  }
//一直保存在內(nèi)存中
  @override
  // TODO: implement wantKeepAlive
  bool get wantKeepAlive => true;
}

其中PageController是可以控制pageView中要顯示的界面
physics //How the page view should respond to user input. 用戶如何響應(yīng),具體行為可以查看源碼,我們這里可以禁止滑動(dòng)NeverScrollableScrollPhysics

 [ScrollPhysics], which can be used instead of this class when the default
///    behavior is desired instead.
///  * [BouncingScrollPhysics], which provides the bouncing overscroll behavior
///    found on iOS.
///  * [ClampingScrollPhysics], which provides the clamping overscroll behavior
///    found on Android.
pageView .gif
?著作權(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)容