Code前端首页关于Code前端联系我们

Flutter仿抖音TikTok手势交互(一)

terry 2年前 (2023-09-23) 阅读数 62 #移动小程序

Flutter是Google推出并开源的移动应用开发框架,专注于跨平台、高可靠性和高性能。开发者可以通过Dart语言开发应用程序,一组代码同时运行在iOS和Android平台上。

抖音,英文名为TikTok,是一款风靡全球的短视频应用程序。在玩抖音的日子里,最让我舒服的就是抖音的手势交互。另外最近研究了Flutter,所以就产生了用Flutter来模仿TikTok手势交互的想法。

我们来看看效果:Flutter仿写抖音TikTok手势交互(一)

Gif:giphy.com/gifs/Y0nMQw…

Github地址:github.com/ditclear/ti…

下载

demo GestureDetector And Transform

自从它是手势交互,需要检测手势。 Flutter 提供了 GestureDetector 来帮助开发者,并提供了多个回调来处理手势。

属性/回调描述
onTapDown每次用户与屏幕交互时调用onTap短暂触摸屏幕
onTapCancel时触发当用户触摸时触发
onDoubleTap 用户在短时间内 ❀ onLongPress当用户触摸屏幕超过 500ms 时触发
onVerticalDragDown当一个接触点开始与屏幕交互并垂直方向移动时触发此回调
onVerticalDragEnd当用户停止时认为完成,此回调被触发
onVerticalDragCancel 当用户突然停止拖动时触发
opHorizo​​ntalDragDown并移动触摸屏与触摸方向交互
onHorizo​​ntalDragStart当触摸点开始水平方向移动时触发
onHorizo​​ntalDragUpdate每次触摸点位置在屏幕上发生变化时触发,该回调被触发En Horizo​​ntal 水平拖动结束时触发
onHorizo​​ntalDragCancel onHorizo​​ntalDragDown 在未成功结束时触发
onPanDown onPanStart当触摸点开始移动时触发
onPanUpdate每次触摸点位置在屏幕上发生变化时触发。当平移操作完成时,会触发此回调
onPanEnd。当触摸点开始与屏幕交互并在 1.0 处建立焦点时,会触发
onScaleStart
onScaleUpdate 当触摸点与屏幕交互时触发。同时标记一个新焦点
onScaleEnd触摸点将不再跟随屏幕屏幕上出现了所有的交互,也意味着缩放手势已经准备好了。

手势检测器不会侦听上述所有手势。它仅侦听传入回调不为空的情况。所以,如果你想禁用某个手势,可以传入 null 给对应​​的回调。 这篇文章主要关注画线,比如 Onpanxx, ❙OnHorizo​​ntaldragxx,, , Onverticaldragxx等等。

Transform可以在绘制时对其子控件应用矩阵变换(变换)。 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仿写抖音TikTok手势交互(一)

Flutter 提供了多种加密变换效果供开发者选择,例如:平移、旋转、缩放。

明白了这两点之后,我们来一点一点分解之前的效果。

交互分解

首先必须明确,这些交互效果实际上是通过捕获手指的滑动,得到x坐标或者y坐标的偏移量,然后使用Transform进行各种变换来获得的。明白了此时实现这样的效果并不困难。

  • 首页互动

Flutter仿写抖音TikTok手势交互(一)

Gif:user-gold-cdn.xitu.io/2019/4/20/1…

这里的互动都是水平滑动,所以这里主要处理❀ onHorizo​​ntalDragXX 相关事件。

然后我们看一下主页的布局: Flutter仿写抖音TikTok手势交互(一)

左:拍摄页面 中:主页右:用户页面

外层是手势整个页面上的Gesture Detector,里面用的它是一个stack,类似于Android中的FrameLayout。它包含 3 个Transform 子小部件。 Flutter仿写抖音TikTok手势交互(一)

这里我们选择拍摄面(左)来详细说一下。

通过观察可以看到,随着偏移的变化,这里其实有两个变化:1.缩放2.前景色透明度

缩放可以直接使用上面的Transform.scale,前景色可以使用ForegroundDecoration通过改变颜色来改变效果。看一下实现:

/// 左侧Widget
///
/// 通过 [Transform.scale] 进行根据 [offsetX] 缩放
/// 最小 0.88 最大为 1
Transform 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会重绘视图,达到上面的效果。

  • 英雄动画

Flutter仿写抖音TikTok手势交互(一)

Gif:user-gold-cdn.xitu.io/2019/4/20/1…

Flutter提供了英雄动画来实现这样的过渡效果。 Hero指的是可以在轨道(页面)之间“飞行”的小部件。简单来说,英雄动画就是当路线改变时,有一个共享的widget可以在新旧路线之间进行切换。由于共享widget在新旧路由页面上,位置和外观可能不同,所以在路由切换时会有一个逐渐的过渡,从而产生英雄动画。

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

确保标签一致。

  • 详情页互动

Flutter仿写抖音TikTok手势交互(一)

Gif:user-gold-cdn.xitu.io/2019/4/20/1…

和首页的思路一样,只不过这里的手势是垂直的。

的布局也是GestureDetector加上Stack然后加上变换。

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的理念,

Gesture DetectorHero都是widget,并提供了很多回调函数。再加上数据驱动的UI和Flutter优秀的渲染机制,降低了开发者的石头交互难度。

Github地址:github.com/ditclear/ti…

作者:ditclear
链接:https://juejin.im/post/5cbadb71f265da037c7c7ce19fets:版权归作者所有。如需商业转载,请联系求作者授权。非商业转载请来源。

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门