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

效果

简介

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

全部效果为代码绘制(爱心图标来自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 {

GlobalKey _key = GlobalKey();

// 内部转换坐标点

Offset _p(Offset p) {

RenderBox getBox = _key.currentContext.findRenderObject();

return getBox.globalToLocal(p);

}

List icons = [];

bool canAddFavorite = false;

bool justAddFavorite = false;

Timer timer;

@override

Widget build(BuildContext context) {

var iconStack = Stack(

children: icons

.map(

(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.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 _TikTokFavoriteAnimationIconState

extends State with TickerProviderStateMixin {

AnimationController _animationController;

@override

void dispose() {

_animationController?.dispose();

super.dispose();

}

@override

void didChangeDependencies() {

print('didChangeDependencies');

super.didChangeDependencies();

}

@override

void 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;

}

@override

Widget 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,

);

}

}

结语

作者:马嘉伦

日期:2020/01/31

平台:Segmentfault独家,勿转载

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/346225.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java8 linq4j_Java 8仍然需要LINQ吗? 还是比LINQ更好?

java8 linq4j长期以来&#xff0c; LINQ是.NET软件工程生态系统中发生的最好的事情之一。 通过在Visual Studio 2008中引入lambda表达式和monad &#xff0c;它使C&#xff03;语言跃居Java之前&#xff0c;Java在当时是版本6&#xff0c;但仍在讨论泛型类型擦除的优缺点。 这项…

printf sizeof c语言,你可能对 sizeof(i++) 有点误解。。。

原标题&#xff1a;你可能对 sizeof(i) 有点误解。。。各位&#xff0c;今天还是按照惯例给大家分享一个C语言容易出现的小错误&#xff0c;这也是跟sizeof有关的&#xff0c;问题虽小&#xff0c;却可管中窥豹&#xff0c;话不多说&#xff0c;代码先行&#xff1a;# includei…

mongodb上一篇下一篇_如何使用Microsoft office word—上一篇

从这一期开始&#xff0c;将会逐一介绍Microsoft office的几个常用的软件&#xff0c;例如word ppt excel等&#xff0c;每一个软件将分为几期介绍&#xff0c;这几期介绍word。注意&#xff1a;介绍软件版本是Microsoft office365。如何插入图片首先打开word&#xff0c;点击插…

Java:使用Mockito模拟ResultSet

这篇文章展示了如何使用Mockito模拟java.sql.ResultSet 。 它可用于帮助单元测试代码对ResultSet &#xff08;例如ResultSetExtractor &#xff09;执行操作&#xff0c;而无需依赖外部数据源。 您可以通过提供列名列表和2D数据数组来创建MockResultSet 。 例如&#xff1a; …

c语言如何随机获取1kb,基于VS2010+C语言实现播放器的顺序播放、随机播放

1.[文件] music.h ~ 920B 下载(38)/** File: music.h* Time: 2014/10/11*/#ifndef __MUSIC_H__#define __MUSIC_H__typedef enum { UNPLAYED, PLAYED } BOOL; // 自定义一个bool类型typedef enum { ORDER, RANDOM } PLAY_MODEL; // 自定义一个播放类型typedef char *MUSIC_…

rmi远程代码执行漏洞_fastjson远程代码执行漏洞复现

漏洞原理fastjson提供了autotype功能&#xff0c;在请求过程中&#xff0c;我们可以在请求包中通过修改type的值&#xff0c;来反序列化为指定的类型&#xff0c;而fastjson在反序列化过程中会设置和获取类中的属性&#xff0c;如果类中存在恶意方法&#xff0c;就会导致代码执…

c语言编简单博弈小游戏,[2018年最新整理]实验二:利用α-β搜索过程的博弈树搜索算法编写一字棋游戏.doc...

[2018年最新整理]实验二&#xff1a;利用α-β搜索过程的博弈树搜索算法编写一字棋游戏实验二&#xff1a;利用α-β搜索过程的博弈树搜索算法编写一字棋游戏一、实验目的与要求(1)了解极大极小算法的原理和使用方法&#xff0c;并学会用α-β剪枝来提高算法的效率。(2)使用C语…

java中重载 参数顺序_Java方法中的参数太多,第4部分:重载

java中重载 参数顺序期望将过多的参数传递给Java方法的问题之一是&#xff0c;该方法的客户端很难确定它们是否以适当的顺序传递了适当的值。 在以前的文章中&#xff0c;我描述了如何使用自定义类型 &#xff0c; 参数对象和构建器来解决此问题。 解决此问题的另一种方法&…

c语言金箍棒答案,《西游记》阅读测试题(带答案)

《西游记》测试题(后附答案)姓名得分1.《如来佛辨识假猴王》故事中,那只假孙悟空是什么猴子变的&#xff1f;()A&#xff0e;金丝猴 B&#xff0e;石猴 C.六耳猕猴2.金角大王和银角大王原来是()的弟子。A&#xff0e;太上老君 B&#xff0e;孙悟空 C&#xff0e;观音菩萨3.蜘蛛…

五个金念什么_四个“金”字读什么?

展开全部读音为&#xff1a;jīn &#xff0c;是金字的异体字写法&#xff0c;读音和意思与金字完全相同&#xff0c;打不62616964757a686964616fe58685e5aeb931333431353265出来&#xff0c;如下图&#xff1a;金拼音&#xff1a;jīn释义&#xff1a;1.俗称金子。金属元素&am…

Istio的零停机滚动更新

本系列文章的第一部分介绍了如何在Kubernetes集群中实现真正的零停机时间更新。 我们专门解决了将流量从旧实例切换到新实例时出现的请求失败。 本文将展示如何使用Istio群集实现相同的目标。 服务网格技术&#xff08;例如Istio&#xff09;通常与容器编排结合使用。 Istio以…

聚类dbi指数_一种基于DBI-PD聚类算法的异常检测机制

一种基于DBI-PD聚类算法的异常检测机制丁姝郁【期刊名称】《电脑开发与应用》【年(卷),期】2015(000)002【摘要】分析了网络数据维数和检测准确度之间的关系&#xff0c;介绍了常用于入侵检测的聚类分析方法及其优缺点。在此基础上&#xff0c;提出一种以戴维森堡丁指数(DBI)为…

单片机红外通信c语言,基于C语言的计算机与多单片机红外无线串口通信的实现.doc...

基于C语言的计算机与多单片机红外无线串口通信的实现基于C语言的计算机与多单片机红外无线串口通信的实现黄文亮 信息学院 电子信息工程专业指导教师 刘传菊摘要&#xff1a;计算机与一台或多台单片机的通信系统中的数据通讯一般采用的是串行通信方式。串行通信可采用有线与无线…

android 设置资源,Android 资源

Android 资源Android Resources02/01/2018本文内容本文介绍了 Xamarin 中 Android 资源的概念&#xff0c;并介绍了如何使用这些资源。其中介绍了如何使用 Android 应用程序中的资源来支持应用程序本地化和多个设备&#xff0c;包括不同的屏幕大小和密度。This article introdu…

zbrush常用笔刷_ZBrush中常用笔刷综合简介

单击左托盘的笔刷图标&#xff0c;弹出一个笔刷库&#xff0c;其中有许多常用笔刷&#xff0c;这也是许多初学者所头疼的问题&#xff0c;ZBrush的笔刷非常多&#xff0c;而且功能很强大&#xff0c;好多朋友不知道该选择哪一个笔刷进行雕刻。其实&#xff0c;在ZBrush的学习中…

spring java配置_Spring:使基于Java的配置更加优雅

spring java配置大家好&#xff0c;我很久没有写新文章了。 积累了很多资料&#xff0c;需要在不久的将来在我的博客中发布。 但是现在我想谈谈Spring MVC应用程序配置。 确切地说&#xff0c;我想谈谈基于Java的Spring配置。 尽管在3.0版本中引入了基于Spring java的配置&…

android封装oauth2,Android AccountAuthenticator和OAuth2

这肯定是可行的。来自Android AccountManager文档&#xff1a;Many servers support some notion of an authentication token, which canbe used to authenticate a request to the server without sending theusers actual password. (Auth tokens are normally created with…

php redis 队列抢红包_php+redis实现消息队列

消息队列&#xff1a;是在消息的传输过程中保存消息的容器。消息队列管理器在将消息从它的源中继到它的目标时充当中间人。队列的主要目的是提供路由并保证消息的传递&#xff1b;如果发送消息时接收者不可用&#xff0c;消息队列会保留消息&#xff0c;直到可以成功地传递它应…

使用Spring Security在Spring Boot中进行缓存

在这篇文章中&#xff0c;我想分享一下O&#xff06;B的一个团队的经验教训。 他们正在使用带有Spring Security的Spring Boot。 默认情况下&#xff0c;Spring Security保护的所有内容都将通过以下HTTP标头发送到浏览器&#xff1a; Cache-Control: no-cache, no-store, max…

wifi定位算法android,WIFI定位算法

网络定位指通过周边wifi列表、基站列表、IP地址等信息确定用户位置的过程。 我们采集的训练数据是每个GPS坐标位置和对应的Wifi和基站列表。 其中每个Wifi和基站有唯一的Mac地址作为ID和信号强度。有三种定位方法&#xff1a;均值法首先估计一个wifi的中心点位置&#xff0c;可…