使用Flutter仿写TikTok的手势交互

作者 : 开心源码 本文共4494个字,预计阅读时间需要12分钟 发布时间: 2022-05-12 共287人阅读

写在前面

Flutter 是 Google推出并开源的移动应用开发框架,主打跨平台、高保真、高性能。开发者可以通过 Dart语言开发 App,一套代码同时运行在 iOS 和 Android平台。

Flutter官网:https://flutter-io.cn

抖音,英文名TikTok,一款火遍全球的短视频App。在玩抖音的日子里,最令我感到舒服的就是抖音的手势交互,加上近期都在进行Flutter方面的学习,因而就产生了使用Flutter来仿写TikTok手势交互的想法。

来看看实现的效果:

Github地址: ditclear/tiktok_gestures

GestureDetector以及Transform

既然是手势交互,那么就必然要检测手势,在Flutter中提供了GestureDetector来帮助开发者,并提供了多个回

调来解决手势。

Property/CallbackDescription
onTapDown客户每次和屏幕交互时都会被调用
onTapUp客户中止触摸屏幕时触发
onTap短暂触摸屏幕时触发
onTapCancel客户触摸了屏幕,但是没有完成Tap的动作时触发
onDoubleTap客户在短时间内触摸了屏幕两次
onLongPress客户触摸屏幕时间超过500ms时触发
onVerticalDragDown当一个触摸点开始跟屏幕交互,同时在垂直方向上移动时触发
onVerticalDragStart当触摸点开始在垂直方向上移动时触发
onVerticalDragUpdate屏幕上的触摸点位置每次改变时,都会触发这个回调
onVerticalDragEnd当客户中止移动,这个拖拽操作就被认为是完成了,就会触发这个回调
onVerticalDragCancel客户忽然中止拖拽时触发
onHorizontalDragDown当一个触摸点开始跟屏幕交互,同时在水平方向上移动时触发
onHorizontalDragStart当触摸点开始在水平方向上移动时触发
onHorizontalDragUpdate屏幕上的触摸点位置每次改变时,都会触发这个回调
onHorizontalDragEnd水平拖拽结束时触发
onHorizontalDragCancelonHorizontalDragDown没有成功完成时触发
onPanDown当触摸点开始跟屏幕交互时触发
onPanStart当触摸点开始移动时触发
onPanUpdate屏幕上的触摸点位置每次改变时,都会触发这个回调
onPanEndpan操作完成时触发
onScaleStart触摸点开始跟屏幕交互时触发,同时会建立一个焦点为1.0
onScaleUpdate跟屏幕交互时触发,同时会标示一个新的焦点
onScaleEnd触摸点不再跟屏幕有任何交互,同时也表示这个scale手势完成

GestureDetector并不会监听上面所有的手势,只有传入的callbacks非空时,才会监听。所以,假如你想要禁用某个手势时,可以给对应的callback传null。

本文主要关注的的是拖动相关的,比方onPanXXonHorizontalDragXXonVerticalDragXX等等回调事件。

Transform可以在其子Widget绘制时对其应用一个矩阵变换(transformation),Matrix4是一个4D矩阵,通过它我们可以实现各种矩阵操作。

Container(  color: Colors.black,  child: new Transform(    alignment: Alignment.topRight, //相对于坐标系原点的对齐方式    transform: new Matrix4.skewY(0.3), //沿Y轴倾斜0.3弧度    child: new Container(      padding: const EdgeInsets.all(8.0),      color: Colors.deepOrange,      child: const Text('Apartment for rent!'),    ),  ),);

效果如下:

在Flutter中提供了少量封装好的transform效果供开发者选择,比方:平移(translate)、旋转(rotate)、缩放(scale)。

在理解了这两点之后,我们来逐渐分解前文的效果。

交互分解

首先,需要明确的是这些交互效果其实都是通过检测手指的滑动,得到一个x坐标或者者y坐标的偏移量,而后配合Transform进行各种不同的变换,明白了这一点,想做到这样的效果并不难。

  • 首页的交互

这里的交互都是横向的滑动,因而这里主要解决onHorizontalDragXX相关的事件。

而后来看看首页的布局:

Left:拍摄页 Middle:主页 Right:客户页

外层是一个GestureDetector用于解决整个页面的手势,里面用的是一个Stack,相似于Android中的FrameLayout,它包含3个Transform的子Widget。

这里选取拍摄页(left)来具体谈谈.

通过观察可以发现,随着偏移量的改变,这里其实包含两个变化:1.缩放 2. 前景色透明度。

缩放可以直接采用前文提到的Transform.scale,前景色可以用foregroundDecoration通过改变Color的透明度来达到效果,看看实现:

/// 左侧Widget////// 通过 [Transform.scale] 进行根据 [offsetX] 缩放/// 最小 0.88 最大为 1Transform buildLeftPage(double screenWidth) {  return Transform.scale(    scale: 0.88 + 0.12 * offsetX / screenWidth < 0.88 ? 0.88 : 0.88 + 0.12 * offsetX / screenWidth,    child: Container(      child: Image.asset(        "assets/left.png",        fit: BoxFit.fill,      ),      foregroundDecoration: BoxDecoration(          color: Color.fromRGBO(0, 0, 0, 1 - (offsetX / screenWidth)),         ),    ),  );}

当我们的手指在横向移动的时候,记录下偏移总量offsetX,而后通过setState进行升级。

onHorizontalDragUpdate: (details) {  // 控制 offsetX 的值在 -screenWidth 到 screenWidth 之间  if (offsetX + details.delta.dx >= screenWidth) {    setState(() {      offsetX = screenWidth;    });  } else if (offsetX + details.delta.dx <= -screenWidth) {    setState(() {      offsetX = -screenWidth;    });  } else {    setState(() {      offsetX += details.delta.dx;    });  }}

通过setState升级偏移量offsetX之后,Flutter便会重新渲染视图,从而达到上图的效果。

  • Hero动画

Flutter提供了Hero动画来实现这样的过渡效果。Hero指的是可以在路由(页面)之间“飞行”的widget,简单来说Hero动画就是在路由切换时,有一个共享的Widget可以在新旧路由间切换,因为共享的Widget在新旧路由页面上的位置、外观可能有所差异,所以在路由切换时会逐步过渡,这样就会产生一个Hero动画。

/// tiktok_page.dartWidget build(BuildContext context) {        return  Hero(              tag: "detail",              //child            ) )  /// detail_page.dart Widget build(BuildContext context) {    return Hero(      tag: "detail",      // child        )  }

保证tag一致即可以了。

  • 介绍页的交互

跟首页一样的思路,只是这里的手势是垂直方向。

布局同样是GestureDetector加上Stack再配合Transform.translate

Hero(      tag: "detail",      child: GestureDetector(        onVerticalDragUpdate: (details){          // dy 不超过 -screenHeight * 0.6          dy += details.delta.dy;          if ((dy < 0 && dy.abs() > screenHeight * 0.6)) {            dy = -screenHeight * 0.6;          } else {            setState(() {});          }        },        child: Stack(          children: <Widget>[            Image.asset(              "assets/detail.png",              fit: BoxFit.fitWidth,              width: screenWidth,              height: screenHeight,            ),            Transform.translate(              offset: Offset(0, dy + screenHeight),              child: Container(                  height: screenHeight * 0.6,                  child: GestureDetector(                    onTap: () {},                    child: Image.asset(                        "assets/comment.png",),                  )              ),            ),          ],        ),      ),    );

在手指离开屏幕时,根据偏移利用动画进行调整。

onVerticalDragEnd: (_){          // 滑动截止时,根据 dy 判断是开展还是回缩          if (dy < 0) {            if (!isCommentShow && dy.abs() > screenHeight * 0.2) {              if (dy.abs() > screenHeight * 0.2) {                animateToTop(screenHeight);              } else {                animateToBottom(screenHeight);              }            } else {              if (dy.abs() > screenHeight * 0.4) {                animateToTop(screenHeight);              } else {                animateToBottom(screenHeight);              }            }          }        },

写在最后

总的来说,这些交互都是依靠着对手势的检测做到的,相比于Android,Flutter有着一切都是Widget的概念,

GestureDetector以及Hero都是Widget而且提供了很多回调函数,再配合数据驱动UI和Flutter优秀的渲染机制,减轻了开发者进行手势交互的难度。

Github地址: ditclear/tiktok_gestures

假如本文对你有帮助,请点赞支持。

更多Flutter资料分享欢迎Android工程师朋友们加入安卓开发技术进阶互助:856328774免费提供安卓开发架构的资料(包括Fultter、高级UI、性能优化、架构师课程、 NDK、Kotlin、混合式开发(ReactNative+Weex)和一线互联网公司关于Android面试的题目汇总。

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » 使用Flutter仿写TikTok的手势交互

发表回复