本文主要是使用Flutter封装一个双击屏幕显示点赞爱心UI效果,并实现了爱心Icon 透明度、缩放、旋转、渐变等动画效果。
实现效果:
实现逻辑:
1、封装FavoriteGesture(爱心手势)实现双击屏幕显示爱心Icon;
2、封装FavoriteAnimationIcon(爱心Icon)实现双击屏幕显示爱心Icon,快速双击时同时显示多个爱心Icon;
3、给FavoriteAnimationIcon增加透明度淡入淡出动画效果;
4、给FavoriteAnimationIcon增加缩放动画效果;
5、给FavoriteAnimationIcon增加旋转动画效果;
7、给FavoriteAnimationIcon增加渐变动画效果;
一、封装FavoriteGesture爱心手势
1)Stack实现多界面堆叠
实现爱心Icon显示在视频界面上层,视频界面由上层child传入,使用Stack实现多界面堆叠;
class FavoriteGesture extends StatefulWidget {
static const double defaultSize = 100;
final Widget child;
final double size;
const FavoriteGesture({super.key, this.size = defaultSize, required this.child});
@override
State<FavoriteGesture> createState() => _FavoriteGestureState();
}
class _FavoriteGestureState extends State<FavoriteGesture> {
@override
Widget build(BuildContext context) {
return Stack(
children: [
widget.child,
Icon(Icons.favorite, size: widget.size, color: Colors.redAccent)
],
);
}
}
2)GestureDetector监听双击事件
使用GestureDetector监听屏幕双击事件和点击的坐标,使用Positioned将Icon显示到点击坐标的位置;当用户双击屏幕时,显示爱心Icon,延迟600毫秒,爱心Icon消失。
class FavoriteGesture extends StatefulWidget {
static const double defaultSize = 100;
final Widget child;
final double size;
const FavoriteGesture({super.key, this.size = defaultSize, required this.child});
@override
State<FavoriteGesture> createState() => _FavoriteGestureState();
}
class _FavoriteGestureState extends State<FavoriteGesture> {
final GlobalKey _key = GlobalKey();
bool inFavorite = false;
// temp表示最近的一次双击坐标
Offset temp = Offset.zero;
@override
Widget build(BuildContext context) {
return GestureDetector(
key: _key,
onDoubleTapDown: (details) {
temp = details.globalPosition;
},
onDoubleTap: () {
setState(() {
inFavorite = true;
});
Future.delayed(const Duration(milliseconds: 600), () {
setState(() {
inFavorite = false;
});
});
},
child: Stack(
children: [
widget.child,
if (inFavorite)
Positioned(
top: temp.dy - widget.size / 2,
left: temp.dx - widget.size / 2,
child: Icon(Icons.favorite, size: widget.size, color: Colors.redAccent)),
],
));
}
}
3)RenderBox 实现屏幕坐标转换本地坐标
onDoubleTapDown: (details) {temp = details.globalPosition;} 获取到的点击坐标是屏幕的坐标,需要转换成Icon的父布局Stack的坐标,通过RenderBox 来实现屏幕坐标转换本地坐标。
class FavoriteGesture extends StatefulWidget {
static const double defaultSize = 100;
final Widget child;
final double size;
const FavoriteGesture({super.key, this.size = defaultSize, required this.child});
@override
State<FavoriteGesture> createState() => _FavoriteGestureState();
}
class _FavoriteGestureState extends State<FavoriteGesture> {
final GlobalKey _key = GlobalKey();
bool inFavorite = false;
// temp表示最近的一次双击坐标
Offset temp = Offset.zero;
Offset _globalToLocal(Offset global) {
RenderBox renderBox = _key.currentContext?.findRenderObject() as RenderBox;
return renderBox.globalToLocal(global);
}
@override
Widget build(BuildContext context) {
return GestureDetector(
key: _key,
onDoubleTapDown: (details) {
temp = _globalToLocal(details.globalPosition);
},
on