Flutter滚动位置监听插件positioned_scroll_observer的使用

发布于 1周前 作者 yuanlaile 来自 Flutter

Flutter滚动位置监听插件 positioned_scroll_observer 的使用

positioned_scroll_observer 是一个用于监听和控制滚动位置的Flutter插件。它支持多种滚动视图(如 ListView, GridView, SingleChildScrollView 等),并提供了丰富的功能,例如根据索引跳转、动画到特定位置、检查元素是否可见等。

主要特性

  1. 根据索引跳转或动画到指定位置:使用 jumpToIndexanimateToIndex 方法。
  2. 按比例跳转或动画到视口中的位置:适用于快速跳转到列表的顶部、中间或底部。
  3. 保留旧的滚动偏移量:使用 PositionRetainedScrollPhysics 避免在顶部添加新项目时滚动位置发生变化。
  4. 检查特定索引是否在屏幕上可见
  5. 获取当前视口中可见的所有项目
  6. 检查特定 RenderObject 在视口中的可见比例

使用步骤

1. 创建并绑定观察者

首先需要创建一个观察者,并将其绑定到所有子项上。可以通过 ObserverProxy 来包裹每个子项。

2. 使用观察者

_observer.jumpToIndex(
    index,
    position: _controller.position,
);

_observer.animateToIndex(
    index,
    position: _controller.position,
    duration: const Duration(milliseconds: 200),
    curve: Curves.fastLinearToSlowEaseIn,
);

示例代码

示例1:单ChildScrollView 和 ListWheelScrollView

创建观察者

final ScrollController _controller = ScrollController();
late final _observer = ScrollObserver.boxMulti(
  axis: Axis.vertical, // 指定滚动方向
  itemCount: 30, // 子项数量
);

绑定观察者到子项

SingleChildScrollView(
  controller: _controller,
  scrollDirection: Axis.vertical,
  child: Column(
    children: [
      for (int i = 0; i < 30; i++)
        ObserverProxy(
          observer: _observer,
          child: DecoratedBox(
            decoration: BoxDecoration(border: Border.all()),
            child: SizedBox(
              height: 100,
              width: 100,
              child: Center(
                child: Text("Column item $i"),
              ),
            ),
          ),
        ),
    ],
  ),
);

示例2:SliverWidgets (如 ListView, GridView)

创建观察者

final ScrollController _controller = ScrollController();
late final _observer = ScrollObserver.sliverMulti(itemCount: 30);

绑定观察者到子项

ListView.builder(
  controller: _controller,
  itemBuilder: (context, index) => ObserverProxy(
    observer: _observer,
    child: ListTile(
      key: ValueKey<int>(index),
      leading: const CircleAvatar(
        child: Text("L"),
      ),
      title: Text("Positioned List Example $index"),
    ),
  ),
  itemCount: 30,
);

示例3:自定义滚动视图

对于 ListView.customGridView.custom,可以使用 PositionedChildListDelegatePositionedChildBuilderDelegate 方便地包裹子项:

ListView.custom(
  controller: _controller,
  childrenDelegate: PositionedChildBuilderDelegate(
    builder: (context, index) {
      return ObserverProxy(
        observer: _observer,
        child: ListTile(
          title: Text("Custom ListView Item $index"),
        ),
      );
    },
    childCount: 30,
  ),
);

更多功能

检查索引是否可见

bool isVisible = _observer.isRevealed(index);

获取当前视口中的可见项

List<int> visibleItems = _observer.getVisibleIndexes();

保持滚动偏移量

当在顶部添加新项目时,避免滚动位置发生变化:

ListView.builder(
  controller: _controller,
  reverse: true,
  physics: const PositionRetainedScrollPhysics(),
  itemBuilder: (context, index) => _items[index],
  itemCount: _itemCount,
);

按比例跳转或动画到视口中的位置

_observer.showInViewport(
  _controller.position,
  alignment: 0.5, // 0.0 表示对齐到视口的开头,0.5 表示居中,1.0 表示对齐到末尾
);

注意事项

  • 所有子项必须用 ObserverProxy 包裹。
  • 观察者的 itemCount 必须与实际子项数量一致。
  • 当使用 ScrollObserver.boxMulti 时,必须指定 axis 参数。

完整示例 Demo

以下是一个完整的示例,展示了如何使用 positioned_scroll_observer 插件来实现滚动监听和控制:

import 'package:flutter/material.dart';
import 'package:positioned_scroll_observer/positioned_scroll_observer.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Scroll Observer Demo'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late final ScrollController _controller;
  late final ScrollObserver _observer;

  @override
  void initState() {
    super.initState();
    _controller = ScrollController();
    _observer = ScrollObserver.sliverMulti(itemCount: 30);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: ListView.builder(
        controller: _controller,
        itemBuilder: (context, index) => ObserverProxy(
          observer: _observer,
          child: ListTile(
            title: Text("Item $index"),
          ),
        ),
        itemCount: 30,
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          _observer.animateToIndex(15, position: _controller.position, duration: Duration(seconds: 1));
        },
        tooltip: 'Jump to Index 15',
        child: Icon(Icons.arrow_downward),
      ),
    );
  }
}

这个示例展示了如何使用 positioned_scroll_observer 插件来监听和控制滚动位置,并通过按钮点击将滚动位置动画到第15个子项。


更多关于Flutter滚动位置监听插件positioned_scroll_observer的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter滚动位置监听插件positioned_scroll_observer的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,positioned_scroll_observer 是一个用于 Flutter 的插件,它允许开发者监听滚动视图(如 ListViewCustomScrollView)的滚动位置。以下是一个使用 positioned_scroll_observer 的示例代码,展示了如何监听滚动位置并执行相应的操作。

首先,确保你已经在 pubspec.yaml 文件中添加了 positioned_scroll_observer 依赖:

dependencies:
  flutter:
    sdk: flutter
  positioned_scroll_observer: ^x.y.z  # 替换为最新版本号

然后,运行 flutter pub get 来获取依赖。

接下来是一个完整的 Flutter 应用示例,展示如何使用 PositionedScrollObserver 来监听滚动位置:

import 'package:flutter/material.dart';
import 'package:positioned_scroll_observer/positioned_scroll_observer.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'PositionedScrollObserver Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: ScrollPositionDemo(),
    );
  }
}

class ScrollPositionDemo extends StatefulWidget {
  @override
  _ScrollPositionDemoState createState() => _ScrollPositionDemoState();
}

class _ScrollPositionDemoState extends State<ScrollPositionDemo> {
  late PositionedScrollController _scrollController;
  late PositionedScrollObserver _scrollObserver;

  @override
  void initState() {
    super.initState();
    _scrollController = PositionedScrollController();
    _scrollObserver = PositionedScrollObserver(_scrollController)
      ..addListener(() {
        double scrollPosition = _scrollObserver.position!.pixels;
        double maxScroll = _scrollObserver.position!.maxScrollExtent;
        print('Current scroll position: $scrollPosition, Max scroll: $maxScroll');
      });
  }

  @override
  void dispose() {
    _scrollObserver.dispose();
    _scrollController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('PositionedScrollObserver Demo'),
      ),
      body: ListView.builder(
        controller: _scrollController,
        itemCount: 100,
        itemBuilder: (context, index) {
          return ListTile(
            title: Text('Item $index'),
          );
        },
      ),
    );
  }
}

在这个示例中:

  1. 我们创建了一个 PositionedScrollController 实例来控制滚动视图。
  2. 我们创建了一个 PositionedScrollObserver 实例并将其与 PositionedScrollController 关联。
  3. 通过 _scrollObserver.addListener 方法,我们添加了一个监听器,该监听器会在滚动位置发生变化时被调用,并打印当前的滚动位置和最大滚动位置。
  4. ListView.builder 中,我们将 controller 属性设置为 _scrollController,以便 PositionedScrollObserver 可以监听其滚动事件。

请确保你已经安装了 positioned_scroll_observer 插件,并且替换示例代码中的 ^x.y.z 为实际的最新版本号。运行这个示例应用,你应该能够在控制台中看到滚动位置的更新信息。

回到顶部