flutter - 如何在 Flutter 中模拟波纹效果并执行按钮的 onPressed?
问题描述
我试图模仿在 Flutter 中的 MaterialButton 上点击波纹的行为。本质上,我希望能够调用一些任意函数(例如tapTargetWithEffect(GlobalKey target)
)并查看给定的按钮上的涟漪效应GlobalKey
以及onPressed
要执行的回调。
我在指针测试中看到可以通过分派指针事件WidgetsBinding
来触发涟漪效应。如何执行onPressed
回调?
解决方案
这是如何实现这种效果的简单实现。
- 首先,找到分配给给定 GlobalKey 的 RenderBox
- 然后检查它是否是语义意义上的按钮(即可以按下/点击)
- 在 RenderBox 上执行命中测试以获取
HitTestEntry
给定指针位置下的小部件(对象)列表 - 查找
onTap
分配了回调的目标(这些将实现RenderSemanticsGestureHandler
),首先获取并分配给tappable
- 查找
onPointerDown
分配了回调的目标(这些将实现RenderPointerListener
),首先获取并分配给clickable
- 调用
onTap
回调来执行按钮的onPressed
onPointerDown
用适当的方式调用PointerDownEvent
以显示波纹PointerDownEvent
接受position
参数,使其成为原件的中心RenderBox
- 通过在应用程序边界内的某处
PointerDownEvent
调度来取消所需的持续时间PointerMoveEvent
WidgetsBinding.instance.dispatchEvent
- 您必须在此之前执行命中测试
请注意,hitTest()
函数接受BoxHitTestResult
将包含命中测试的结果:)
示例实现:
void tapTargetWithEffect(GlobalKey target) {
final RenderBox renderBox = target.currentContext.findRenderObject();
final child = renderBox as RenderSemanticsAnnotations;
if (child.button) {
final size = renderBox.size;
final center = renderBox.localToGlobal(size.center(Offset.zero));
final hitResult = BoxHitTestResult();
child.hitTest(hitResult, position: size.center(Offset.zero));
final pointerDown = PointerDownEvent(
position: center,
);
final tappableL = hitResult.path
.where((element) => element.target is RenderSemanticsGestureHandler)
.map((element) => element.target as RenderSemanticsGestureHandler)
.toList();
final clickableL = hitResult.path
.where((element) => element.target is RenderPointerListener)
.map((e) => e.target as RenderPointerListener)
.toList();
if (tappableL.isEmpty) {
print('No RenderSemanticsGestureHandler available');
return;
}
if (clickableL.isEmpty) {
print('No RenderPointerListener available');
return;
}
final tappable = tappableL.first;
final clickable = clickableL.first;
clickable.onPointerDown?.call(pointerDown);
tappable.onTap?.call();
// cancel the pointer down event
Future.delayed(Duration(milliseconds: 500)).then((value) {
print('Cancelling the pointer down event');
final result = BoxHitTestResult();
WidgetsBinding.instance.hitTest(result, Offset.zero);
WidgetsBinding.instance.dispatchEvent(PointerMoveEvent(), result);
});
}
}
推荐阅读
- c# - 在 Parallel.Foreach 中调用异步方法的最佳实践/正确方法是什么?
- javascript - Onclick 函数在加载事件侦听器中时未调用
- sharepoint - 如何开始从 SharePoint 外部读取 SharePoint 列表信息?
- python - 将两个单独的数据框之间的对应列组合成新的数据框
- ios - 视图转换后如何修复不均匀的边框宽度?
- angularjs - 如何为自定义 B2C 邀请策略注册 MSAL JS 回调?
- flutter - WidgetsApp 类、MaterialApp 类和 Directionality 类有什么区别
- python - 当复杂索引和基于布尔的条件作为子集时,如何为熊猫数据框赋值?
- yii - Yii 2 高级模板默认后台管理员登录详情
- javascript - 如果在使用 javascript 中的 map 方法通过该数组执行循环期间将元素推入数组会发生什么