效果

简介

仿抖音点赞手势,单击暂停,双击点赞,可连续点击添加多个爱心,特点如下

全部效果为代码绘制(爱心图标来自Material Icon的图标)
套上在目标Widget外即可使用
提供单击与点赞的回调
建议复制代码使用,动画可按需修改
没有flutter之外的依赖项,可复制使用(懒得发pub)

基本原理

一个罩在child上的stack层,双击后根据坐标添加目标爱心Widget,爱心Widget在出现时会播放动画,用坐标作为key,动画结束后移除已经消失的爱心。

全部代码

什么都不依赖,可以直接复制使用。

import 'dart:async';
import 'dart:math';import 'package:flutter/material.dart';/// 视频手势封装
/// 单击:暂停
/// 双击:点赞,双击后再次单击也是增加点赞爱心
class TikTokVideoGesture extends StatefulWidget {const TikTokVideoGesture({Key key,@required this.child,this.onAddFavorite,this.onSingleTap,}) : super(key: key);final Function onAddFavorite;final Function onSingleTap;final Widget child;@override_TikTokVideoGestureState createState() => _TikTokVideoGestureState();
}class _TikTokVideoGestureState extends State<TikTokVideoGesture> {GlobalKey _key = GlobalKey();// 内部转换坐标点Offset _p(Offset p) {RenderBox getBox = _key.currentContext.findRenderObject();return getBox.globalToLocal(p);}List<Offset> icons = [];bool canAddFavorite = false;bool justAddFavorite = false;Timer timer;@overrideWidget build(BuildContext context) {var iconStack = Stack(children: icons.map<Widget>((p) => TikTokFavoriteAnimationIcon(key: Key(p.toString()),position: p,onAnimationComplete: () {icons.remove(p);},),).toList(),);return GestureDetector(key: _key,onTapDown: (detail) {setState(() {if (canAddFavorite) {print('添加爱心,当前爱心数量:${icons.length}');icons.add(_p(detail.globalPosition));widget.onAddFavorite?.call();justAddFavorite = true;} else {justAddFavorite = false;}});},onTapUp: (detail) {timer?.cancel();var delay = canAddFavorite ? 1200 : 600;timer = Timer(Duration(milliseconds: delay), () {canAddFavorite = false;timer = null;if (!justAddFavorite) {widget.onSingleTap?.call();}});canAddFavorite = true;},onTapCancel: () {print('onTapCancel');},child: Stack(children: <Widget>[widget.child,iconStack,],),);}
}class TikTokFavoriteAnimationIcon extends StatefulWidget {final Offset position;final double size;final Function onAnimationComplete;const TikTokFavoriteAnimationIcon({Key key,this.onAnimationComplete,this.position,this.size: 100,}) : super(key: key);@override_TikTokFavoriteAnimationIconState createState() =>_TikTokFavoriteAnimationIconState();
}class _TikTokFavoriteAnimationIconStateextends State<TikTokFavoriteAnimationIcon> with TickerProviderStateMixin {AnimationController _animationController;@overridevoid dispose() {_animationController?.dispose();super.dispose();}@overridevoid didChangeDependencies() {print('didChangeDependencies');super.didChangeDependencies();}@overridevoid initState() {_animationController = AnimationController(lowerBound: 0,upperBound: 1,duration: Duration(milliseconds: 1600),vsync: this,);_animationController.addListener(() {setState(() {});});startAnimation();super.initState();}startAnimation() async {await _animationController.forward();widget.onAnimationComplete?.call();}double rotate = pi / 10.0 * (2 * Random().nextDouble() - 1);double get value => _animationController?.value;double appearDuration = 0.1;double dismissDuration = 0.8;double get opa {if (value < appearDuration) {return 0.99 / appearDuration * value;}if (value < dismissDuration) {return 0.99;}var res = 0.99 - (value - dismissDuration) / (1 - dismissDuration);return res < 0 ? 0 : res;}double get scale {if (value < appearDuration) {return 1 + appearDuration - value;}if (value < dismissDuration) {return 1;}return (value - dismissDuration) / (1 - dismissDuration) + 1;}@overrideWidget build(BuildContext context) {Widget content = Icon(Icons.favorite,size: widget.size,color: Colors.redAccent,);content = ShaderMask(child: content,blendMode: BlendMode.srcATop,shaderCallback: (Rect bounds) => RadialGradient(center: Alignment.topLeft.add(Alignment(0.66, 0.66)),colors: [Color(0xffEF6F6F),Color(0xffF03E3E),],).createShader(bounds),);Widget body = Transform.rotate(angle: rotate,child: Opacity(opacity: opa,child: Transform.scale(alignment: Alignment.bottomCenter,scale: scale,child: content,),),);return widget.position == null? Container(): Positioned(left: widget.position.dx - widget.size / 2,top: widget.position.dy - widget.size / 2,child: body,);}
}

原文作者:马嘉伦
原文链接:人类身份验证 - SegmentFault
来源:Segmentfault

Flutter组件:仿抖音双击点赞弹出爱心效果相关推荐

  1. 多图弹出最后变成心形html,【Flutter组件】仿抖音双击点赞弹出爱心效果(可连点)...

    效果 简介 仿抖音点赞手势,单击暂停,双击点赞,可连续点击添加多个爱心,特点如下 全部效果为代码绘制(爱心图标来自Material Icon的图标) 套上在目标Widget外即可使用 提供单击与点赞的 ...

  2. pythoni屏幕连点_【Flutter组件】仿抖音双击点赞弹出爱心效果(可连点)

    效果 简介 仿抖音点赞手势,单击暂停,双击点赞,可连续点击添加多个爱心,特点如下 全部效果为代码绘制(爱心图标来自Material Icon的图标) 套上在目标Widget外即可使用 提供单击与点赞的 ...

  3. 【Flutter组件】仿抖音双击点赞弹出爱心效果(可连点)

    效果 简介 仿抖音点赞手势,单击暂停,双击点赞,可连续点击添加多个爱心,特点如下 全部效果为代码绘制(爱心图标来自Material Icon的图标) 套上在目标Widget外即可使用 提供单击与点赞的 ...

  4. android+底部评论框,Android 之BottomsheetDialogFragment仿抖音评论底部弹出对话框效果(实例代码)...

    实现的效果图: 自定义Fragment继承BottomSheetDialogFragment 重写它的三个方法: onCreateDialog() onCreateView() onStart() 他 ...

  5. 仿抖音短视频源码,高仿抖音双击点赞效果之双击的问题

    仿抖音短视频源码中,实现仿抖音的双击点赞效果,相关代码如下: public class MyView extends View {private GestureDetector gestureDete ...

  6. 仿抖音评论底部弹出框(列表框+发表框)

    BottomSheetDialogFragment高仿抖音评论底部弹出框 先看效果图: 这个弹窗的效果是使用BottomSheetDialogFragment做的,第一个弹出的对话框为CommentL ...

  7. Android仿抖音双击点赞动画,Android仿抖音点击效果

    原标题:Android仿抖音点击效果 作者丨wish_xy https://www.jianshu.com/p/1d17c38a3db1 学习自定义view,想找点东西耍一下,刚好看到抖音的点赞效果不 ...

  8. Android自定义view之实现仿抖音双击点赞单击暂停特效

    2018年抖音.快手.火山等短视频App比较火,最近自己做短视频项目时有个需求,就是类似抖音的点赞特效,单击屏幕时视频暂停,再次点击时视频恢复播放,双击或者连续多次点击时出现点赞特效(飘小心心特效), ...

  9. java 特效_Android仿抖音双击点赞特效 java实现

    实现思路 首先分析该特效的实现思路和具体的表现.在抖音中短视频的播放界面,无论双击屏幕的无其他控件的位置都能够触发双击点赞的特效,因此这是一个自定义布局实现.其次,在双击完后会有一个心形产生并飘动,所 ...

最新文章

  1. Django---应用如何创建
  2. nginx 配置文件
  3. HPC China2016全国高性能计算学术年会即将举行
  4. opengl游戏引擎源码_UE4渲染引擎模块简介(1)
  5. proxy error: could not proxy request解决方案
  6. LeetCode 1822. 数组元素积的符号
  7. bulk of the 用法_代词的用法详解:第三部分(不定代词)
  8. 【AI视野·今日NLP 自然语言处理论文速览 第七期】Tue, 15 Jun 2021
  9. “拼多多”的假面人生
  10. .net MVC全局定时器执行作业
  11. 利用FME进行火星、百度坐标反算及误差分析
  12. ceph rbd mysql_ceph-rbd使用
  13. 死链提交为什么不能提交 html文件,如何正确使用死链提交工具
  14. 19年 GSoC 中 Jenkins 的七个项目
  15. 香八拉 北京 香山 八大处 防火通道
  16. 主成分分析(principal component analysis, PCA)公式
  17. 基于php新闻发布平台 毕业设计-附源码141646
  18. 计算机计算公式在哪,计算机的计算器在哪 自己的电脑上的计算器在哪里找
  19. MK趋势检验和MK突变检验(代码分享及结果分析)
  20. 把insert和update写成一个复合语句

热门文章

  1. 微信开发之发送消息接口
  2. [JavaEE - JPA] 6. ORM的核心注解 - 基础类型以及嵌套类型
  3. 磁盘管理---RAID磁盘阵列(重点容错能力)软RAID的实现
  4. commai.ai.openpolit学习笔记
  5. Coinbase今日上市,加密市场提前暴涨,行情接下来怎么走?
  6. Buuctf [DDCTF2018]流量分析
  7. Two Scoops Django 推荐的数据模型最佳实践
  8. 01 | 使用Gradle构建多模块项目
  9. 小程序+企业微信活码群做裂变营销的4个步骤
  10. ST 电机控制工作台帮助文档翻译 之 支持的类别参数(单电机(控制级))