Flutter Swiper 小技巧

796 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第13天,点击查看活动详情

前言

flutter_swiper是flutter中最好用的swiper,做循环banner展示的首要选择,样式多,使用简单。下面主要分享下flutter_swiper的几个需要注意的地方/小技巧。

SwiperLayout.STACK 布局

flutter_swiper提供了几个布局供我们使用,不过部分布局相对来说不够自由。

比如STACK,固定的方向是右向左的渐出,无法修改。

image.png

那我们要左向右的渐出,怎么做呢?当然不用修改源码这么麻烦的事情,可以想一下,既然有向右的方向的布局,那水平翻转一下,是不是就是向左方向的布局了。

水平翻转的方法

Transform(
  transform: Matrix4.diagonal3Values(-1, 1, 1.0),
  alignment: Alignment.center,
  child: child,
)

翻转后

image.png

然后我们会发现,里面的Item也水平翻转了。这时候,我们可以再次对Item水平翻转,这样,Item就翻回来了。

itemBuilder: (context, index) {
  return Transform(
    transform: Matrix4.diagonal3Values(-1, 1, 1.0),
    alignment: Alignment.center,
    child: _buildItem(),
  );
}

image.png

这样左向右方向的STACK布局就完成了,其他类似的问题也可以用这种翻转再翻转的方式解决。

多余的间距如何去除

有些布局会因为动画或者什么的原因,带有一些空白间距。再拿STACK举例,转换成左向右之后,可以看到左边有明显的一大块空白

image.png

这种比较麻烦,因为可能设计就是如此。在不改源码的情况下,可以尝试暴力解决

Stack(
    alignment: Alignment.centerLeft,
    children: [
      Positioned(
        left: -45,
        right: 0,
        child: Swiper

Stack 默认使超出可视部分不显示,所以可以偏移负的距离,来抵消多余的间距。

image.png

可能需要细调一下,因为不确定具体偏移了多少。比较暴力的方式。

与Hero结合的问题

常见的一种需求是,点击可循环播放的图片列表,进入到对应放大的图片查看器(PhotoView)中,还带有对应的Hero动画。

看起来就是使用Hero将图片和PhotoView中heroTag对应上。但实际操作之后,你会发现,会经常报错:

I/flutter ( 8790): Another exception was thrown: There are multiple heroes that share the same tag within a subtree.

为什么呢?因为循环的方式,一般是前后补位的方式,即比如abc三个元素,第一个的位置的前面,插入复制的最后一个元素 (c),最后一个位置的后面,插入原来的复制的第一个元素 (a),也就是

(c) a b c (a)

当滑动到 (c) 时,无动画切换到元素c;当滑动到 (a) 时,无动画切换到a

这样就实现了循环

但这时问题就出现了,(c)和c,(a)和a,实际上返回的index下标都是最终的下标,对我们来说,他们只有两个(c和a),但内部实现的却是有四个不同元素。

也就是说,heroTag 对于(c)和c,(a)和a分别使用的是相同的tag,导致了他的报错。

解决方案

可以考虑将Hero更改到Swiper层,而不是Item层,然后进入PhotoView初始化Swiper时,初始化对应的index下标;然后在页面返回时,设置切换后的index下标

PhotoView

Hero(
  tag: 'photo',
  child: Swiper(
    index: currentIndex,
    ...
  )
)

Picture

final index = await NrNavigator.push(...);
if (index != null) {
  swiperController.move(index, animation: false);
}

这样就可以实现Swiper带Hero动画的效果了。

总结

再完善的组件也不能考虑到所有的问题,可以思考怎么结合一些方法来达到自己想要的效果,不一定要修改源码。