Flutter web GestureDetector:检测鼠标滚轮事件

问题描述 投票:0回答:2

我正在开发一个用于网络的flutter应用程序,当我在小部件(不是滚动小部件)内滚动鼠标滚轮时,我试图执行回调方法。

我知道

MouseRegion
小部件,并使用
Listener
作为其子项,我可以检测
onPointerSignal
事件。当
Listener
的子级是可滚动小部件(例如
ListView
)时,此方法可以正常工作,但如果此小部件不可滚动,则此方法不起作用。

我理想中想要的是一个类似于

GestureDetector
的小部件,其回调方法类似于
onPanStart
onPanUpdate
onPanEnd
,但发生在鼠标滚轮事件上(或者以相同的方式,用于笔记本电脑上的触控板滚动事件)。

有人知道我怎样才能实现这个目标吗?

flutter scroll
2个回答
11
投票

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,
    );
  }
}

这是 DartPad 上的完整示例。


0
投票

如果 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,
          ),
        ),
      ),
    );
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.