欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

如何利用Flutter实现酷狗流畅Tabbar效果

程序员文章站 2023-01-14 15:30:41
前言在2021年末,酷狗发布了最新版11.0.0版本,这是一次重大的ui重构,更新完打开着实让我耳目一新。在原有风格上,整个app变得更加清爽,流畅。其中tabbar的风格让我非常感兴趣,如果用flu...

前言

在2021年末,酷狗发布了最新版11.0.0版本,这是一次重大的ui重构,更新完打开着实让我耳目一新。在原有风格上,整个app变得更加清爽,流畅。其中tabbar的风格让我非常感兴趣,如果用flutter来实现,或许是一个很有趣的事情。

效果图

如何利用Flutter实现酷狗流畅Tabbar效果

如何利用Flutter实现酷狗流畅Tabbar效果

分析效果

研究酷狗tabbar的动画可以发现,默认状态下在当前tab的中心处展示圆点,滑动时的效果拆分成两个以下部分:

  • 从单个tab a的中心根据x轴平移到tab b的中心位置;
  • 指示器的长度从圆点变长,再缩短为圆点。其中最大长度是可变的,跟两个tab的大小和距离都有关系;
  • 指示器虽然依赖tab的size和offset来变换,但和tab却基本是同一时间渲染的,整个过程非常顺滑;
  • 总的来说,酷狗的效果就是改变了指示器的渲染动画而已。

开发思路

从上面的分析可以明确,指示器的滑动效果一定跟每个tab的size和offset相关。那在flutter中,获取渲染信息我们马上能想到globalkey,通过globalkey的currentcontext对象获取rander信息,但这必须在视图渲染完成后才能获取,也就是说tab渲染完才能开始计算并渲染指示器。很显然不符合体验要求,同时频繁使用globalkey也会导致性能较差。

转变思路,我们需要在tab渲染的不断把信息传给指示器,然后更新指示器,这种方式自然想到了custompainter【之前写了很多canvas的控件,都是根据传入的值进行绘制,从而实现控件的变化了layout类】。在tab updatewidget的时候,不断把rander的信息传给画笔painter,然后更新绘制,理论上这样做是完全行得通的。

flutter tabbar 解析源码

为了验证我的思路,我开始研究官方tabbar是如何写的:

  • 进入tabbar类,直接查看build方法,可以看到为每个tab加入了globalkey,然后指示器用custompaint进行绘制;
  • 绘制指示器用custompaint跟我们的预想一致,那如何把绘制的size和offset传进去呢。我们来看_tablabelbar继承于flex,而flex又继承自multichildrenderobjectwidget,重写其createrenderobject方法;

查看真实的渲染对象:_tablabelbarrenderer,在performlayout中返回渲染的size和offset,并通过tabbar传入的_savetaboffsets方法保存到_indicatorpainter中;_savetaboffsets尤为重要,把tabbar的渲染位移通知给painter,从而让painter可以轻松算出tab之间的宽度差

  • 通过tabbar中的didchangedependencies和didupdatewidget生命周期,更新指示器;
  • 然后重点就在指示器_indicatorpainter如何进行绘制了。

实现步骤

通过理解flutter tabbar的实现思路,大体跟我们预想的差不多。不过官方继承了flex来计算offset和size,实现起来很优雅。所以我也不班门弄斧了,直接改动官方的tabbar就可以了。

  • 创建kugoutabbar,复制官方代码,修改引用,删除无关的类,只保留tabbar相关的代码。

如何利用Flutter实现酷狗流畅Tabbar效果

2. 重点修改_indicatorpainter,根据我们的需求来绘制指示器。在painter方法中,我们可以通过controller拿到当前tab的index以及animation!.value, 我们模拟下切换的过程,当tab从第0个移到第1个,动画的值从0变成1,然后动画走到0.5时,tab的index会从0突然变为1,指示器应该是先变长,然后在动画走到0.5时,再变短。因此动画0.5之前,我们用动画的value-index作为指示器缩放的倍数,指示器不断增大;动画0.5之后,用index-value作为缩放倍数,不断缩小。

而指示器接收缩放倍数的前提还需要计算指示器最大的宽度,并且上面是根据动画的0.5作为最大的宽度,也就是移动到一半的时候,指示器应该达到最大宽度。因此指示器最大的宽度是需要✖️2的。请看下面代码:

  • 如上,指示器的宽度我们根据controller切换时的index和动画值进行转化,实现宽度的变化。而offset的最小值和最大值分别是切换前后两个tab的中心点,这里应该做下相应的的限制,然后传给rect.fromltwh。

【由于时间和精力问题,我并没有去做这一步的实现,而且酷狗那边动画跟滑动逻辑的关系需要ui给出具体的公式,才能百分百还原。】

最后就是加多一个参数,让业务方传入指示器的最小宽度。

业务使用

在上面我们已经把简单的动画效果改完了,接下来就是传入圆角的indicator、最小宽度indicatorminwidth,就可以正常使用啦。

  • 圆角的指示器,我直接上源码
  • 调用非常简单,跟原来官方代码一模一样。

写在最后

模仿酷狗的tabbar效果,就分享到这里啦,重点在于实现步骤的第2、3步,涉及到一些简单的数学知识。说说心得吧,flutter ui层面的问题,其实技术栈已经很单一了。只要跟着官方的实现思路,能写出跟其类似的代码,把rander层理解透彻,笔者认为已经足够了。往深了还是得往原生、混编、解决flutter痛点问题为主。 希望一起共勉!!!

实现源码

https://github.com/wxqkb/kugoutabbar.git

到此这篇关于如何利用flutter实现酷狗流畅tabbar效果的文章就介绍到这了,更多相关flutter实现酷狗tabbar效果内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!