在叠加层前面制作一个小部件
Make a widget in front of an overlay
我正在尝试在 Flutter 中重现 Pinterest 的相同上下文菜单。所以我有一个叠加层,它显示我的上下文菜单和背景,我还想将当前元素保留在叠加层前面。
这里有 2 个视频:Pinterest menu vs My Flutter menu。
为了制作叠加层,我使用了 flutter_portal 包。
这是蓝卡小部件的代码,带有叠加层:
import 'package:flutter/material.dart';
import 'package:flutter_portal/flutter_portal.dart';
import 'package:vector_math/vector_math.dart' show radians;
class CardWidget extends StatefulWidget {
@override
_CardWidgetState createState() => _CardWidgetState();
}
class _CardWidgetState extends State<CardWidget> with SingleTickerProviderStateMixin {
late AnimationController controller;
late Animation<double> degreeAnimation;
late Animation<double> opacityAnimation;
bool isMenuOpen = false;
double menuPosX = 0;
double menuPosY = 0;
@override
void initState() {
controller = AnimationController(vsync: this, duration: Duration(milliseconds: 200))
..addListener(() {
setState(() {});
})
..addStatusListener((status) {
if (status == AnimationStatus.forward) {
isMenuOpen = true;
} else if (status == AnimationStatus.dismissed) {
isMenuOpen = false;
}
});
degreeAnimation =
Tween(begin: 0.0, end: 1.0).animate(CurvedAnimation(parent: controller, curve: Curves.easeOutBack));
opacityAnimation =
Tween(begin: 0.0, end: 1.0).animate(CurvedAnimation(parent: controller, curve: Curves.easeOutExpo));
super.initState();
}
@override
Widget build(BuildContext context) {
return AspectRatio(
aspectRatio: 63.5 / 88.9,
child: PortalEntry(
visible: isMenuOpen,
portal: Container(
color: Colors.black.withOpacity(opacityAnimation.value / 2),
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
controller.reverse();
},
),
),
child: PortalEntry(
visible: isMenuOpen,
child: GestureDetector(
onTapDown: (details) {
if (controller.isCompleted) {
controller.reverse();
} else {
menuPosX = details.globalPosition.dx;
menuPosY = details.globalPosition.dy;
controller.forward();
}
},
// Blue card content
child: Container(
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.all(
Radius.circular(8),
),
),
child: Center(
child: Text(
'Card Widget',
style: TextStyle(color: Colors.white),
),
),
),
),
// Current contextual Menu
portal: ContextualMenuWidget(),
),
),
);
}
}
感谢您的帮助!
也许您可以将所有其他卡片的颜色更改为与背景相同,而不是尝试添加叠加层。这样你会达到同样的效果。
您可以检查 isMenuOpen
是否为真并保存点击它的卡片的索引,并且在您的网格生成器功能中您可以将所有卡片的颜色更改为与背景相同.
多亏了 orotype,我终于用 AnimatedOpacity 包装了我的卡片,而不是制作黑色叠加层,并在上下文菜单为 opened/closed 时传递回调以触发动画。
我不知道这是否是最好的解决方案,但我喜欢这个结果。
我正在尝试在 Flutter 中重现 Pinterest 的相同上下文菜单。所以我有一个叠加层,它显示我的上下文菜单和背景,我还想将当前元素保留在叠加层前面。
这里有 2 个视频:Pinterest menu vs My Flutter menu。
为了制作叠加层,我使用了 flutter_portal 包。
这是蓝卡小部件的代码,带有叠加层:
import 'package:flutter/material.dart';
import 'package:flutter_portal/flutter_portal.dart';
import 'package:vector_math/vector_math.dart' show radians;
class CardWidget extends StatefulWidget {
@override
_CardWidgetState createState() => _CardWidgetState();
}
class _CardWidgetState extends State<CardWidget> with SingleTickerProviderStateMixin {
late AnimationController controller;
late Animation<double> degreeAnimation;
late Animation<double> opacityAnimation;
bool isMenuOpen = false;
double menuPosX = 0;
double menuPosY = 0;
@override
void initState() {
controller = AnimationController(vsync: this, duration: Duration(milliseconds: 200))
..addListener(() {
setState(() {});
})
..addStatusListener((status) {
if (status == AnimationStatus.forward) {
isMenuOpen = true;
} else if (status == AnimationStatus.dismissed) {
isMenuOpen = false;
}
});
degreeAnimation =
Tween(begin: 0.0, end: 1.0).animate(CurvedAnimation(parent: controller, curve: Curves.easeOutBack));
opacityAnimation =
Tween(begin: 0.0, end: 1.0).animate(CurvedAnimation(parent: controller, curve: Curves.easeOutExpo));
super.initState();
}
@override
Widget build(BuildContext context) {
return AspectRatio(
aspectRatio: 63.5 / 88.9,
child: PortalEntry(
visible: isMenuOpen,
portal: Container(
color: Colors.black.withOpacity(opacityAnimation.value / 2),
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
controller.reverse();
},
),
),
child: PortalEntry(
visible: isMenuOpen,
child: GestureDetector(
onTapDown: (details) {
if (controller.isCompleted) {
controller.reverse();
} else {
menuPosX = details.globalPosition.dx;
menuPosY = details.globalPosition.dy;
controller.forward();
}
},
// Blue card content
child: Container(
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.all(
Radius.circular(8),
),
),
child: Center(
child: Text(
'Card Widget',
style: TextStyle(color: Colors.white),
),
),
),
),
// Current contextual Menu
portal: ContextualMenuWidget(),
),
),
);
}
}
感谢您的帮助!
也许您可以将所有其他卡片的颜色更改为与背景相同,而不是尝试添加叠加层。这样你会达到同样的效果。
您可以检查 isMenuOpen
是否为真并保存点击它的卡片的索引,并且在您的网格生成器功能中您可以将所有卡片的颜色更改为与背景相同.
多亏了 orotype,我终于用 AnimatedOpacity 包装了我的卡片,而不是制作黑色叠加层,并在上下文菜单为 opened/closed 时传递回调以触发动画。
我不知道这是否是最好的解决方案,但我喜欢这个结果。