9

FlutterComponent最佳实践之TabbarIndicator

 2 years ago
source link: https://blog.csdn.net/eclipsexys/article/details/123564543
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

FlutterComponent最佳实践之TabbarIndicator

ba6842730aa76a5deb040a754b7ac1bb.png

点击上方蓝字关注我,知识会给你力量

49203fa50a7019d99f3c3d740bb09c4a.png

TabBar是UI中非常常用的一个组件,Flutter提供的TabBar几乎可以满足我们大部分的业务需求,而且实现非常简单,我们可以仅用几行代码,就完成一个Tab滑动效果。

关于TabBar的基本使用,我这里就不讲解了,不熟悉的朋友可以去Dojo里面好好体验一下。

下面我们针对TabBar在平时的开发中遇到的一些问题,来看下如何解决。

首先,我们来看下TabBar的抖动问题,这个问题发生在我们设置labelStyle和unselectedLabelStyle的字体大小不一致时,这个需求其实也很常见,当我们选中一个Tab时,当然希望选中的标题能够放大,突出一些,但是Flutter的TabBar居然会在滑动过程中抖动,开始以为是Debug包的问题,后来发现Release也一样。

Flutter的Issue中,其实已经有这样的问题了,地址如下:

https://github.com/flutter/flutter/issues/24505

不过到目前为止,这个问题也没修复,可能在老外的设计中,重来没有这种设计吧。不过Issue中也提到了很多方案来修复这个问题,其中比较好的一个方案,就是通过修改源码来实现,在TabBar源码的_TabStyle的build函数中,将实现改为下面的方案。

newCodeMoreWhite.png

这个方案的确可以修复这个问题,不过却需要修改源码,所以,有一些使用成本,那么有没有其它方案呢,其实,Issue中已经给出了问题的来源,实际上就是Text在计算Scala的过程中,由于Baseline不对齐导致的抖动,所以,我们可以换一种思路,将labelStyle和unselectedLabelStyle的字体大小设置成一样的,这样就不会抖动啦。(MDZZ)

当然,这样的话需求就被我们做没了。。。

其实,我们是将Scala的效果,放到外面来实现,在TabBar的tabs中,我们将滑动百分比传入,借助隐式动画来实现Scala效果,这不就避免了抖动问题吗?

是不是柳暗花明又一村,很简单就解决了这个问题。

indicator

indicator是TabBar中另一个磨人的小妖精,由于indicator的存在,TabBar成了设计师自由发挥的重灾区,可以效果信手拈来,虽然Flutter提供了很完善的接口来给开发者创建indicator,但是也架不住一些设计师的奇思妙想。

下面我们来看下几种比较常见的indicator实现方案。

indicator是一个Decoration,Flutter中关于Decoration的继承关系如下所示。

87806f9aeedd3eafa7afe600b69e17af.png Ftab-bar-view-06-20220301160241981

Shape indicator

UnderlineTabIndicator是Tab的默认实现,我们可以修改为ShapeDecoration,这样就可以实现一个简单的方框indicator。

实现效果如下。

96d6ce9fb66d33881df0864bdb855466.png image-20220301160841929

这样我们可以实现很多Shape风格的Indicator,借助ShapeDecoration,可以实现纯色、渐变等多种颜色的风格。

indicatorWeight & indicatorPadding

这两个参数用于控制indicator的尺寸,代码如下所示。

如果你想要indicator在垂直距离上更接近,那么可以使用indicatorPadding参数,如果你想让indicator更细,那么可以使用indicatorWeight参数。

自定义Indicator

永远逃不掉自定义。

先把系统默认实现的UnderlineTabIndicator Copy过来,这是我们自定义的模板。

看完源码你就懂了,最后的BoxPainter,就是我们绘制Indicator的核心,在这里根据Offset和ImageConfiguration,就可以拿到当前Indicator的参数,就可以进行绘制了。

例如我们最简单的,把Indicator绘制成一个圆,实际上只需要修改最后的draw函数,代码如下所示。

newCodeMoreWhite.png

效果如图所示。

79d1cc6a0d9ca47a04c4e2f97138a041.png image-20220301170202632

再来一个:

newCodeMoreWhite.png

效果如图所示。

ddae90cc4031d32253b774c8032e8f57.png image-20220301170842559

有内味儿了。所以说你发现没,东西都给你了,怎么画,就看你自己的功底了。

不过要注意的是,这一类的indicator,都是基于UnderlineTabIndicator的实现来做的,所以它的样式也有一些限制,例如:必须会实现在Tab下的滑动效果,而且滑动时,无法修改尺寸。

固定的indicator & 滑动系数监听

那么如果我需要去掉indicator的滑动效果呢?有两个办法,一个是修改TabBar的源码,另一个是将固定的indicator放入tabs中实现,而不是indicator。

这两个方法各有利弊,修改源码是釜底抽薪,可以实现一切效果,同样的,成本高,另一方法简单,但是需要拿到滑动系数。

下面我们就通过使用第二种方式来看下怎么实现,同时,也完成下前面介绍的抖动问题的最后实现(它也需要拿到滑动系数)。

首先,我们需要知道从哪获得滑动系数,这个东西,我们可以通过_tabController来获取,这里面包含了TabBar滑动的一切参数,例如:

  • _tabController.animation!.value:滑动变化区间值

  • _tabController.offset:滑动方向

  • _tabController.previousIndex:滑动前的Index

  • _tabController.index:滑动到的Index

  • _tabController.indexIsChanging:是滑动还是点击Tab产生的滑动

这些东西,就是我们的原始数据,通过它们,我们就可以得到当前滑动的滑动系数。

newCodeMoreWhite.png

首先,我们通过offset来判断滑动的方向,再通过indexIsChanging来判断当前是点击还是滑动,最后根据animation来获取当前的滑动系数。

有了滑动系数,我们就可以很方便的对Tab中的标题做Scala动画,同时对固定的indicator做动画了。

newCodeMoreWhite.png

图就不放了,下面还有。

Material效果的indicator

应群友的呼声,增加了Material效果的indicator,很奇怪的是,官方居然没有支持这种Material风格,带伸缩的indicator,Native上都支持了。

原始的Indicator在滑动时,是固定尺寸的,在Tabbar源码中,我们找到_IndicatorPainter,这个CustomPainter负责了对Indicator的绘制,所以,我们要想获得类似Material组件弹性伸缩的效果,那就必须修改绘制时的宽度,显然,我们来到了paint函数,在这里,发现两个rect——fromRect和toRect,它们执行的lerp操作,就成了我们想要的Indicator动画效果。

所以,思路自然就出来了,我们只需要根据当前滑动的进度,修改当前Rect的宽度即可。

那么下面还有一个问题,就是Material风格的伸缩动画,是如何实现的呢?

我们打开CircularProgressIndicator的源码,看下它的动画是怎么实现的就知道了。

显而易见,这个动画被分为了两部分,0-0.5时,以缩放系数增加,0.5-1时,按照缩放系数递减。

所以,首先,我们给indicatorRect增加一个参数scale,用来传入当前两个Tab间的滑动比例。

注释掉的行,就是源码中的代码,第一个if判断,实际上是偷懒,因为默认FixedTabBarIndicatorSize是tab,所以这里不会走,我们放开判断,第二个改动,就是修改rect的left和width,left是为了让rect居中,width是为了修改宽度做动画,代码很简单。

接下来,就是需要拿到scale了,源代码中其实已经写了一半了。

同样,注释掉的行是源码,我们增加一个scale,它实际上就是index和value的绝对值,为啥是绝对值呢,因为方向咯。

所以,就这几行代码,我们就修改了这个Material功能,不过,这里只是最基本的修改,如果要形成一个完整的lib,那么需要将这些参数抽出去,作为配置选项,我就不做了,因为懒。

fadc9673138b44a53c48f1c03cfcf4ef.gif material_tab

图中还顺带演示了前一个固定的indicator的实现效果。

向大家推荐下我的网站 https://xuyisheng.top/  点击原文一键直达

专注 Android-Kotlin-Flutter 欢迎大家访问

本文原创公众号:群英传,授权转载请联系微信(Tomcat_xu),授权后,请在原创发表24小时后转载。

< END >

作者:徐宜生

更文不易,点个“三连”支持一下👇


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK