热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Flutter第六章(BottomNavigationBar,AppBar,TabBar,TabController以及案例)

版权声明:本文为作者原创书籍。转载请注明作者和出处,未经授权,严禁私自转载,侵权必究!!!情感语录:如果你想得到从未拥有过的东西,那么你必须去做从未做过的事
版权声明:本文为作者原创书籍。转载请注明作者和出处,未经授权,严禁私自转载,侵权必究!!!

情感语录:如果你想得到从未拥有过的东西,那么你必须去做从未做过的事情。

欢迎来到本章节,上一章节我们讲了路由 还记得吗?知识点回顾 戳这里 Flutter基础第五章

本章主要围绕底部导航条顶部导航条 以及自定义AppBar 和优化方案TabController进行讲解,现在无论什么应用底部导航菜单和顶部导航菜单似乎都成了标配 ;有关这样的应用可以说是多不胜数”QQ、微信、头条、京东、饿了么等等…..”

本章简要:

1、BottomNavigationBar 底部导航条

2、 AppBar 自定义顶部样式

3、 TabBar 的样式配置

4、 TabController 的使用

一、BottomNavigationBar

BottomNavigationBar 是底部导航条,可以让我们定义底部 Tab 切换,BottomNavigationBar是 Scaffold组件的参数。抛开IOS不说,因为我是做Android开发的,在Android原生中你没有封装有自己的底部导航栏菜单模块,你可能最常用的就是 Activity + RadioButton + Fragment的方式去实现了,这对于刚入Android的新手来说,可能并没那么好切入,因为我在技术群里看到好多初学者都在问这样的问题。而在Flutter中这将变得轻松自如。

构造函数如下:

   BottomNavigationBar({
    Key key,
    @required this.items,
    this.onTap,
    this.currentIndex = 0,
    this.elevation = 8.0,
    BottomNavigationBarType type,
    Color fixedColor,
    this.backgroundColor,
    this.icOnSize= 24.0,
    Color selectedItemColor,
    this.unselectedItemColor,
    this.selectedIcOnTheme= const IconThemeData(),
    this.unselectedIcOnTheme= const IconThemeData(),
    this.selectedFOntSize= 14.0,
    this.unselectedFOntSize= 12.0,
    this.selectedLabelStyle,
    this.unselectedLabelStyle,
    this.showSelectedLabels = true,
    bool showUnselectedLabels,
  })
BottomNavigationBar 常用属性
    items List        底部导航条按钮集合
    
    iconSize                                   设置icon大小
    
    currentIndex                               默认选中第几个
    
    onTap                                      选中变化回调函数
    
    fixedColor                                 选中的颜色
    
    type                                       BottomNavigationBarType.fixed (固定类型)
    
                                               BottomNavigationBarType.shifting (流动类型)

                                               
    selectedLabelStyle                         选中时文本的样式

    unselectedLabelStyle                       未选中时文本的样式
                                               
    selectedFontSize                           选中时文本的大小            
                                               
    unselectedFontSize                         未选中时文本的大小    

    selectedItemColor                          选择中的颜色和 fixedColor互斥
    
    unselectedItemColor                        未选择中的颜色
    
    showUnselectedLabels                       是否显示未选中的文本标签

BottomNavigationBar的属性都大致了解了,下面我们来结合案例去实践,感受它妖娆的魅力吧O(∩_∩)O

本案例不会再按照以前的写法,把代码都写在main.dart 程序入口中,方便后面的文章写案例和查阅源码学习,在本章开始进行代码抽离。

案例要求: 利用上面的 BottomNavigationBar 组件实现类似微信手机端的底部菜单导航,点击底部导航菜单可以进行页面之间的切换。

首先我们先准备三个页面,主要用于点击底部导航菜单按钮,显示不同的页面效果,内容随便写点,有区分即可:

1、HomePage(主页)
  import 'package:flutter/material.dart';
  
  class HomePage extends StatefulWidget {
    HomePage({Key key}) : super(key: key);
  
    _HomePageState createState() => _HomePageState();
  }
  
  class _HomePageState extends State {
    @override
    Widget build(BuildContext context) {
      return Container(
        color: Colors.cyan,
        child: Center(child: Text("主页"),),
      );
    }
  }
2、CommunityPage(社区)
  import 'package:flutter/material.dart';
  
  class CommunityPage extends StatefulWidget {
    CommunityPage({Key key}) : super(key: key);
  
    _CommunityPageState createState() => _CommunityPageState();
  }
  
  class _CommunityPageState extends State {
    @override
    Widget build(BuildContext context) {
      return Container(
        color: Colors.green,
        child: Center(child: Text("社区"),),
      );
    }
  }
3、PersionPage(个人中心)
  import 'package:flutter/material.dart';
  
  class PersionPage extends StatefulWidget {
  
    PersionPage({Key key}) : super(key: key);
  
    _PersionPageState createState() => _PersionPageState();
  }
  
  class _PersionPageState extends State {
    @override
    Widget build(BuildContext context) {
        return Container(
        color: Colors.blue,
        child: Center(child: Text("个人中心"),),
      );
    }
  }
4、重点来了,新建Tabs.dart文件(名字随意,见名知意即可),按钮的点击有状态的改变,且要反应到视图模板上,这里我们应该使用 StatefulWidget,让Tabs类继承StatefulWidget:
  import 'package:flutter/material.dart';

  //引入准备好的界面
  import 'tabs/CommunityPage.dart';
  import 'tabs/PersionPage.dart';
  import 'tabs/HomePage.dart';

  
  
  class Tabs extends StatefulWidget {

    _TabsState createState() => _TabsState();

  }

  class _TabsState extends State {

    //默认选中的索引
    int _currentIndex=0;

    //将页面封装在集合中,方便通过索引取出
    List _pageList=[
      HomePage(),
      CommunityPage(),
      PersionPage(),
    ];


    @override
    Widget build(BuildContext context) {
      return Scaffold(
          appBar: AppBar(
            title: Text("呆萌"),
          ),
          body: this._pageList[this._currentIndex],

          bottomNavigationBar: BottomNavigationBar(

            //配置选中的索引值
            currentIndex: this._currentIndex,

            onTap: (int index){

              //改变状态
                setState(() {
                    this._currentIndex=index;
                });
            },

            //icon的大小
            iconSize:36.0,

            //选中的颜色
            fixedColor:Colors.red,

            selectedFontSize: 18,

            selectedLabelStyle: TextStyle(color: Colors.red),

            // selectedItemColor: Colors.red, 和 fixedColor互斥

            unselectedFontSize: 18,

            unselectedItemColor:Colors.deepPurple ,

            unselectedLabelStyle: TextStyle(color: Colors.deepPurple),

            showUnselectedLabels: true,

            //配置底部tabs为固定效果,即没有点击后的凸出感
            type:BottomNavigationBarType.fixed,

            // BottomNavigationBarItem 包装的底部按钮
            items: [

              BottomNavigationBarItem(

                icon: Icon(Icons.home),
                title: Text("首页")

              ),
               BottomNavigationBarItem(
                icon: Icon(Icons.question_answer),
                title: Text("社区")
              ),

               BottomNavigationBarItem(
                icon: Icon(Icons.people),
                title: Text("个人中心")
              )
            ],
          ),
        );
    }
  }

Tabs类中并没什么难点,部分也给出了介绍,值得注意的是 这里在点击事件 onTap中我们接收了一个点击后的索引值 并通过调用 setState()方法去改变了当前的索引值和界面的重新 build渲染视图,然后根据变化后的索引值重新在 _pageList 页面集合中取出对应的页面并赋值给 body,然而这就实现了页面切换效果的过程,第四章知识点还记得吗?戳这里回顾 StatefulWidget

5、接着在入口程序中将底部菜单进行引入
  import 'package:flutter/material.dart';
  import 'package:flutter_learn/page/Tabs.dart';


  void main() => runApp(MyApp());

  class MyApp extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
      return MaterialApp(
          home:Tabs(), // 返回 Tabs包装的菜单Widget
      );
    }
  }

运行效果见下图,还是挺简单的吧O(∩_∩)O

Flutter第六章(BottomNavigationBar ,AppBar,TabBar ,TabController 以及案例)
底部导航.gif

二、AppBar

AppBar中的属性较多,构造函数如下:

   AppBar({
    Key key,
    this.leading,
    this.automaticallyImplyLeading = true,
    this.title,
    this.actions,
    this.flexibleSpace,
    this.bottom,
    this.elevation,
    this.shape,
    this.backgroundColor,
    this.brightness,
    this.iconTheme,
    this.actionsIconTheme,
    this.textTheme,
    this.primary = true,
    this.centerTitle,
    this.titleSpacing = NavigationToolbar.kMiddleSpacing,
    this.toolbarOpacity = 1.0,
    this.bottomOpacity = 1.0,
  })
AppBar 常用属性:
    属性                         描述

    leading                      在标题前面显示的一个控件,在首页通常显示应用
                                 的 logo;在其他界面通常显示为返回按钮
                                 
    title                        标题,通常显示为当前界面的标题文字,可以放组件

    actions                      通常使用 IconButton 来表示,可以放按钮组

    bottom                       通常放 tabBar,标题下面显示一个 Tab 导航栏

    backgroundColor              导航背景颜色

    iconTheme                    图标样式

    textTheme                    文字样式

    centerTitle                  标题是否居中显示

AppBar在之前的案例中一直都有使用只是没有过多使用它的属性而已,现在介绍了,写个简单的页面来练习下。这里先不在上个案例中进行配置,新建一个 AppBarPage界面。

import 'package:flutter/material.dart';

class AppBarPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        //标题
        title: Text("呆萌"),
        //设置Bar背景色
        backgroundColor: Colors.red,
        //标题居中
        centerTitle: true,

        leading: Builder(
          builder: (BuildContext context) {
            return IconButton(

              icon: Icon(Icons.menu),

              onPressed: () {

                Scaffold.of(context)
                    .showSnackBar(SnackBar(content: new Text('点击了左侧按钮')));
              },
            );
          },
        ),
        actions: [
          IconButton(

            icon: Icon(Icons.search ,color: Colors.white,),
          ),
          IconButton(

            icon: Icon(Icons.settings,color: Colors.white,),
          )
        ],
      ),
      body: Center(
        child: Text(
          '这是AppBar测试界面',
          style: TextStyle(
            color: Colors.green,
            fontSize: 22,
          ),
        ),
      ),
    );
  }
}

首先是在AppBar左边leading 添加了一个 IconButton 并显示了一个菜单Icon,在点击的时候 弹出个SnackBar提示信息,SnackBar这里不具体讲,这个会在后面章节中详细介绍,需要注意的是当BuildContext在Scaffold之前时,调用Scaffold.of(context)会报错。这时可以通过Builder Widget来解决这个问题。其次通过actions添加了一组图片按钮,而actions接收的是一个List 集合,所以这里你可以放多个组件。

接下来配置路由,使得跳转可以到我们刚新建的AppBarPage页面中去。路由还记得吗?戳这里回顾 路由

 //配置路由
  final routes={
     //如有多个,请在这里添加即可。
    '/SecondPage':(context,{arguments})=>SecondPage(arguments:arguments),
    //让AppBarPage 做为launcher界面
    '/':(context)=>AppBarPage(),
  };

为了方便观看 AppBar 中添加的组件,这里使用 debugShowCheckedModeBanner:false把 debug 图标进行去掉。并在入口类中初始路由的时候去加载我们的 AppBarPage 页面

  import 'package:flutter/material.dart';
  import 'route/Routes.dart';


  void main() => runApp(MyApp());

  class MyApp extends StatelessWidget {

    @override
    Widget build(BuildContext context) {
      return MaterialApp(

          //去掉debug图标
          debugShowCheckedModeBanner:false ,

          //初始化的时候加载的路由
          initialRoute: '/',
          onGenerateRoute: onGenerateRoute

      );
    }
  }

运行看看效果吧:

Flutter第六章(BottomNavigationBar ,AppBar,TabBar ,TabController 以及案例)
AppBar(eg1).gif

效果还是不错吧,debug 图标也被我们成功的去掉了,这只是模拟器,在真设备上显示效果应该会更好,有没有觉得比原生实现起来简单很多呢?

三、TabBar

在Flutter中可以通过 TabBar 组件可以轻松实现顶部导航条,如不使用 TabBar 组件也是可以,比如通过Row组件去嵌套也是可以的,只是实现起来相对复杂很多。

构造函数如下:

  const TabBar({
    Key key,
    @required this.tabs,
    this.controller,
    this.isScrollable = false,
    this.indicatorColor,
    this.indicatorWeight = 2.0,
    this.indicatorPadding = EdgeInsets.zero,
    this.indicator,
    this.indicatorSize,
    this.labelColor,
    this.labelStyle,
    this.labelPadding,
    this.unselectedLabelColor,
    this.unselectedLabelStyle,
    this.dragStartBehavior = DragStartBehavior.start,
    this.onTap,
  })
TabBar 常用属性:
    属性                      描述

    tabs                      显示的标签内容,一般使用 Tab 对象,也可以是其他的Widget

    controller                TabController 对象

    isScrollable              是否可滚动

    indicatorColor            指示器颜色

    indicatorWeight           指示器高度

    indicatorPadding          底部指示器的 Padding

    indicator                 指示器 decoration,例如边框等

    indicatorSize             指示器大小计算方式,TabBarIndicatorSize.label 跟文字等宽,
                              TabBarIndicatorSize.tab 跟每个 tab 等宽
                              
    labelColor                选中 label 颜色

    labelStyle                选中 label 的 Style

    labelPadding              每个 label 的 padding 值

    unselectedLabelColor      未选中 label 颜色

    unselectedLabelStyle      未选中 label 的 Style

在上面介绍AppBar中有一个bottom属性刚好接收的就是 Widget 组件,TabBar也是一个组件,瞌睡遇到枕头啊!! 下面我们就来创建一个TabBar 组件将其插入。

  import 'package:flutter/material.dart';
  
  class AppBarPage extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
      return DefaultTabController(
        //这个一定的和tabs的子元素大小一致
        length: 3,
        
        child: Scaffold(
          appBar: AppBar(
            //标题
            title: Text("呆萌"),
            //设置Bar背景色
            backgroundColor: Colors.red,
            //标题居中
            centerTitle: true,
  
            bottom: TabBar(
  
              //配置指示器颜色
              indicatorColor: Colors.green,
              //让指示器和文字等宽
              indicatorSize: TabBarIndicatorSize.label,
              // 导航Tab
              tabs: [
                Tab(text: "视频"),
                Tab(text: "段子"), 
                Tab(text: "趣图")],
            ),
  
            leading: Builder(
              builder: (BuildContext context) {
                return IconButton(
                  icon: Icon(Icons.menu),
                  onPressed: () {
                    Scaffold.of(context)
                        .showSnackBar(SnackBar(content: new Text('点击了左侧按钮')));
                  },
                );
              },
            ),
            actions: [
              IconButton(
                icon: Icon(
                  Icons.search,
                  color: Colors.white,
                ),
              ),
              IconButton(
                icon: Icon(
                  Icons.settings,
                  color: Colors.white,
                ),
              )
            ],
          ),
          body: Container(child: Center(child: Text("测试TabBar"),),),
        ),
      );
    }
  }

这段代码中有个非常重要的配置 DefaultTabController 其中 length的大小一定等于 TabBar 中 tabs的子元素数量,否则报错。而 tabs 接收的是一个List 集合,在实际开发中,length往往需要动态配置。

Flutter第六章(BottomNavigationBar ,AppBar,TabBar ,TabController 以及案例)
TabBar(eg1).gif

可以看到我们实现了顶部菜单导航条,你可能马上会问,顶部导航是实现了,但我想点击顶部的菜单按钮后让下面空白区域跟随着进行页面联动,那该怎样实现呢? 想想下,Flutter中一个页面也是Widget,那我能不能给每个导航按钮绑定一个页面呢? 点击每个按钮就显示绑定的页面Widget即可!!

嘿嘿,确实是可以的,Flutter中也是这么做的并提供了 TabBarView 组件让我们去实现。

TabBarView构造函数:

  const TabBarView({
    Key key,
    @required this.children,
    this.controller,
    this.physics,
    this.dragStartBehavior = DragStartBehavior.start,
  }) 

TabBarView中 children 属性接收的也是一个List 那便不难看出:TabBar中的 tabs 的子元素和 TabBarView 中的子元素通过下标进行了一 一绑定。也就是说导航菜单有多少个按钮,TabBarView中就要准备多少个页面组件。基于这个原理我们把上面案例中的 body 替换成如下

   body: TabBarView(

      children: [
        Container(
          child: Center(
            child: Text("视频专区"),
          ),
        ),
        Container(
          child: Center(
            child: Text("段子专区"),
          ),
        ),
        Container(
          child: Center(
            child: Text("趣图专区"),
          ),
        )
       
      ],
    ),

运行试看下效果:

Flutter第六章(BottomNavigationBar ,AppBar,TabBar ,TabController 以及案例)
TabBarView.gif

果不其然,确实这样就实现了联动。是不是很激动?下面我来看一种情况:我们将顶部导航菜单增加到 7 个 甚至更多看看是个什么效果,添加之后注意修改 length 的长度 :

         // 导航Tab
          tabs: [
            Tab(text: "视频"),
            Tab(text: "段子"),
            Tab(text: "趣图"),

            Tab(text: "测试"),
            Tab(text: "测试"),
            Tab(text: "测试"),

            Tab(text: "测试"),
          ],
Flutter第六章(BottomNavigationBar ,AppBar,TabBar ,TabController 以及案例)
TabBarView(eg2).gif

尼玛啊! 菜单被逐渐覆盖了,也就是说当前一屏的宽度不能够足以均分给这么多个导航菜单,导致了按钮不能完全显示出来!!那能不能让它能够自适应,如果有很多菜单,就让它能左右滑动呢? 当然可以 上面TabBar属性介绍中 isScrollable 就能让 TabBar 实现可以左右滑动。下面添加一个属性试试。

  import 'package:flutter/material.dart';
  
  class AppBarPage extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
      return MaterialApp(
        //去掉debug图标
        debugShowCheckedModeBanner:false ,
  
        home: DefaultTabController(
          //这个一定的和tabs的子元素大小一致
          length: 7,
  
          child: Scaffold(
            appBar: AppBar(
              //标题
              title: Text("呆萌"),
              //设置Bar背景色
              backgroundColor: Colors.red,
              //标题居中
              centerTitle: true,
  
              bottom:  TabBar(
  
                //设置选中菜单文字颜色
                labelColor: Colors.white,
                //未选中文字菜单的颜色
                unselectedLabelColor: Colors.deepPurple,
  
  
                isScrollable: true,
                //配置指示器颜色
                indicatorColor: Colors.green,
                //让指示器和文字等宽
                indicatorSize: TabBarIndicatorSize.label,
                // 导航Tab
                tabs: [
                  Tab(text: "视频"),
                  Tab(text: "段子"),
                  Tab(text: "趣图"),
                  Tab(text: "测试"),
                  Tab(text: "测试"),
                  Tab(text: "测试"),
                  Tab(text: "测试"),
                ],
              ),
  
  
              leading: Builder(
                builder: (BuildContext context) {
                  return IconButton(
                    icon: Icon(Icons.menu),
                    onPressed: () {
                      Scaffold.of(context)
                          .showSnackBar(SnackBar(content: new Text('点击了左侧按钮')));
                    },
                  );
                },
              ),
              actions: [
                IconButton(
                  icon: Icon(
                    Icons.search,
                    color: Colors.white,
                  ),
                ),
                IconButton(
                  icon: Icon(
                    Icons.settings,
                    color: Colors.white,
                  ),
                )
              ],
            ),
            body: TabBarView(
              children: [
                Container(
                  child: Center(
                    child: Text("视频专区"),
                  ),
                ),
                Container(
                  child: Center(
                    child: Text("段子专区"),
                  ),
                ),
                Container(
                  child: Center(
                    child: Text("趣图专区"),
                  ),
                ),
                Container(
                  child: Center(
                    child: Text("趣图专区"),
                  ),
                ),
                Container(
                  child: Center(
                    child: Text("趣图专区"),
                  ),
                ),
                Container(
                  child: Center(
                    child: Text("趣图专区"),
                  ),
                ),
                Container(
                  child: Center(
                    child: Text("趣图专区"),
                  ),
                ),
              ],
            ),
          ),
        ),
      );
    }
  }

效果如下:

Flutter第六章(BottomNavigationBar ,AppBar,TabBar ,TabController 以及案例)
TabBarView(eg3).gif

特别需要注意的是在不知道顶部菜单具体有多少个的时候(尤其是菜单是根据服务器获取的情况)或者顶部有很多个菜单需要放置时一定得加上 isScrollable 属性。

此时你可能会说,感觉这样的方式实现好复杂,有没有像底部导航菜单那样更简单高效的实现方案啊? 当然是有的,请继续往下看。

三、TabController

上面的例子中 DefaultTabController 组件实现了AppBar里面的顶部导航切换,但是在项目中有数据请求,上拉加载更多等操作的时候,或者想在统一回调函数中处理点击菜单事件的监听,那么前面的写法,就不是很方便操作,因此,在flutter里面,还提供了一个用于实现顶部导航的组件 TabController

新建一个TabBarController.dart 页面 ,并继承 StatefulWidget 的有状态组件,并且实现 SingleTickerProviderStateMixin 这个类,这里用到了Dart 中的 mixin。你可以简单的理解就是通过 with 实现了多继承。

  import 'package:flutter/material.dart';
  
  class TabBarControllerPage extends StatefulWidget {
    TabBarControllerPage({Key key}) : super(key: key);
  
    _TabBarControllerPageState createState() => _TabBarControllerPageState();
  }
  
  class _TabBarControllerPageState extends State
      with SingleTickerProviderStateMixin {
  
    TabController _tabController;
  
    @override
    void dispose() {
      super.dispose();
      //在组件树中移除时销毁_tabController
      _tabController.dispose();
    }
  
    @override
    void initState() {
      super.initState();
      
      _tabCOntroller= new TabController(vsync: this, length: 4);
  
      //监听点击事件的回调
      _tabController.addListener(() {
  
        print( getView()[_tabController.index].key.toString());
  
      });
    }
  
    List getView() {
  
      List viewWidget = new List();
  
      //配置下key 方便日子看出 是否回调了 对应的菜单
      Tab tab = Tab(key: Key("video"), text: "视频");
      Tab tab1 = Tab(key: Key("Duan Zi"), text: "段子");
      Tab tab2 = Tab(key: Key("Pic"), text: "趣图");
      Tab tab3 = Tab(key: Key("Test"), text: "测试");
  
      viewWidget.add(tab);
      viewWidget.add(tab1);
      viewWidget.add(tab2);
      viewWidget.add(tab3);
  
      return viewWidget;
    }
  
    @override
    Widget build(BuildContext context) {
      return Scaffold(
        appBar: AppBar(
          title: Text("呆萌"),
          bottom: TabBar(
  
              //根据你的场景进行配置
              // isScrollable: true,
  
              //指示器颜色
              indicatorColor: Colors.red,
  
              //设置选中菜单文字颜色
              labelColor: Colors.white,
              //未选中文字菜单的颜色
              unselectedLabelColor: Colors.yellowAccent,
  
              //使得 TabBar 和 TabBarView之间进行关联,需要同时配置该对象 _tabController
              controller: this._tabController,
              tabs: getView()),
        ),
        body: TabBarView(
  
          controller: this._tabController,
          children: [
            Container(
              child: Center(
                child: Text("视频专区"),
              ),
            ),
            Container(
              child: Center(
                child: Text("段子专区"),
              ),
            ),
            Container(
              child: Center(
                child: Text("趣图专区"),
              ),
            ),
            Container(
              child: Center(
                child: Text("测试专区"),
              ),
            ),
          ],
        ),
      );
    }
  }

特别需要注意的是 在 TabController 依然是需要指定 tabs的长度,且 TabBarTabBarView 产生关联关系都是通过 controller 属性进行配置。

重新配置初始化路由到 TabBarControllerPage 界面,下面我们来运行看下效果。

Flutter第六章(BottomNavigationBar ,AppBar,TabBar ,TabController 以及案例)
TabController方案.gif

点击切换菜单按钮后控制台输出结果:

    I/flutter ( 2731): []
    I/flutter ( 2731): []
    I/flutter ( 2731): []
    I/flutter ( 2731): []
    I/flutter ( 2731): []
    I/flutter ( 2731): []
    I/flutter ( 2731): []
    I/flutter ( 2731): []
    I/flutter ( 2731): []
    I/flutter ( 2731): []
    I/flutter ( 2731): []

在回调中确实能获取到点击菜单按钮的后的下标,并通过下标取出了对应页面的Key值信息。在案例中明显可以看出 通过 TabController 方式去实现顶部导航菜单会更加简洁且灵活,因此开发中这样的需求我们应该多使用这种方式去实现。

好了本章节就此结束,又到了说再见的时候了,如果你喜欢请留下你的小红星,你们的支持才是创作的动力,如有错误,请热心的你留言指正, 谢谢大家观看,下章再会 O(∩_∩)O

实例源码地址: https://github.com/zhengzaihong/flutter_learn


推荐阅读
  • android开发分享Flutter学习笔记(15)–App结构和导航组件
    今天上班没那么忙,突然想起来我好像没StatefulWidget(有状态组件)的demo,闲来无事,写一个简单的学习学习,前面我们有说过,Flutter不同于Android。Flu ... [详细]
  • 使用platformchannels,Flutter可以与本机平台互操作(即读取电池电量).在Android上,这需要调用Java方法.我想使用第三方JavaSDK(适用于AW ... [详细]
  • Webpack5内置处理图片资源的配置方法
    本文介绍了在Webpack5中处理图片资源的配置方法。在Webpack4中,我们需要使用file-loader和url-loader来处理图片资源,但是在Webpack5中,这两个Loader的功能已经被内置到Webpack中,我们只需要简单配置即可实现图片资源的处理。本文还介绍了一些常用的配置方法,如匹配不同类型的图片文件、设置输出路径等。通过本文的学习,读者可以快速掌握Webpack5处理图片资源的方法。 ... [详细]
  • Commit1ced2a7433ea8937a1b260ea65d708f32ca7c95eintroduceda+Clonetraitboundtom ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • Oracle分析函数first_value()和last_value()的用法及原理
    本文介绍了Oracle分析函数first_value()和last_value()的用法和原理,以及在查询销售记录日期和部门中的应用。通过示例和解释,详细说明了first_value()和last_value()的功能和不同之处。同时,对于last_value()的结果出现不一样的情况进行了解释,并提供了理解last_value()默认统计范围的方法。该文对于使用Oracle分析函数的开发人员和数据库管理员具有参考价值。 ... [详细]
  • 高质量SQL书写的30条建议
    本文提供了30条关于优化SQL的建议,包括避免使用select *,使用具体字段,以及使用limit 1等。这些建议是基于实际开发经验总结出来的,旨在帮助读者优化SQL查询。 ... [详细]
  • 在springmvc框架中,前台ajax调用方法,对图片批量下载,如何弹出提示保存位置选框?Controller方法 ... [详细]
  • 本文介绍了一个适用于PHP应用快速接入TRX和TRC20数字资产的开发包,该开发包支持使用自有Tron区块链节点的应用场景,也支持基于Tron官方公共API服务的轻量级部署场景。提供的功能包括生成地址、验证地址、查询余额、交易转账、查询最新区块和查询交易信息等。详细信息可参考tron-php的Github地址:https://github.com/Fenguoz/tron-php。 ... [详细]
  • VueCLI多页分目录打包的步骤记录
    本文介绍了使用VueCLI进行多页分目录打包的步骤,包括页面目录结构、安装依赖、获取Vue CLI需要的多页对象等内容。同时还提供了自定义不同模块页面标题的方法。 ... [详细]
  • 本文讨论了在使用PHP cURL发送POST请求时,请求体在node.js中没有定义的问题。作者尝试了多种解决方案,但仍然无法解决该问题。同时提供了当前PHP代码示例。 ... [详细]
  • 使用Flutternewintegration_test进行示例集成测试?回答首先在dev下的p ... [详细]
  • 摘录自Understandingplaceholderselectors.extendextend让你能够在多个选择器中通过继承的方式共享一段样式:.icon{transition ... [详细]
author-avatar
罗文彬2502852027
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有