首页 > 其他分享 >Flutter可滚动组件(7):TabBarView

Flutter可滚动组件(7):TabBarView

时间:2024-10-11 16:12:55浏览次数:8  
标签:TabBarView 选项卡 Text TabBar child 组件 const Flutter

TabBarView 是 Material 组件库中提供了 Tab 布局组件,通常和 TabBar 配合使用。

一、TabBarView

TabBarView 封装了 PageView,它的构造方法很简单

 TabBarView({
  Key? key,
  required this.children, // tab 页
  this.controller, // TabController
  this.physics,
  this.dragStartBehavior = DragStartBehavior.start,
}) 

TabController 用于监听和控制 TabBarView 的页面切换,通常和 TabBar 联动。如果没有指定,则会在组件树中向上查找并使用最近的一个 DefaultTabController

二、TabBar

TabBar 为 TabBarView 的导航标题,如下图所示:

图6-20


TabBar 有很多配置参数,通过这些参数我们可以定义 TabBar 的样式,很多属性都是在配置 indicator 和 label,拿上图来举例,Label 是每个Tab 的文本,indicator 指 “历史” 下面的白色下划线。

const TabBar({
  Key? key,
  required this.tabs, // 具体的 Tabs,需要我们创建
  this.controller,
  this.isScrollable = false, // 是否可以滑动
  this.padding,
  this.indicatorColor,// 指示器颜色,默认是高度为2的一条下划线
  this.automaticIndicatorColorAdjustment = true,
  this.indicatorWeight = 2.0,// 指示器高度
  this.indicatorPadding = EdgeInsets.zero, //指示器padding
  this.indicator, // 指示器
  this.indicatorSize, // 指示器长度,有两个可选值,一个tab的长度,一个是label长度
  this.labelColor, 
  this.labelStyle,
  this.labelPadding,
  this.unselectedLabelColor,
  this.unselectedLabelStyle,
  this.mouseCursor,
  this.onTap,
  ...
}) 

TabBar 通常位于 AppBar 的底部,它也可以接收一个 TabController ,如果需要和 TabBarView 联动, TabBar 和 TabBarView 使用同一个 TabController 即可,注意,联动时 TabBar 和 TabBarView 的孩子数量需要一致。如果没有指定 controller,则会在组件树中向上查找并使用最近的一个 DefaultTabController 。另外我们需要创建需要的 tab 并通过 tabs 传给 TabBar, tab 可以是任何 Widget,不过Material 组件库中已经实现了一个 Tab 组件,我们一般都会直接使用它:

const Tab({
  Key? key,
  this.text, //文本
  this.icon, // 图标
  this.iconMargin = const EdgeInsets.only(bottom: 10.0),
  this.height,
  this.child, // 自定义 widget
})

注意,textchild 是互斥的,不能同时指定。

三、简单示例

下面我们看一个例子:

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: DefaultTabController(
        length: 3, // 选项卡的数量
        child: Scaffold(
          appBar: AppBar(
            title: const Text('TabBarView示例'),
            bottom: const TabBar(
              tabs: [
                Tab(text: '选项卡1'),
                Tab(text: '选项卡2'),
                Tab(text: '选项卡3'),
              ],
            ),
          ),
          body: const TabBarView(
            children: [
              // 每个选项卡的内容
              Center(child: Text('选项卡1内容')),
              Center(child: Text('选项卡2内容')),
              Center(child: Text('选项卡3内容')),
            ],
          ),
        ),
      ),
    );
  }
}

点一点,滑动滑动。常规得不能再常规。效果图如下所示:

Flutter_tabBarView_A.gif


上面这几行代码,我们可以知道。

  • DefaultTabControllerlength 属性设置为3,表示我们有三个选项卡。

  • DefaultTabControllerchild 属性中,我们创建了一个 Scaffold,这是一个包含应用程序基本布局的小部件。Scaffold 包括一个 AppBar 和一个 TabBarView

  • AppBar 是顶部的应用栏,它包含一个标题("TabBarView示例")和一个 TabBar 小部件。TabBar 用于显示选项卡,它的 tabs 属性包含三个 Tab 小部件,分别命名为 "选项卡1","选项卡2" 和 "选项卡3"。

  • TabBarView 是一个小部件,用于显示选项卡内容。它的 children 属性包含了三个子小部件,每个子小部件都代表一个选项卡的内容。在这个示例中,内容很简单,只是一个居中显示的文本,分别对应 "选项卡1内容","选项卡2内容" 和 "选项卡3内容"。


四、不结合Scaffold的示例

可以使用DefaultTabControllerTabBarTabBarView,并将它们包裹在您自己的自定义布局中。不结合Scaffold;

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: DefaultTabController(
        length: 3, // 选项卡的数量
        child: MyTabBarView(),
      ),
    );
  }
}

class MyTabBarView extends StatefulWidget {
  const MyTabBarView({super.key});
  @override
  State<MyTabBarView> createState() => _MyTabBarViewState();
}

class _MyTabBarViewState extends State<MyTabBarView> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('TabBarView示例'),
        bottom: const TabBar(
          tabs: [
            Tab(
              text: '选项卡1',
            ),
            Tab(
              text: '选项卡2',
            ),
            Tab(
              text: '选项卡3',
            ),
          ],
          labelStyle: TextStyle(
            fontSize: 16,
            fontWeight: FontWeight.bold,
            color: Colors.red,
          ),
        ),
      ),
      body: const TabBarView(
        physics: BouncingScrollPhysics(), // 添加弹簧效果
        children: [
          // 每个选项卡的内容
          Center(child: Text('选项卡1内容')),
          Center(child: Text('选项卡2内容')),
          Center(child: Text('选项卡3内容')),
        ],
      ),
    );
  }
}

效果图如下所示:

Flutter_tabBarView_B.gif


五、来点自定义

5.1 自定义选项卡视图

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: DefaultTabController(
        length: 3, // 选项卡的数量
        child: Scaffold(
          appBar: AppBar(
            title: const Text('TabBarView示例'),
            bottom: const TabBar(
              tabs: [
                Tab(
                  text: '选项卡1',
                  icon: Icon(Icons.home), // 添加图标
                ),
                Tab(
                  text: '选项卡2',
                  icon: Icon(Icons.business), // 添加不同图标
                ),
                Tab(
                  text: '选项卡3',
                  icon: Icon(Icons.school), // 添加不同图标
                ),
              ],
              labelStyle: TextStyle(
                fontSize: 16,
                fontWeight: FontWeight.bold,
                color: Colors.red,
              ),
            ),
          ),
          body: const TabBarView(
            children: [
              // 每个选项卡的内容
              Center(child: Text('选项卡1内容')),
              Center(child: Text('选项卡2内容')),
              Center(child: Text('选项卡3内容')),
            ],
          ),
        ),
      ),
    );
  }
}

效果图如下所示:

Flutter_tabBarView_D.png


5.2 tabBar在底部,tabBarView在上方

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: DefaultTabController(
        length: 3,
        child: Scaffold(
          body: Column(
            children: [
              const Expanded(
                child: TabBarView(
                  children: [
                    Center(child: Text('选项卡1内容')),
                    Center(child: Text('选项卡2内容')),
                    Center(child: Text('选项卡3内容')),
                  ],
                ),
              ),
              Container(
                color: Colors.blue, // 设置TabBar的背景颜色
                child: const TabBar(
                  tabs: [
                    Tab(
                      text: '选项卡1',
                      icon: Icon(Icons.home),
                    ),
                    Tab(
                      text: '选项卡2',
                      icon: Icon(Icons.business),
                    ),
                    Tab(
                      text: '选项卡3',
                      icon: Icon(Icons.school),
                    ),
                  ],
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

效果图如下所示:

Flutter_tabBarView_E.png


5.3 自定义选项卡的背景颜色

  • 字体大小、颜色、粗细等
  • 自定义选项卡的颜色
  • 自定义tab的图标和文本的距离
  • 自定义选项卡指示器的背景颜色
  • 自定义整个TabBar的颜色
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: DefaultTabController(
        length: 3, // 选项卡的数量
        child: Scaffold(
          appBar: AppBar(
            backgroundColor: Colors.brown, // 设置AppBar的背景颜色为棕色
            title: const Text('TabBarView示例'),
            bottom: const TabBar(
              tabs: [
                Tab(
                  text: '选项卡1',
                  icon: Icon(Icons.home), // 添加图标
                  // 特殊设置一下
                  iconMargin: EdgeInsets.only(bottom: 0.0), // 图标与文本之间的距离
                ),
                Tab(
                  text: '选项卡2',
                  icon: Icon(Icons.business), // 添加不同图标
                ),
                Tab(
                  text: '选项卡3',
                  icon: Icon(Icons.school), // 添加不同图标
                ),
              ],

              // 字体大小、颜色、粗细等
              labelStyle: TextStyle(
                fontSize: 18, // 自定义字体大小
                fontWeight: FontWeight.bold, // 字体粗细
                color: Colors.blue, // 文本颜色
              ),

              // 自定义选项卡的颜色
              labelColor: Colors.red, // 选中状态下的文本颜色
              unselectedLabelColor: Colors.grey, // 未选中状态下的文本颜色

              // 自定义选项卡指示器的背景颜色
              indicatorColor: Colors.blue, // 选中状态下的指示器颜色
              indicatorWeight: 4.0, // 选中状态下的指示器厚度
              indicatorSize:
                  TabBarIndicatorSize.label, // 指示器大小计算方式  tab、label两种方式
              indicatorPadding:
                  EdgeInsets.symmetric(horizontal: 16.0), // 指示器内边距
            ),
          ),
          body: const TabBarView(
            children: [
              // 每个选项卡的内容
              Center(child: Text('选项卡1内容')),
              Center(child: Text('选项卡2内容')),
              Center(child: Text('选项卡3内容')),
            ],
          ),
        ),
      ),
    );
  }
}

效果图如下所示:

Flutter_tabBarView_I.png


六、稍微高级一点的自定义

6.1 tabBar自定义。圆角啊,线包裹啊

PreferredSize 走一个

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage>
    with SingleTickerProviderStateMixin {
  TabController? _tabController;

  @override
  void initState() {
    super.initState();
    _tabController = TabController(length: 3, vsync: this);
  }

  @override
  void dispose() {
    _tabController?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Custom TabBar'),
        bottom: PreferredSize(
          preferredSize: const Size.fromHeight(50.0),
          child: Container(
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(20),
              border: Border.all(color: Colors.red),
            ),
            margin: const EdgeInsets.all(10),
            padding: const EdgeInsets.all(1),
            child: TabBar(
              controller: _tabController,
              indicator: BoxDecoration(
                borderRadius: BorderRadius.circular(20),
                color: Colors.red,
              ),
              unselectedLabelColor: Colors.black,
              labelColor: Colors.white,
              tabs: const [
                Tab(text: '选项卡1'),
                Tab(text: '选项卡2'),
                Tab(text: '选项卡3'),
              ],
            ),
          ),
        ),
      ),
      body: TabBarView(
        controller: _tabController,
        children: const [
          Center(child: Text('选项卡1内容')),
          Center(child: Text('选项卡2内容')),
          Center(child: Text('选项卡3内容')),
        ],
      ),
    );
  }
}

效果图如下所示:

Flutter_tabBarView_G.png


6.2 用Row代替Tabvar,TabController走一个

要使用Row来实现类似TabBar的效果,并且不使用PreferredSize

可以自定义一个Row来放置的选项卡,并使用TabController来控制TabBarView

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});
  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage>
    with SingleTickerProviderStateMixin {
  late TabController _tabController;

  @override
  void initState() {
    super.initState();
    _tabController = TabController(length: 3, vsync: this);
  }

  @override
  void dispose() {
    _tabController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Custom TabBar'),
        bottom: AppBarBottom(tabController: _tabController),
      ),
      body: TabBarView(
        controller: _tabController,
        children: const [
          Center(child: Text('选项卡1内容')),
          Center(child: Text('选项卡2内容')),
          Center(child: Text('选项卡3内容')),
        ],
      ),
    );
  }
}

class AppBarBottom extends StatefulWidget implements PreferredSizeWidget {
  final TabController tabController;

  const AppBarBottom({required this.tabController});

  @override
  State<AppBarBottom> createState() => _AppBarBottomState();

  @override
  Size get preferredSize => Size.fromHeight(50.0);
}

class _AppBarBottomState extends State<AppBarBottom> {
  @override
  void initState() {
    super.initState();
    widget.tabController.addListener(_setActiveTab);
  }

  void _setActiveTab() {
    if (mounted) {
      setState(() {}); // 触发重建
    }
  }

  @override
  void dispose() {
    widget.tabController.removeListener(_setActiveTab);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: const EdgeInsets.all(10),
      padding: const EdgeInsets.all(1),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: List<Widget>.generate(3, (int index) {
          bool isSelected = widget.tabController.index == index;
          return GestureDetector(
            onTap: () => widget.tabController.animateTo(index),
            child: Container(
              padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 20),
              decoration: BoxDecoration(
                color: isSelected ? Colors.red : Colors.transparent,
                borderRadius: BorderRadius.circular(20),
                border:
                    Border.all(color: isSelected ? Colors.red : Colors.grey),
              ),
              child: Text(
                '选项卡${index + 1}',
                style: TextStyle(
                  color: isSelected ? Colors.white : Colors.black,
                ),
              ),
            ),
          );
        }),
      ),
    );
  }
}

效果图如下所示:

Flutter_tabBarView_H.png


标签:TabBarView,选项卡,Text,TabBar,child,组件,const,Flutter
From: https://www.cnblogs.com/linuxAndMcu/p/18458650

相关文章

  • Flutter可滚动组件(6):可滚动组件子项缓存
    本节将介绍可滚动组件中缓存指定子项的通用方案。首先回想一下,在介绍ListView时,有一个addAutomaticKeepAlives属性我们并没有介绍,如果addAutomaticKeepAlives为true,则ListView会为每一个列表项添加一个AutomaticKeepAlive父组件。虽然PageView的默认构造函数和PageVi......
  • Flutter功能性组件(1):对话框
    Material库提供了三种基本对话框组件AlertDialog通常用于提示型对话框SimpleDialog通常用于列表型对话框Dialog通常用于自定义布局元素的对话框弹出对话框时,调用showDialog函数,将对话框控件传入,由于对话框本身是路由,所以关闭对话框时,需使用Navigator.of(context).pop......
  • Flutter可滚动组件(9):嵌套可滚动组件 NestedScrollView
    一、NestedScrollView上一节中,我们知道CustomScrollView只能组合Sliver,如果有孩子也是一个可滚动组件(通过SliverToBoxAdapter嵌入)且它们的滑动方向一致时便不能正常工作。为了解决这个问题,Flutter中提供了一个NestedScrollView组件,它的功能是组合(协调)两个可滚动组件,下面我......
  • Flutter功能性组件(2):弹出框
    一、showModalBottomSheet(模态底部弹出框)showModalBottomSheet用于显示一个模态底部弹出框。属性解析:Future<T?>showModalBottomSheet<T>({requiredBuildContextcontext,//表示底部弹出框所处的上下文,通常来自当前widget。requiredWidgetBuilderbuilder,//用......
  • Flutter基础组件(7):进度条
    在Flutter应用开发中,无论是处理网络请求,执行耗时任务,或是等待用户响应,我们总是需要在界面上显示进度条或者等待指示器。在这篇博客中,我们将介绍Flutter中两种常用的进度指示器:LinearProgressIndicator和CircularProgressIndicator。我们将比较它们的异同点,以及如何使用和自......
  • Flutter基础组件(6):单选按钮、复选框、单选开关
    在移动应用开发中,单选和复选是常见的用户交互模式,用于选择一个或多个选项。Flutter提供了一些内置的组件和机制,方便我们实现单选和复选功能。本文将介绍Flutter中的单选按钮(RadioButton)和复选框(Checkbox)的使用方法和示例。一、单选按钮(RadioButton)单选按钮是一种用户界面组件......
  • Flutter布局(2):弹性布局(Flex、Expanded)
    一、什么是弹性布局(Flex)什么是弹性布局(Flex)?弹性布局(Flex)是一种基于弹性盒子模型的布局方式,类似于Web开发中的Flexbox。在Flutter中,Flex组件是用于实现弹性布局的关键组件之一。Flex布局是一种简洁且强大的方式,可用于构建水平或垂直方向的弹性布局。Flex组件可以沿着水平......
  • Flutter布局(1):线性布局(Row、Column)
    所谓线性布局,即指沿水平或垂直方向排列子组件。Flutter中通过Row和Column来实现线性布局。主轴和纵轴对于线性布局,有主轴和纵轴之分,如果布局是沿水平方向,那么主轴就是指水平方向,而纵轴即垂直方向;如果布局沿垂直方向,那么主轴就是指垂直方向,而纵轴就是水平方向。一、Row组件1.1......
  • Flutter布局(4):层叠布局(Stack、Positioned)
    层叠布局和Web中的绝对定位、Android中的Frame布局是相似的,子组件可以根据距父容器四个角的位置来确定自身的位置。层叠布局允许子组件按照代码中声明的顺序堆叠起来。Flutter中使用Stack和Positioned这两个组件来配合实现绝对定位。Stack允许子组件堆叠,而Positioned用于根据......
  • Flutter布局(3):流式布局(Wrap、Flow)
    一、简介在Flutter中,流式布局是一种常用的布局方式,用于实现动态调整子组件位置和尺寸的需求。Flutter提供了两个流式布局的组件:Wrap和Flow。其实,Flow用的实在不多呀。二、Wrap组件Wrap组件是一种流式布局,它会自动调整和换行子组件,以适应可用空间。属性Wrap组件具有......