一、话不多说,先来看下实现的交互效果,源码在文末

二、首先分解一下需求

  1. 自定义Tab指示器与Tab
  2. 当秒杀节点小于5个的时候,每一个Tab的宽度为平分屏幕宽度
  3. 当大于等于5个的时候,每一个Tab的宽度为固定宽度

1、先来看下最简单的TabBar与TabBarView需要如何实现

/// 省略若干代码...
@override
Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('TabBar'),bottom: TabBar(controller: _tabController,tabs: [Tab(text: "热销"),Tab(text: "推荐"),Tab(text: "我的"),],),),body: TabBarView(controller: _tabController,children: [Center(child: Text('热销')),Center(child: Text('推荐')),Center(child: Text('我的')),],),);
}

上面代码实现的效果

2、通过阅读TabBar的源码可以知道tabs属性接收widget集合,这也就是我们自定义Tab的突破口了

/// Typically a list of two or more [Tab] widgets.
///
/// The length of this list must match the [controller]'s [TabController.length]
/// and the length of the [TabBarView.children] list.
final List<Widget> tabs;

三、通过画图来分析一下整个Tab的层级结构

  • 白色层:就是TabBar所占的高度(Tab高度+三角箭头高度)
  • 灰色层:就是每一个Tab所占的高度
  • 红色层:就是自定义的TabBar indicator

1、通过上面的图我们需要定义如下一些数据:

  1. 每个Tab的宽度和高度
double _tabWidth = 82.0;
double _tabHeight = 70.0;
  1. 三角形的宽高
Size triangleSize = Size(10, 10);

2、每一个Tab通过Container组件来实现

class FlashSale extends StatefulWidget {@overrideFlashSaleState createState() => new FlashSaleState();
}
class FlashSaleState extends State<FlashSale>with SingleTickerProviderStateMixin {TabController _tabController;List<String> _list;double _tabWidth = 82.0;double _tabHeight = 70.0;///定义三角的大小Size triangleSize = Size(10, 10);@overridevoid initState() {super.initState();_list = ['10:00', '11:00', '12:00', '13:00', '14:00'];_tabController =TabController(initialIndex: 0, length: _list.length, vsync: this);}@overrideWidget build(BuildContext context) {return Scaffold(///省略....body: Column(children: [TabBar(isScrollable: true,controller: _tabController,tabs: _list.map((e) {return _tab(e);}).toList(),)///省略TabBarView内容...],),);}Widget _tab(String content) {return Container(width: _tabWidth,height: _tabHeight + triangleSize.height,child: Padding(padding: EdgeInsets.only(bottom: triangleSize.height),child: Column(mainAxisAlignment: MainAxisAlignment.center,children: [Text(content,style: TextStyle(color: Colors.white, fontSize: 22),),Text('抢购中',style: TextStyle(color: Colors.white, fontSize: 14),)],),),);}}

Container的高度就是上面说到的,需要加上三角形的高度;如下效果图
这里文字需要剧中,所以需要padding bottom 三角形的高度

3、现在就需要给每一个Tab添加灰色未选中的颜色了;很容易想到是加在Container中的,但是加在这里是有问题的我们需要把这个灰色加在TabBar这里;但是现在我们TabBar的高度=Tab高度 + 三角箭头高度所以加在这里会使得三角箭头区域也是灰色,那这样需要怎么处理呢?解决方法如下

  • 通过Stack布局方式在TabBar底部层叠个灰色的Container
///省略....
@override
Widget build(BuildContext context) {return Scaffold(///省略....body: Column(children: [Stack(children: [Container(width: double.infinity,height: _tabHeight,color: Color(0xFF4D525C),),TabBar(isScrollable: true,controller: _tabController,tabs: _list.map((e) {return _tab(e);}).toList(),)],)///省略TabBarView内容...],),);
}

四、现在重要的一步就是自定义TabBarindicator,通过源码可知是一个Decoration对象,所以我们只需继承它即可

1、一个继承Decoration最基本的结构就是下面的样子了

class TriangleIndicator extends Decoration {//三角形的大小final Size triangleSize;TriangleIndicator(this.triangleSize);@overrideBoxPainter createBoxPainter([VoidCallback onChanged]) {return _CustomBoxPainter(triangleSize);}
}class _CustomBoxPainter extends BoxPainter {final Size triangleSize;_CustomBoxPainter(this.triangleSize);@overridevoid paint(Canvas canvas, Offset offset, ImageConfiguration configuration) {}
}
  • 然后在TabBar处使用即可
//省略其它...
TabBar(isScrollable: true,controller: _tabController,indicator: TriangleIndicator(triangleSize),tabs: _list.map((e) {return _tab(e);}).toList(),
)

2、接下来就只需要在paint函数中将选中的Tab样式绘制出来即可(写过Android自定义View看着就会显的很亲切了)

  • 绘制矩形
@override
void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) {///每个Tab的宽高Size tabSize = Size(configuration.size.width,configuration.size.height - triangleSize.height);final Rect rect = offset & tabSize;final Paint paint = Paint();paint.color = Color(0xFFFF443D);paint.style = PaintingStyle.fill;///画Tab矩形canvas.drawRect(rect, paint);
}
  • offset参数:意思当前位置距离组建左上角的偏移量
  • configuration参数:当前画布的大小

  • 从图中发现绘制的高度减去了三角形区域的高度,可还是多出了一点,这是为什么呢?原因是TabBar的indicator默认给了高度为2,只需要将它设置为0即可
TabBar(//省略....indicatorWeight: 0,
)
  • 绘制三角形,这里通过Path来绘制,也就是三角形的 起点、中点、终点连接起来
@override
void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) {///每个Tab的宽高Size tabSize = Size(configuration.size.width,configuration.size.height - triangleSize.height);final Rect rect = offset & tabSize;final Paint paint = Paint();paint.color = Color(0xFFFF443D);paint.style = PaintingStyle.fill;///画Tab矩形canvas.drawRect(rect, paint);///画三角形double start = (tabSize.width - triangleSize.width) / 2;Path trianglePath = Path();///起点trianglePath.moveTo(start + offset.dx, configuration.size.height - triangleSize.height);///中点trianglePath.lineTo((tabSize.width / 2) + offset.dx, configuration.size.height);///终点trianglePath.lineTo(start + offset.dx + triangleSize.width,configuration.size.height - triangleSize.height);canvas.drawPath(trianglePath, paint);
}

五、最后一条需求动态改变每个Tab的宽高,这个也很简单:只需要判断当前有几个Tab然后动态计算即可,直接查看源码即可

本篇源码下载地址

Flutter 自定义TabBar指示器(indicator)实现秒杀UI样式相关推荐

  1. 微信小程序自定义tabbar导航栏,中间凸出样式

    这种样式的底部导航栏 使用微信小程序的自定义tabBar:微信小程序官方说明 uni.app=>在 page.json 中的 tabBar 项指定 custom 字段为true: "t ...

  2. flutter 自定义Tabbar高度和背景色

    最近在学习flutter相关的知识,在学到Tabbar的时候默认无法修改它的高度背景色,在网上查看被人的代码后自己封装了一下.你可以复制直接使用.(不排除有更好的实现方法,我也是刚接触flutter) ...

  3. Flutter自定义 TabBar

    TabBar常用于放在AppBar中,以标签页的形式展示同一个页面不同内容的主题标签. 常见的属性如下: 1. tabs 标签组: 2. controller 标签控制器: 3. isScrollab ...

  4. 小程序(三)配置tabbar及自定义tabbar样式

    关于tabbar部分,官方文档是有明确的说明的,当然,我这里是不存在把官方文档给你复制一遍的情况.我大概把我再看官方文档过程中遇到的坑,大概复述一下. 一:配置tabbar 这个主要是使用小程序自带的 ...

  5. Flutter 组件之 Flutter高级自定义TabBar(教程含源码)

    实战需求 Flutter 组件之 Flutter高级自定义TabBar(教程含源码) 本文价值与收获 看完本文后,您将能够作出下面的界面 实战代码 import 'package:flutter/ma ...

  6. React Native ScrollableTabView的自定义tabBar

    react-native-scrollable-tab-view是一个非常好用的TabBar组件,支持滑动,可以实现标签超过屏幕宽度的情况.但是有时会需要实现比如提示未读个数.定制样式这些需求,那么已 ...

  7. 微信小程序 五 npm 包 、安装 vant组件、promise组件、全局数据共享、 分包!!!、自定义 tabBar 案例

    总结 能够知道如何安装和配置 vant-weapp 组件库 参考 Vant 的官方文档 能够知道如何使用 MobX 实现全局数据共享 安装包.创建 Store.参考官方文档进行使用 能够知道如何对小程 ...

  8. 微信小程序 - 进阶(自定义组件、promis化、mobx、分包、自定义tabBar)

    文章目录 一.自定义组件 1.创建组件 2.引用组件 3.组件和页面区别 4.组件样式 5.data.methods.properties 6.小程序的 data 和 properties 区别 7. ...

  9. 二、TabLayout自定义图片指示器

    最近项目需求,多个tab切换显示不同的页面,但是tab的下划线是一个带有圆角阴影的下划线,看过Tablayout源码的小伙伴可能会知道,通过原生的TabLayout是无法实现的,想了解的可以看我的另一 ...

  10. 小程序自定义tabbar踩坑笔记

    最近在给客户做一个定制小程序,客户不喜欢小程序自带的tabbar,想要一个炫酷的异形的tabbar,翻看了小程序开发者文档是可以执行的. 参考官方网站,自定义tabBar 自定义 tabBar | 微 ...

最新文章

  1. directx 游戏模拟键盘输入
  2. 牛客小白月赛6 H 挖沟
  3. boost::mpl::min和boost::mpl::max相关的测试程序
  4. QT绘制堆叠水平条形图
  5. implementation of CreateBindingContext
  6. C++中堆和栈的完全解析
  7. 企业级实战03_真实项目实战SpringMVC整合ActiveMQ
  8. SQL安装文件挂起解决方法
  9. 时序数据库php,时序数据库InfluxDB
  10. 新手进阶:LoadRunner中Pacing的设置
  11. 软件观念革命:交互设计精髓_2021年中国传媒大学设计学考研招生分析、参考书目、复试线、真题回忆、考研经验指南篇...
  12. 苹果悬浮球_手机轻松实现多个系统!安卓手机运行苹果iOS系统?期待!
  13. ShineDisk M667固态修复记录 慧荣SM2258XT开卡量产工具
  14. 利用数据质量规则库推动数据质量管理
  15. 手机wps怎么设置打印横竖_WPS中横竖打印怎么设置
  16. 什么是语法糖(Syntactic sugar)?
  17. jpa报错:mappedBy reference an unknown target entity property:
  18. Kotlin 非对称加密RSA
  19. wireshark 抓包使用教程
  20. Arduino 浊度传感器 TS300B 的使用

热门文章

  1. 5G协议 基本架构 专有名词简称和缩写
  2. Linux操作系统之网络管理
  3. Vue指纹识别验证 h5plus
  4. MaXmaPLe v1.0 for v0.62冒险岛服务端发布
  5. SKlearn - ValueError: Unknown label type: 'continuous'
  6. C 语言面试题大汇总
  7. 云计算和web服务器应用,基于云计算的Web服务选择及应用研究
  8. 2019.7.summary
  9. oracle第二天笔记
  10. kubernetes 网络组件 calico 运行原理分析