Flutter速来系列23-2、来吧TabBarView选项卡,绚丽的自定义,都能写的呀

是啊,Tab啊,滑动啊,点击啊,它是个混蛋啊。每个App都要写的啊。 但是不论如何,flutter官方封装的,拯救了我们的时间。

但是官方效果有限,既然如此。整活吧。

由由由由由由由浅入深,让小白来了,也能哇偶,明明明明明明明明了。

后面呢,搞点自定义。

比如:

在比如:


Emm,哪怕是微信,底部也是几个选项卡。几个tab。

一、TabBarView 经典开打

TabBarView,用于创建具有选项卡导航的可滚动视图。

上代码。

DART 复制代码
import 'package:flutter/material.dart';

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

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

是的,点一点,滑动滑动。常规得不能再常规。

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


  1. DefaultTabControllerlength 属性设置为3,表示我们有三个选项卡。
  2. DefaultTabControllerchild 属性中,我们创建了一个 Scaffold,这是一个包含应用程序基本布局的小部件。Scaffold 包括一个 AppBar 和一个 TabBarView
  3. AppBar 是顶部的应用栏,它包含一个标题("TabBarView示例")和一个 TabBar 小部件。TabBar 用于显示选项卡,它的 tabs 属性包含三个 Tab 小部件,分别命名为 "选项卡1","选项卡2" 和 "选项卡3"。
  4. TabBarView 是一个小部件,用于显示选项卡内容。它的 children 属性包含了三个子小部件,每个子小部件都代表一个选项卡的内容。在这个示例中,内容很简单,只是一个居中显示的文本,分别对应 "选项卡1内容","选项卡2内容" 和 "选项卡3内容"。

要注意哈,TabBar和TabBarView并不需要一定结合一起


Emm,如果换成原生安卓或者原生iOS,Emm,不说了。


不结合Scaffold可以吗,当然可以

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

less 复制代码
import 'package:flutter/material.dart';

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

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

class MyTabBarView extends StatefulWidget {
  @override
  _MyTabBarViewState createState() => _MyTabBarViewState();
}

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

二、来点自定义

自定义选项卡视图

less 复制代码
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: DefaultTabController(
        length: 3, // 选项卡的数量
        child: Scaffold(
          appBar: AppBar(
            title: Text('TabBarView示例'),
            bottom: 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: TabBarView(
            children: [
              // 每个选项卡的内容
              Center(child: Text('选项卡1内容')),
              Center(child: Text('选项卡2内容')),
              Center(child: Text('选项卡3内容')),
            ],
          ),
        ),
      ),
    );
  }
}

看图


是的,看起来还是简单,但是还可以更多自定义。


tabBar在底部,tabBarView在上方,可以吗,可以

DART 复制代码
import 'package:flutter/material.dart';

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

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

自定义选项卡的背景颜色

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: DefaultTabController(
        length: 3, // 选项卡的数量
        child: Scaffold(
          appBar: AppBar(
            backgroundColor: Colors.brown, // 设置AppBar的背景颜色为棕色
            title: Text('TabBarView示例'),
            bottom: 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: TabBarView(
            children: [
              // 每个选项卡的内容
              Center(child: Text('选项卡1内容')),
              Center(child: Text('选项卡2内容')),
              Center(child: Text('选项卡3内容')),
            ],
          ),
        ),
      ),
    );
  }
}

但是,不够,远远不够。


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

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

PreferredSize 走一个

less 复制代码
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState 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: Text('Custom TabBar'),
        bottom: PreferredSize(
          preferredSize: Size.fromHeight(50.0),
          child: Container(
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(20),
              border: Border.all(color: Colors.red),
            ),
            margin: EdgeInsets.all(10),
            padding: EdgeInsets.all(1),
            child: TabBar(
              controller: _tabController,
              indicator: BoxDecoration(
                borderRadius: BorderRadius.circular(20),
                color: Colors.red,
              ),
              unselectedLabelColor: Colors.black,
              labelColor: Colors.white,
              tabs: [
                Tab(text: '选项卡1'),
                Tab(text: '选项卡2'),
                Tab(text: '选项卡3'),
              ],
            ),
          ),
        ),
      ),
      body: TabBarView(
        controller: _tabController,
        children: [
          Center(child: Text('选项卡1内容')),
          Center(child: Text('选项卡2内容')),
          Center(child: Text('选项卡3内容')),
        ],
      ),
    );
  }
}

核心,就是 PreferredSize

这不就是以前原生那些看起来很复杂的效果吗

只能说,Flutter,优秀。

但是你知道,不够,这远远不够。


用Row代替Tabvar,TabController走一个

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

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

dart 复制代码
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState 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: Text('Custom TabBar'),
        bottom: AppBarBottom(tabController: _tabController),
      ),
      body: TabBarView(
        controller: _tabController,
        children: [
          Center(child: Text('选项卡1内容')),
          Center(child: Text('选项卡2内容')),
          Center(child: Text('选项卡3内容')),
        ],
      ),
    );
  }
}

class AppBarBottom extends StatefulWidget implements PreferredSizeWidget {
  final TabController tabController;

  AppBarBottom({required this.tabController});

  @override
  _AppBarBottomState 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: EdgeInsets.all(10),
      padding: 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: 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,
                ),
              ),
            ),
          );
        }),
      ),
    );
  }
}

如果看到了这里,还不知道点个赞。那就,过分了呀

请及时点赞。我不要面子的吗??? 请及时点赞。我不要面子的吗??? 请及时点赞。我不要面子的吗??? 请及时点赞。我不要面子的吗???

其实呢,我觉得,完全可以了。

没必要再写了。

举一反三,想要什么效果,自己写吧。

其实可以留言666了。说的就是你,你要知道,写作,很花时间的。

点赞评论,是先富起来的基础条件! 点赞评论,是先富起来的基础条件!! 点赞评论,是先富起来的基础条件!!! 点赞评论,是先富起来的基础条件!!!! 点赞评论,是先富起来的基础条件!!!!!

完事,洗澡。

相关推荐
只喜欢赚钱的棉花没有糖14 分钟前
http的缓存问题
前端·javascript·http
小小小小宇29 分钟前
请求竞态问题统一封装
前端
loriloy30 分钟前
前端资源帖
前端
源码超级联盟32 分钟前
display的block和inline-block有什么区别
前端
GISer_Jing38 分钟前
前端构建工具(Webpack\Vite\esbuild\Rspack)拆包能力深度解析
前端·webpack·node.js
让梦想疯狂40 分钟前
开源、免费、美观的 Vue 后台管理系统模板
前端·javascript·vue.js
海云前端1 小时前
前端写简历有个很大的误区,就是夸张自己做过的东西。
前端
葡萄糖o_o1 小时前
ResizeObserver的错误
前端·javascript·html
AntBlack1 小时前
Python : AI 太牛了 ,撸了两个 Markdown 阅读器 ,谈谈使用感受
前端·人工智能·后端
ZFJ_张福杰2 小时前
【Flutter】Widget、Element和Render的关系-Flutter三棵树
flutter