美文网首页
TabBar组件实践 2023-07-22 周六

TabBar组件实践 2023-07-22 周六

作者: 勇往直前888 | 来源:发表于2023-07-23 10:30 被阅读0次

    简介

    原先的工程中用了TabBar,最简单的那种。现在UI提出了优化要求,那么就要在原先的基础上进行样式修改。

    企业微信截图_6f86b386-831b-4c4c-89cf-d32bc6f8c0dc.png

    选择:系统组件还是自定义?

    • 使用系统提供的TabBarTabBarView套装

    • 使用ContainerListView等模拟

    经过纠结,最终还是决定用TabBarTabBarView套装,通过给出的属性来逐步达到目的;

    使用ContainerListView等模拟这种方式,实在没办法的时候再考虑;

    • TabBarView只是一个容器,所以UI的难度集中在TabBar

    TabBar常用属性

    高度

    class TabBar extends StatefulWidget implements PreferredSizeWidget可以看出,TabBar是一种PreferredSizeWidget。所以,可以考虑把TabBar放到一个PreferredSize组件中,高度就根据tabs的数量来

    @override
      Widget build(BuildContext context) {
        double height = 30.h;
        if (tabs.length < 4) {
          height = 44.h;
        }
        return PreferredSize(
          preferredSize: Size.fromHeight(height),
          child: TabBar(
            tabs: tabs,
          ),
        );
      }
    

    控制器

    这个是TabBarTabBarView联动的纽带,大多数情况是需要的,只需要按照原来的定义透传就可以了。

    文本

    • 颜色与其他样式分开设置;

    • 选中与不选中分开设置;

        this.labelColor,
        this.labelStyle,
        this.unselectedLabelColor,
        this.unselectedLabelStyle,
    

    滑动切换

    这个默认是this.isScrollable = false,;通常要改为true

    文本间距

    • Tab底层应该是类似ListView的实现,等分是不大好做的;

    • 可以通过labelPadding这个属性模拟;tab少的时候大一些,tab多的时候小一些;

    指示器大小

    • 对应的属性是indicatorSize

    • 默认是和tab容器宽度一样TabBarIndicatorSize.tab

    • 按照设计图,这里要改为TabBarIndicatorSize.label, 和tab的文字一样长度;

    指示器pad

    • 对应的属性是indicatorPadding

    • 默认都是0,所以是和文字一样宽度,紧贴底部;

    • 这里,按照设计图给一下就好;

    • 另外,指示器和tab内容应该用了stack,两者不是一个图层。所以,设置indicatorPadding可以改变指示器和文本之间的间距。

    指示器形状

    • 如果只是调整一下颜色和粗细,可以设置这两个属性
        this.indicatorColor,
        this.indicatorWeight = 2.0,
    
    • 如果需要圆角,那么就需要使用this.indicator属性;同时,上面两个属性失效

    • this.indicator的类型是Decoration;但是这个是虚基类,真正有用的是UnderlineTabIndicator

            indicator: UnderlineTabIndicator(
              borderRadius: BorderRadius.circular(1.5.h),
              borderSide: BorderSide(
                color: const Color(0xFF11BA66),
                width: 3.h,
              ),
            ),
    

    tabs

    • 类型定义是普通的Widgetfinal List<Widget> tabs;

    • 但是,实际上一般都是给Tab组件

    const Tab({
        super.key,
        this.text,
        this.icon,
        this.iconMargin = const EdgeInsets.only(bottom: 10.0),
        this.height,
        this.child,
      })
    
    • 从定义上看,可以是文字,也可以是图片,也可以是自定义widget;但是实际上,大多数情况是文本。

    • 所以,这里简单处理,就是直接规定为文本

            tabs: textList
                .map((text) => Tab(
                      text: text,
                    ))
                .toList(),
    

    封装为组件

    由于Flutter的特性,就像套娃一样一层层嵌套。所以考虑在外面TabBar外面套一层,把上面那些讨论过的属性定义封装起来。

    class PandaTabBar extends StatelessWidget implements PreferredSizeWidget {
      const PandaTabBar({
        Key? key,
        required this.textList,
        this.controller,
      }) : super(key: key);
    
      final TabController? controller;
      final List<String> textList;
    
      @override
      Widget build(BuildContext context) {
        /// 参数判空
        if (textList.isEmpty) {
          return Container();
        }
    
        /// Tab个数4个以下,高度44;其他情况,高度30
        /// 文本之间的间距,4个以下,40;其他情况15
        double height = 30.h;
        double pad = 15.w;
        if (textList.length < 4) {
          height = 44.h;
          pad = 40.w;
        }
        return PreferredSize(
          preferredSize: Size.fromHeight(height),
          child: TabBar(
            controller: controller,
            labelColor: const Color(0xFF11BA66),
            unselectedLabelColor: PandaColorConfig().col333333,
            labelStyle: TextStyle(
              fontSize: 16.sp,
              fontWeight: FontWeight.w500,
            ),
            unselectedLabelStyle: TextStyle(
              fontSize: 16.sp,
              fontWeight: FontWeight.w400,
            ),
            isScrollable: true,
            labelPadding: EdgeInsets.symmetric(horizontal: pad),
            indicatorSize: TabBarIndicatorSize.label,
            indicatorPadding: EdgeInsets.symmetric(horizontal: 5.w, vertical: 9.h),
            indicator: UnderlineTabIndicator(
              borderRadius: BorderRadius.circular(1.5.h),
              borderSide: BorderSide(
                color: const Color(0xFF11BA66),
                width: 3.h,
              ),
            ),
            tabs: textList
                .map((text) => Tab(
                      text: text,
                    ))
                .toList(),
          ),
        );
    
      @override
      Size get preferredSize => Size.fromHeight(44.h);
      }
    

    指示器固定大小

    • 系统提供的指示器,宽度给了两种模式,和容器一样(加padding),或者和文字一样(加偏移)

    • 指示器给出的是方角,不是圆角。

    • 如果要求指示器固定宽度,并且是圆角,那么就需要自定义UnderlineTabIndicator

    • 做法也很取消,就是复制UnderlineTabIndicator的内容,改个名字,然后稍微修改一下代码。

    • 具体做法这篇文章写的非常清楚:Flutter tabbar自定义indicator的固定宽度、圆角

    参考文章

    flutter tabBar 的属性及自定义实现

    Flutter UnderlineTabIndicator BoxDecoration ShapeDecoration FlutterLogoDecoration

    Flutter设置TabBar indicator宽度(爆改UnderlineTabIndicator )

    相关文章

      网友评论

          本文标题:TabBar组件实践 2023-07-22 周六

          本文链接:https://www.haomeiwen.com/subject/nvutpdtx.html