我在水平滚动PageView
中有一个垂直滚动WebView
。像这样:
PageView.builder(
itemCount: 5,
itemBuilder: (context, index) {
return WebView(
initialUrl: 'https://flutter.dev/docs',
gestureRecognizers: [
Factory(() => VerticalDragGestureRecognizer()),
].toSet(),
);
},
);
在Flutter的先前稳定版本(1.5.4)中,此操作按预期工作-垂直滚动将在WebView中移动内容,水平滚动将在PageView中移动。
在升级到Flutter v1.7.8+hotfix.3
后,此问题中断了。现在,即使手势几乎完全是垂直的,水平滚动似乎总是可以取胜的。如果页面完全垂直滚动,则仅在手势停止后(即,手势停止后我停止触摸屏幕)–手势进行时就不会垂直滚动。
在VerticalDragGestureRecognizer
中添加和删除gestureRecognizers
现在无效-程序以任何一种方式工作都好像识别器不在列表中(尽管并不是gestureRecognizers
被完全忽略了,因为添加EagerGestureRecognizer
确实有效果)。
这是手势竞技场的调试输出(请记住,我试图将手势保持尽可能垂直,但即使手指稍微向两侧移动也足以赢得HorizontalDragGestureRecognizer
,即使我也一直在垂直移动)
I/flutter (30125): Gesture arena 14 ❙ ★ Opening new gesture arena.
I/flutter (30125): Gesture arena 14 ❙ Adding: Instance of '_CombiningGestureArenaMember'
I/flutter (30125): Gesture arena 14 ❙ Adding: LongPressGestureRecognizer#9cad1(debugOwner: GestureDetector, state: ready)
I/flutter (30125): Gesture arena 14 ❙ Adding: HorizontalDragGestureRecognizer#69b8f(start behavior: start)
I/flutter (30125): Gesture arena 14 ❙ Closing with 3 members.
I/flutter (30125): Gesture arena 14 ❙ Rejecting: LongPressGestureRecognizer#9cad1(debugOwner: GestureDetector, state: possible)
I/flutter (30125): Gesture arena 14 ❙ Accepting: HorizontalDragGestureRecognizer#69b8f(start behavior: start)
I/flutter (30125): Gesture arena 14 ❙ Self-declared winner: HorizontalDragGestureRecognizer#69b8f(start behavior: start)
这是当您确实在进行拖动手势时设法将手势保持完全垂直(似乎在使用鼠标的模拟器上更容易)时发生的情况:
flutter: Gesture arena 30 ❙ ★ Opening new gesture arena.
flutter: Gesture arena 30 ❙ Adding: Instance of '_CombiningGestureArenaMember'
flutter: Gesture arena 30 ❙ Adding: HorizontalDragGestureRecognizer#11e7f(start behavior: down)
flutter: Gesture arena 30 ❙ Closing with 2 members.
即使是轻微的垂直移动也会使HorizontalDragGestureRecognizer
宣布获胜,但是VerticalDragGestureRecognizer
(似乎包裹在_CombiningGestureArenaMember
内)从不要求胜利。实际上,似乎似乎完全忽略了它-在VerticalDragGestureRecognizer
中使用gestureRecognizers
的手势竞技场输出,如果没有,则完全相同。
这可能是Flutter中的错误,因此我还创建了an issue on Flutter's GitHub。但是,无论哪种方式-如何在当前版本的Flutter中达到这种效果?任何解决方法或规范解决方案将不胜感激。
答案 0 :(得分:1)
我升级SDK只是为了解决您描述的这个问题。这个问题太烦人了,我想出了这个相当丑陋的技巧。
当事件发生在中间(通常是我们滚动的地方)时,此CustomGestureRecognizer
将忽略不需要的行为。
这确实会带来一些过度滚动的阴影,我认为这些阴影可以处理,可能还需要更多时间。
class CustomGestureRecognizer extends OneSequenceGestureRecognizer {
double maxScreenOffsetX;
final double edgeMargin = 20.0;
CustomGestureRecognizer({@required this.maxScreenOffsetX});
@override
void addAllowedPointer(PointerDownEvent event) {
print("CustomGestureRecognizer: Screen Width: "+ maxScreenOffsetX.toString());
print("CustomGestureRecognizer: dx: "+event.position.dx.toString());
if (event.position.dx < edgeMargin || event.position.dx > (maxScreenOffsetX - edgeMargin)) {
print("CustomGestureRecognizer: At the Edge.");
return;
}
print("CustomGestureRecognizer: Inside Safe Zone");
startTrackingPointer(event.pointer, event.transform);
resolve(GestureDisposition.accepted);
stopTrackingPointer(event.pointer);
}
PageView窗口小部件
PageView.builder(
itemCount: 5,
physics: CustomScrollPhysics(),
itemBuilder: (context, index) {
return WebView(
initialUrl: 'https://flutter.dev/docs',
gestureRecognizers: [
Factory(() => CustomGestureRecognizer(maxScreenOffsetX: screenWidth)),
].toSet(),
);
});
屏幕宽度
@override
Widget build(BuildContext context) {
screenWidth = MediaQuery.of(context).size.width;
return Scaffold(//...
答案 1 :(得分:1)
竞技场的规则似乎已更改,现在竞技场将宣布具有主动接收器的手势的胜利,这确实增加了手势的响应能力,但< / strong>,因为本机视图不声明手势,仅在没有其他活动检测器/接收器声明手势时才使用手势,所以我什至怀疑垂直拖动不会作为从WebView手势进入竞技场的原因,这就是为什么水平拖动将宣布水平拖动手势为胜利,因为根本没有其他小部件要求任何手势。
您可以扩展VerticalDragGestureRecognizer
,这是相同的想法,但对我来说效果很好。
代码:
class CustomVerticalGestureRecognizer extends VerticalDragGestureRecognizer{
CustomVerticalGestureRecognizer({ PointerDeviceKind kind }):super(kind: kind);
@override
void addPointer(PointerEvent event) {
startTrackingPointer(event.pointer);
}
@override
void handleEvent(PointerEvent event) {
if (event is PointerMoveEvent){
if (event.delta.dy.abs()>event.delta.dx.abs()){
resolve(GestureDisposition.accepted);
} else {
stopTrackingPointer(event.pointer);
}
}
}
@override
String get debugDescription => 'customPan';
@override
void didStopTrackingLastPointer(int pointer) {}
}
答案 2 :(得分:-1)
Horizontal ListView inside a Vertical ScrollView in Flutter
他们在这里所说的解决方案是整个页面都是可滚动的,然后他们内部只有水平的列表视图,可能对此有用。 Havent对其进行了尝试,但是它在外观和听起来与您的用例高度相关。
希望它能有所帮助。