简体   繁体   中英

How to disable drag scrolling but keep mouse wheel scrolling for ListView in Flutter MacOS?

So when I set physics: const NeverScrollableScrollPhysics() on ListView.builder , it also disables mouse wheel scrolling. Is there a way to keep mouse wheel but disable drag?

Thanks

Thanks for the answer (@HasilT), it helped! I found that PointerScrollEvent.scrollDelta is already "animated", and you can use it with ScrollController.jumpTo . In my code, I prevent overscroll with min and max functions.

import 'dart:math' as math;

Listener(
  onPointerSignal: (ps) {
    if (ps is PointerScrollEvent) {
      final newOffset = _controller.offset + ps.scrollDelta.dy;
      if (ps.scrollDelta.dy.isNegative) {
        _controller.jumpTo(math.max(0, newOffset));
      } else {
        _controller
            .jumpTo(math.min(_controller.position.maxScrollExtent, newOffset));
      }
    }
  },
  child: ListView.builder(
    itemCount: 100,
    controller: _controller,
    physics: NeverScrollableScrollPhysics(),
    itemBuilder: (BuildContext context, int index) {
      return Container(
          height: 100,
          margin: EdgeInsets.all(10),
          color: index.isEven ? Colors.blue : Colors.green);
    },
  ),
);

You can use a Listener widget to watch for drag events happening on your ListView and manually scroll the ListView to desired offset using ScrollController attached to that ListView .

Here is a sample code:

Listener(
          onPointerSignal: (ps) {
            if (ps is PointerScrollEvent) {
              _controller.animateTo(ps.position.dy,
                  duration: Duration(milliseconds: 500),
                  curve: Curves.linear);
            }
          },
          child: ListView.builder(
              itemCount: 100,
              controller: _controller,
              physics: NeverScrollableScrollPhysics(),
              itemBuilder: (BuildContext context, int index) {
                return Container(
                    height: 100,
                    margin: EdgeInsets.all(10),
                    color: index.isEven ? Colors.blue : Colors.green);
              }))

And here is a link to a working demo ( You may have to play around with listener events to make the scrolling perfect, this is just an example)

Feature request has been created for this case: https://github.com/flutter/flutter/issues/71322

Just wrap in a widget @truthmast's solution

import 'dart:math' as math;

import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:responsive_builder/responsive_builder.dart';

class DragPreventingSingleChildScrollView extends StatelessWidget {
  final _controller = ScrollController();
  final Widget child;

  DragPreventingSingleChildScrollView({Key key, this.child}) : super(key: key);

  @override
  Widget build(BuildContext context) => ResponsiveBuilder(
        builder: (c, si) => !si.isDesktop
            ? SingleChildScrollView(child: child)
            : Listener(
                onPointerSignal: (ps) {
                  if (ps is PointerScrollEvent) {
                    final newOffset = _controller.offset + ps.scrollDelta.dy;
                    if (ps.scrollDelta.dy.isNegative) {
                      _controller.jumpTo(math.max(0, newOffset));
                    } else {
                      _controller.jumpTo(math.min(
                          _controller.position.maxScrollExtent, newOffset));
                    }
                  }
                },
                child: SingleChildScrollView(
                  controller: _controller,
                  physics: NeverScrollableScrollPhysics(),
                  child: child,
                ),
              ),
      );
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM