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 分钟前
flutter 跨平台编码库 protobuf 工具使用
android·flutter
程序员老刘·16 分钟前
Flutter 3.35 更新要点解析
flutter·ai编程·跨平台开发·客户端开发
tangweiguo0305198716 分钟前
Flutter vs Android:页面生命周期对比详解
flutter
tangweiguo0305198721 分钟前
Flutter网络请求实战:Retrofit+Dio完美解决方案
flutter
听雪楼主.26 分钟前
Oracle Undo Tablespace 使用率暴涨案例分析
数据库·oracle·架构
高阳言编程26 分钟前
5. 标量处理机
架构
小小愿望1 小时前
前端无法获取响应头(如 Content-Disposition)的原因与解决方案
前端·后端
小小愿望1 小时前
项目启功需要添加SKIP_PREFLIGHT_CHECK=true该怎么办?
前端
烛阴1 小时前
精简之道:TypeScript 参数属性 (Parameter Properties) 详解
前端·javascript·typescript
海上彼尚2 小时前
使用 npm-run-all2 简化你的 npm 脚本工作流
前端·npm·node.js