runApp(MyApp()); class MyApp extends -6ren">
gpt4 book ai didi

在 PageView 中的 WheelEvent 上 Flutter Web "smooth scrolling"

转载 作者:行者123 更新时间:2023-12-03 16:48:06 26 4
gpt4 key购买 nike

使用下面的代码

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
const MyApp({Key key}) : super(key: key);

@override
Widget build(BuildContext context) => MaterialApp(
home: const MyHomePage(),
);
}

class MyHomePage extends StatelessWidget {
const MyHomePage({Key key}) : super(key: key);

@override
Widget build(BuildContext context) => DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
title: const Center(
child: Text('use the mouse wheel to scroll')),
bottom: TabBar(
tabs: const [
Center(child: Text('ScrollView')),
Center(child: Text('PageView'))
],
),
),
body: TabBarView(
children: [
SingleChildScrollView(
child: Column(
children: [
for (int i = 0; i < 10; i++)
Container(
height: MediaQuery.of(context).size.height,
child: const Center(
child: FlutterLogo(size: 80),
),
),
],
),
),
PageView(
scrollDirection: Axis.vertical,
children: [
for (int i = 0; i < 10; ++i)
const Center(
child: FlutterLogo(size: 80),
),
],
),
],
),
),
);
}
可以看到,在 dartpad 上运行或从此 video ,
使用鼠标滚轮滚动 PageView提供平庸的体验(充其量),
这是一个已知问题 #35687 #32120 ,但我正在尝试找到解决方法
实现 PageView的平滑滚动或至少防止“口吃”。
有人可以帮助我或指出我正确的方向吗?
我不确定 PageScrollPhysics 的问题。 ;
我有一种直觉,问题可能出在 WheelEvent 上。
因为使用多点触控滚动滑动非常有效

最佳答案

问题源于一系列事件:

  • 用户将鼠标滚轮旋转一格,
  • Scrollable接收 PointerSignalcalls jumpTo方法,
  • _PagePositionjumpTo方法(源自 ScrollPositionWithSingleContext )更新滚动位置并调用 goBallistic方法,
  • requested来自 PageScrollPhysics模拟将位置恢复到初始值,因为一个缺口偏移量太小而无法翻页,
  • 从步骤(1)重复另一个凹口和过程。

  • 解决问题的一种方法是在调用 goBallistic 之前执行延迟。方法。这可以在 _PagePosition 中完成class,但是 class 是私有(private)的,我们必须修补 Flutter SDK:
    // <FlutterSDK>/packages/flutter/lib/src/widgets/page_view.dart
    // ...

    class _PagePosition extends ScrollPositionWithSingleContext implements PageMetrics {
    //...

    // add this code to fix issue (mostly borrowed from ScrollPositionWithSingleContext):
    Timer timer;

    @override
    void jumpTo(double value) {
    goIdle();
    if (pixels != value) {
    final double oldPixels = pixels;
    forcePixels(value);
    didStartScroll();
    didUpdateScrollPositionBy(pixels - oldPixels);
    didEndScroll();
    }
    if (timer != null) timer.cancel();
    timer = Timer(Duration(milliseconds: 200), () {
    goBallistic(0.0);
    timer = null;
    });
    }

    // ...
    }
    另一种方法是将 jumpTo 替换为 animateTo。这可以在不修补 Flutter SDK 的情况下完成,但看起来更复杂,因为我们需要禁用默认 PointerSignalEvent听众:
    import 'dart:async';
    import 'package:flutter/gestures.dart';
    import 'package:flutter/material.dart';
    import 'package:flutter/rendering.dart';

    class PageViewLab extends StatefulWidget {
    @override
    _PageViewLabState createState() => _PageViewLabState();
    }

    class _PageViewLabState extends State<PageViewLab> {
    final sink = StreamController<double>();
    final pager = PageController();

    @override
    void initState() {
    super.initState();
    throttle(sink.stream).listen((offset) {
    pager.animateTo(
    offset,
    duration: Duration(milliseconds: 200),
    curve: Curves.ease,
    );
    });
    }

    @override
    void dispose() {
    sink.close();
    pager.dispose();
    super.dispose();
    }

    @override
    Widget build(BuildContext context) {
    return Scaffold(
    appBar: AppBar(
    title: Text('Mouse Wheel with PageView'),
    ),
    body: Container(
    constraints: BoxConstraints.expand(),
    child: Listener(
    onPointerSignal: _handlePointerSignal,
    child: _IgnorePointerSignal(
    child: PageView.builder(
    controller: pager,
    scrollDirection: Axis.vertical,
    itemCount: Colors.primaries.length,
    itemBuilder: (context, index) {
    return Padding(
    padding: const EdgeInsets.all(8.0),
    child: Container(color: Colors.primaries[index]),
    );
    },
    ),
    ),
    ),
    ),
    );
    }

    Stream<double> throttle(Stream<double> src) async* {
    double offset = pager.position.pixels;
    DateTime dt = DateTime.now();
    await for (var delta in src) {
    if (DateTime.now().difference(dt) > Duration(milliseconds: 200)) {
    offset = pager.position.pixels;
    }
    dt = DateTime.now();
    offset += delta;
    yield offset;
    }
    }

    void _handlePointerSignal(PointerSignalEvent e) {
    if (e is PointerScrollEvent && e.scrollDelta.dy != 0) {
    sink.add(e.scrollDelta.dy);
    }
    }
    }

    // workaround https://github.com/flutter/flutter/issues/35723
    class _IgnorePointerSignal extends SingleChildRenderObjectWidget {
    _IgnorePointerSignal({Key key, Widget child}) : super(key: key, child: child);

    @override
    RenderObject createRenderObject(_) => _IgnorePointerSignalRenderObject();
    }

    class _IgnorePointerSignalRenderObject extends RenderProxyBox {
    @override
    bool hitTest(BoxHitTestResult result, {Offset position}) {
    final res = super.hitTest(result, position: position);
    result.path.forEach((item) {
    final target = item.target;
    if (target is RenderPointerListener) {
    target.onPointerSignal = null;
    }
    });
    return res;
    }
    }

    Here is demo在 CodePen 上。

    关于在 PageView 中的 WheelEvent 上 Flutter Web "smooth scrolling",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63581685/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com