我正在开发一个用于网络的flutter应用程序,当我在小部件(不是滚动小部件)内滚动鼠标滚轮时,我试图执行回调方法。
我知道
MouseRegion
小部件,并使用 Listener
作为其子项,我可以检测 onPointerSignal
事件。当 Listener
的子级是可滚动小部件(例如 ListView
)时,此方法可以正常工作,但如果此小部件不可滚动,则此方法不起作用。
我理想中想要的是一个类似于
GestureDetector
的小部件,其回调方法类似于 onPanStart
、onPanUpdate
和 onPanEnd
,但发生在鼠标滚轮事件上(或者以相同的方式,用于笔记本电脑上的触控板滚动事件)。
有人知道我怎样才能实现这个目标吗?
Listener
不需要任何父母。
可以使用如下所示的小部件,它将其子部件包装在 Listener
中,并在收到 PointerScrollEvent
时调用给定的回调:
class ScrollDetector extends StatelessWidget {
final void Function(PointerScrollEvent event) onPointerScroll;
final Widget child;
const ScrollDetector({
Key key,
@required this.onPointerScroll,
@required this.child,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Listener(
onPointerSignal: (pointerSignal) {
if (pointerSignal is PointerScrollEvent) onPointerScroll(pointerSignal);
},
child: child,
);
}
}
如果 2024 年的人需要自定义滚动区域:
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
/// A scrollable area that can be sized.
///
/// This widget act like any [Scrollable] widget which can detect mouse/mobile
/// drag and mouse wheel scroll.
///
/// Its usefull when you need extra scrollable area if your [Scrollable] widget
/// must have fixed size.
///
/// Use case example:
/// ```dart
/// const kCardW = 400.0;
/// const kCardH = 200.0;
///
/// Stack(
/// fit: Stack.fit
/// children: [
/// // act as ListView scroller.
/// SizedScrollableArea.expand(controller: _listViewController),
///
/// Center(
/// child: SizedBox(
/// width: kCardW,
/// height: double.infinity,
/// child: ListView.builder(
/// controller: _listViewController,
/// itemCount: 25,
/// itemBuilder: (_, __) => SizedBox(
/// // width: kCardW, // will expand following the ListView
/// height: kCardH,
/// child: Card(),
/// ),
/// ),
/// ),
/// ),
/// ),
/// ],
/// ),
/// ```
class SizedScrollableArea extends StatelessWidget {
const SizedScrollableArea({
super.key,
required this.controller,
this.width,
this.height,
this.child,
});
const SizedScrollableArea.expand({
super.key,
required this.controller,
this.child,
}) : width = double.infinity,
height = double.infinity;
const SizedScrollableArea.shrink({
super.key,
required this.controller,
this.child,
}) : width = 0.0,
height = 0.0;
SizedScrollableArea.fromSize({
super.key,
required this.controller,
Size? size,
this.child,
}) : width = size?.width,
height = size?.height;
const SizedScrollableArea.square({
super.key,
required this.controller,
double? dimension,
this.child,
}) : width = dimension,
height = dimension;
/// Scroll controller to listen.
final ScrollController controller;
/// If non-null, requires the child to have exactly this width.
final double? width;
/// If non-null, requires the child to have exactly this height.
final double? height;
final Widget? child;
/// Scroll position from [controller].
ScrollPosition get position => controller.position;
@override
Widget build(BuildContext context) {
return SizedBox(
width: width,
height: height,
child: Listener(
onPointerSignal: (signal) {
if (signal is PointerScrollEvent) {
position.moveTo(position.pixels + signal.scrollDelta.dy);
}
},
// MouseRegion to trigger listener
child: MouseRegion(
// For mobile/mouse/trackpad drag.
child: GestureDetector(
onVerticalDragUpdate: (details) {
position.moveTo(position.pixels - details.delta.dy);
},
child: child,
),
),
),
);
}
}