ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【Flutter】顶部导航栏实现 ( Scaffold | DefaultTabController | TabBar | Tab | TabBarView )

2021-03-31 12:29:30  阅读:256  来源: 互联网

标签:TabBarView const Tab Scaffold TabBar 组件 导航 icon


文章目录





一、Scaffold 组件



Flutter 中的 Scaffold 组件实现了基础的材料设计 ( Material Design ) 可视化布局结构 ;

Scaffold 提供了显示左侧侧拉导航栏 , 底部导航 , 浮动按钮等 API ;

Scaffold 构造函数如下 :

class Scaffold extends StatefulWidget {
  /// Creates a visual scaffold for material design widgets.
  const Scaffold({
    Key? key,
    this.appBar,	// 顶部的标题栏
    this.body,		// 中间显示的核心部分 , 标题栏下面的部分都是  
    this.floatingActionButton,			// 右下角的悬浮按钮 ( 可改变位置 )
    this.floatingActionButtonLocation,
    this.floatingActionButtonAnimator,
    this.persistentFooterButtons,
    this.drawer,	// 侧拉导航栏 
    this.onDrawerChanged,
    this.endDrawer,
    this.onEndDrawerChanged,
    this.bottomNavigationBar,
    this.bottomSheet,
    this.backgroundColor,
    this.resizeToAvoidBottomInset,
    this.primary = true,
    this.drawerDragStartBehavior = DragStartBehavior.start,
    this.extendBody = false,
    this.extendBodyBehindAppBar = false,
    this.drawerScrimColor,
    this.drawerEdgeDragWidth,
    this.drawerEnableOpenDragGesture = true,
    this.endDrawerEnableOpenDragGesture = true,
    this.restorationId,
  }) : assert(primary != null),
       assert(extendBody != null),
       assert(extendBodyBehindAppBar != null),
       assert(drawerDragStartBehavior != null),
       super(key: key);




二、实现顶部导航栏



实现顶部导航栏需要三个组件 :

  • TabBar : 该组件就是导航栏组件 , 设置多个图标按钮 ;
  • TabBarView : 该组件是被导航的组件 , 设置多个布局结构 , 同时只能显示一个 ;
  • DefaultTabController : 该组件用于关联控制 TabBar 和 TabBarView 组件 ;

界面组件中 , 根组件肯定是 MaterialApp , 然后下一层组件就是 DefaultTabController , 使用 DefaultTabController 包裹 Scaffold , 然后在 Scaffold 中定义的 TabBarTabBarView 就会被关联再一起 ;


注意三个相等的值 :

DefaultTabController length 长度

等于

TabBar 子组件个数

等于

TabBarView 子组件个数


Google 官方给出的文档 :

[TabBar], which displays a row of tabs. ( 显示一行标签 )
[TabBarView], which displays a widget for the currently selected tab. ( 显示当前选中的标签对应的组件 )
[TabController], which coordinates tab selection between a [TabBar] and a [TabBarView]. ( 用于关联标签与选项卡 )
https://material.io/design/components/tabs.html





三、DefaultTabController 导航标签控制组件



DefaultTabController 用于关联 TabBar 和 TabBarView 组件 ;

由于 TabBar 中的组件都是无状态组件 , 或者不同的父类组件 , 导致创建 TabController 不方便时 , 就会使用该 DefaultTabController 组件 ;

DefaultTabController 组件的 length 参数必须不为空 , 并且大于 1 , length 的个数必须等于 TabBar 和 TabBarView 的个数 ;

initialIndex 初始索引值参数必须不能为空


DefaultTabController 构造函数原型 :

  /// 为给定的子组件创建一个默认的导航控制器
  ///
  /// length 参数必须不为空 , 并且大于 1 ;
  /// length 的个数必须等于 TabBar 和 TabBarView 的个数 ;
  /// 
  /// initialIndex 初始索引值参数必须不能为空 
  const DefaultTabController({
    Key? key,
    required this.length,
    this.initialIndex = 0,
    required this.child,
  }) : assert(initialIndex != null),
       assert(length >= 0),
       assert(length == 0 || (initialIndex >= 0 && initialIndex < length)),
       super(key: key);

Google 官方给出的代码示例 :

class MyDemo extends StatelessWidget {
  final List<Tab> myTabs = <Tab>[
    Tab(text: 'LEFT'),
    Tab(text: 'RIGHT'),
  ];
  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: myTabs.length,
      child: Scaffold(
        appBar: AppBar(
          bottom: TabBar(
            tabs: myTabs,
          ),
        ),
        body: TabBarView(
          children: myTabs.map((Tab tab) {
            final String label = tab.text.toLowerCase();
            return Center(
              child: Text(
                'This is the $label tab',
                style: const TextStyle(fontSize: 36),
              ),
            );
          }).toList(),
        ),
      ),
    );
  }
}




四、TabBar 导航按钮组件



TabBar 组件主要用于封装导航栏的图标按钮 , 主要设置一组 Tab 组件 ;

通常放在 AppBar 组件的底部 , 也就是赋值给 AppBar.bottom , 与 TabBarView 结合起来使用 ;

TabBar 中 Tab 子组件的个数 , TabController 中的 length 长度 , TabBarView 中子组件的个数 , 三者必须相等 ;


TabBar 构造函数 :

  const TabBar({
    Key? key,
    required this.tabs,
    this.controller,
    this.isScrollable = false,
    this.indicatorColor,
    this.automaticIndicatorColorAdjustment = true,
    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.overlayColor,
    this.mouseCursor,
    this.enableFeedback,
    this.onTap,
    this.physics,
  }) : assert(tabs != null),
       assert(isScrollable != null),
       assert(dragStartBehavior != null),
       assert(indicator != null || (indicatorWeight != null && indicatorWeight > 0.0)),
       assert(indicator != null || (indicatorPadding != null)),
       super(key: key);

官方提供的 TabBar 代码示例 :

late TabController _tabController;
 @override
 void initState() {
   super.initState();
   _tabController = TabController(length: 3, vsync: this);
 }
 Widget build(BuildContext context) {
   return Scaffold(
     appBar: AppBar(
       title: Text('TabBar Widget'),
       bottom: TabBar(
         controller: _tabController,
         tabs: <Widget>[
           Tab(
             icon: Icon(Icons.cloud_outlined),
           ),
           Tab(
            icon: Icon(Icons.beach_access_sharp),
           ),
           Tab(
             icon: Icon(Icons.brightness_5_sharp),
           ),
         ],
       ),
     ),
     body: TabBarView(
       controller: _tabController,
       children: <Widget>[
         Center(
           child: Text('It\'s cloudy here'),
         ),
         Center(
           child: Text('It\'s rainy here'),
         ),
         Center(
            child: Text('It\'s sunny here'),
         ),
       ],
     ),
   );
 }




五、Tab 标签组件



Tab 组件是 TabBar 组件的子组件 , 每个 TabBar 组件需要设置若干个 Tab 组件 ( 至少一个 ) ;


Tab 构造函数 :

  /// 创建一个材料设计风格的选项卡.
  ///
  /// 至少设置一个 text 文本和 icon 图标 child 必须为非空 .
  const Tab({
    Key? key,
    this.text,
    this.icon,
    this.iconMargin = const EdgeInsets.only(bottom: 10.0),
    this.child,
  }) : assert(text != null || child != null || icon != null),
       assert(text == null || child == null),
       super(key: key);

代码示例 :

bottom: TabBar(
  /// 可左右滑动
  isScrollable: true,
  /// 设置顶部导航栏的图标
  tabs: datas.map((TabData data) {
    /// 导航栏的图标及文本
    return Tab(
      text: data.title,
      icon: Icon(data.icon),
    );
  }).toList(),
),




六、TabBarView 导航主体内容组件



显示 TabBar 中当前选中的 Tab 标签对应的组件 ;

TabBarView 初始化时 , 可以只为其设置 children 参数 , 类型是 List<Widget> ;

TabBarView 构造函数 :

  const TabBarView({
    Key? key,
    required this.children,
    this.controller,
    this.physics,
    this.dragStartBehavior = DragStartBehavior.start,
  }) : assert(children != null),
       assert(dragStartBehavior != null),
       super(key: key);




七、完整代码示例



import 'package:flutter/material.dart';

void main() {
  runApp(
      TabBarWidget()
  );
}

/// 导航栏数据集合
const List<TabData> datas = const <TabData>[
  const TabData(title: '3D', icon: Icons.threed_rotation),
  const TabData(title: '打印机', icon: Icons.print),
  const TabData(title: '动画', icon: Icons.animation),
  const TabData(title: '变换', icon: Icons.transform),
  const TabData(title: '高度', icon: Icons.height),
  const TabData(title: '描述', icon: Icons.description),
  const TabData(title: '向前', icon: Icons.forward),
  const TabData(title: '相机', icon: Icons.camera),
  const TabData(title: '设置', icon: Icons.settings),
  const TabData(title: '学位', icon: Icons.school),
];

/// 顶部导航栏核心页面
class TabBarWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {

    /// 材料设计应用组件 , 一般作为页面的根组件
    return MaterialApp(

      /// 用于将 TabBar 和 TabBarView 封装起来
      home: DefaultTabController(
        length: datas.length,

        /// 主界面框架
        child: Scaffold(

          /// 标题栏
          appBar: AppBar(

            /// 标题栏标题
            title: const Text('顶部导航栏'),

            /// 设置顶部导航栏
            bottom: TabBar(
              /// 可左右滑动
              isScrollable: true,

              /// 设置顶部导航栏的图标
              tabs: datas.map((TabData data) {

                /// 导航栏的图标及文本
                return Tab(
                  text: data.title,
                  icon: Icon(data.icon),
                );

              }).toList(),
            ),
          ),

          /// 导航栏控制的左右轮播的组件
          body: TabBarView(

            /// 界面显示的主体 , 通过 TabBar 切换不同的本组件显示
            children: datas.map((TabData choice) {
              return Padding(
                padding: const EdgeInsets.all(10.0),
                child: TabContent(data: choice),
              );
            }).toList(),
          ),
        ),
      ),
    );
  }
}

/// 通过 TabBar 导航栏切换展示的主要内容
/// 用于在 TabBarView 中显示的组件
class TabContent extends StatelessWidget {
  const TabContent({Key key, this.data}) : super(key: key);

  /// 根据该数据条目生成组件
  final TabData data;

  @override
  Widget build(BuildContext context) {
    TextStyle textStyle = TextStyle(color: Colors.yellow, fontSize: 50);
    return Card(

      /// 设置 20 像素边距
      margin: EdgeInsets.all(20),

      /// 设置阴影
      elevation: 10,

      /// 卡片颜色黑色
      color: Colors.black,

      /// 卡片中的元素居中显示
      child: Center(

        /// 垂直方向的线性布局
        child: Column(

          /// 在主轴 ( 垂直方向 ) 占据的大小
          mainAxisSize: MainAxisSize.min,

          /// 居中显示
          crossAxisAlignment: CrossAxisAlignment.center,

          children: <Widget>[

            /// 设置图标
            Icon(data.icon, size: 128.0, color: Colors.green),

            /// 设置文字
            Text(data.title, style: TextStyle(color: Colors.yellow, fontSize: 50)),

          ],
        ),
      ),
    );
  }
}

/// 封装导航栏的图标与文本数据
class TabData {
  /// 导航数据构造函数
  const TabData({this.title, this.icon});

  /// 导航标题
  final String title;

  // 导航图标
  final IconData icon;
}

运行效果 :

在这里插入图片描述





八、相关资源



参考资料 :


重要的专题 :


博客源码下载 :

标签:TabBarView,const,Tab,Scaffold,TabBar,组件,导航,icon
来源: https://blog.csdn.net/han1202012/article/details/115341908

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有