Flutter可滚动定位列表插件scrollable_positioned_list_extended的使用

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

Flutter可滚动定位列表插件scrollable_positioned_list_extended的使用

概述

scrollable_positioned_list_extended 是一个Flutter插件,它允许你创建一个可以滚动到特定项的列表。它不仅提供了滚动或跳转到特定项目的能力,还允许确定当前可见的项目。

新增功能

该包最近获得了来自 scroll_to_index 的能力,用户可以通过 AutoScrollController 来操作,但存在一定的限制

注意事项

  • 这是 scrollable_positioned_list 的扩展版本,增加了如 scrollToMaxjumpToMax 等方法,并且实现了 scrollListener 以监听滚动通知的功能。

新增特性

  1. scrollToMax - 滚动到最大范围
  2. jumpToMax - 跳转到最大范围
  3. scrollToMin - 滚动到最小范围
  4. jumpToMin - 跳转到最小范围
  5. scrollListener - 监听 ScrollNotifications,例如当前偏移量 ScrollPostition
  6. 访问 AutoScrollController() - 使用 ItemScrollController.getAutoScrollController 方法(需确保 ItemScrollController.isAttached == true
AutoScrollController? _autoScrollController;
if (itemScrollController.isAttached) {
   _autoScrollController = itemScrollController.getAutoScrollController;
}

使用方法

创建 ScrollablePositionedList

你可以通过以下方式创建一个 ScrollablePositionedList

final ItemScrollController itemScrollController = ItemScrollController();
final ItemPositionsListener itemPositionsListener = ItemPositionsListener.create();

ScrollablePositionedList.builder(
  itemCount: 500,
  itemBuilder: (context, index) => Text('Item $index'),
  itemScrollController: itemScrollController,
  itemPositionsListener: itemPositionsListener,
);

滚动到特定项

itemScrollController.scrollTo(
  index: 150,
  duration: Duration(seconds: 2),
  curve: Curves.easeInOutCubic,
);

跳转到特定项

itemScrollController.jumpTo(index: 150);

监听可见项

itemPositionsListener.itemPositions.addListener(() => ...);

监听滚动通知

itemScrollController.scrollListener(
  (notification) {
    debugPrint(notification.position.maxScrollExtent.toString());
    // 处理通知
  },
);

滚动到最大和最小位置

// 滚动到最大
itemScrollController.scrollToMax(
  duration: Duration(seconds: 2),
  curve: Curves.easeInOutCubic,
);

// 跳转到最大
itemScrollController.jumpToMax();

// 滚动到最小
itemScrollController.scrollToMin(
  duration: Duration(seconds: 2),
  curve: Curves.easeInOutCubic,
);

// 跳转到最小
itemScrollController.jumpToMin();

示例代码

以下是完整的示例代码,展示了如何使用 scrollable_positioned_list_extended 插件:

import 'dart:math';

import 'package:flutter/material.dart';
import 'package:scroll_to_index/scroll_to_index.dart';
import 'package:scrollable_positioned_list_extended/scrollable_positioned_list_extended.dart';

const numberOfItems = 5001;
const minItemHeight = 20.0;
const maxItemHeight = 150.0;
const scrollDuration = Duration(seconds: 2);
const randomMax = 32;

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'ScrollablePositionedList Example',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: const ScrollablePositionedListPage(),
    );
  }
}

class ScrollablePositionedListPage extends StatefulWidget {
  const ScrollablePositionedListPage({Key? key}) : super(key: key);

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

class _ScrollablePositionedListPageState extends State<ScrollablePositionedListPage> {
  final ItemScrollController itemScrollController = ItemScrollController();
  final ItemPositionsListener itemPositionsListener = ItemPositionsListener.create();
  late List<double> itemHeights;
  late List<Color> itemColors;
  bool reversed = false;
  double alignment = 0;
  AutoScrollController? _autoScrollController;

  @override
  void initState() {
    super.initState();
    final heightGenerator = Random(328902348);
    final colorGenerator = Random(42490823);
    itemHeights = List<double>.generate(
      numberOfItems,
      (_) => heightGenerator.nextDouble() * (maxItemHeight - minItemHeight) + minItemHeight,
    );
    itemColors = List<Color>.generate(numberOfItems, (_) => Color(colorGenerator.nextInt(randomMax)).withOpacity(1));
    _autoGetPosition();
  }

  void _autoGetPosition() {
    Future.delayed(const Duration(milliseconds: 500), () {
      itemScrollController.scrollListener(
        (notification) {
          _autoScrollController = itemScrollController.getAutoScrollController;
          debugPrint(notification.position.maxScrollExtent.toString());
        },
      );
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: OrientationBuilder(
        builder: (context, orientation) => Column(
          children: [
            Expanded(child: list(orientation)),
            positionsView,
            Row(
              children: [
                Column(
                  children: [
                    scrollControlButtons,
                    const SizedBox(height: 10),
                    jumpControlButtons,
                    alignmentControl,
                  ],
                ),
                Column(
                  children: [
                    ElevatedButton(
                      onPressed: () {
                        itemScrollController.scrollToMax(duration: const Duration(milliseconds: 800));
                      },
                      child: const Text("Scroll To Max"),
                    ),
                    const SizedBox(height: 10),
                    ElevatedButton(
                      onPressed: () {
                        itemScrollController.scrollToMin(duration: const Duration(milliseconds: 800));
                      },
                      child: const Text("Scroll To Min"),
                    ),
                  ],
                ),
                const SizedBox(width: 10),
                Column(
                  children: [
                    ElevatedButton(
                      onPressed: () {
                        itemScrollController.jumpToMax();
                      },
                      child: const Text("Jump To Max"),
                    ),
                    const SizedBox(height: 10),
                    ElevatedButton(
                      onPressed: () {
                        itemScrollController.jumpToMin();
                      },
                      child: const Text("Jump To Min"),
                    ),
                  ],
                ),
                const SizedBox(width: 10),
                Column(
                  children: [
                    ElevatedButton(
                      onPressed: () {
                        _autoScrollController?.scrollToIndex(10);
                      },
                      child: const Text("Scroll To Index Via Scroll_To_Index"),
                    ),
                    const SizedBox(height: 10),
                  ],
                ),
              ],
            )
          ],
        ),
      ),
    );
  }

  Widget get alignmentControl => Row(
        mainAxisSize: MainAxisSize.max,
        children: [
          const Text('Alignment: '),
          SizedBox(
            width: 200,
            child: SliderTheme(
              data: SliderThemeData(showValueIndicator: ShowValueIndicator.always),
              child: Slider(
                value: alignment,
                label: alignment.toStringAsFixed(2),
                onChanged: (double value) => setState(() => alignment = value),
              ),
            ),
          ),
        ],
      );

  Widget list(Orientation orientation) => ScrollablePositionedList.builder(
        itemCount: numberOfItems,
        itemBuilder: (context, index) => item(index, orientation),
        itemScrollController: itemScrollController,
        addAutomaticKeepAlives: false,
        minCacheExtent: 0,
        itemPositionsListener: itemPositionsListener,
        reverse: reversed,
        scrollDirection: Axis.vertical,
      );

  Widget get positionsView => ValueListenableBuilder<Iterable<ItemPosition>>(
        valueListenable: itemPositionsListener.itemPositions,
        builder: (context, positions, child) {
          int? min;
          int? max;
          if (positions.isNotEmpty) {
            min = positions
                .where((position) => position.itemTrailingEdge > 0)
                .reduce((min, position) => position.itemTrailingEdge < min.itemTrailingEdge ? position : min)
                .index;
            max = positions
                .where((position) => position.itemLeadingEdge < 1)
                .reduce((max, position) => position.itemLeadingEdge > max.itemLeadingEdge ? position : max)
                .index;
          }
          return Row(
            children: [
              Expanded(child: Text('First Item: ${min ?? ''}')),
              Expanded(child: Text('Last Item: ${max ?? ''}')),
              const Text('Reversed: '),
              Checkbox(
                value: reversed,
                onChanged: (bool? value) => setState(() => reversed = value!),
              )
            ],
          );
        },
      );

  Widget get scrollControlButtons => Row(
        children: [
          const Text('scroll to'),
          scrollButton(0),
          scrollButton(5),
          scrollButton(10),
          scrollButton(99),
          scrollButton(5000),
        ],
      );

  Widget get jumpControlButtons => Row(
        children: [
          const Text('jump to'),
          jumpButton(0),
          jumpButton(5),
          jumpButton(10),
          jumpButton(99),
          jumpButton(5000),
        ],
      );

  final _scrollButtonStyle = ButtonStyle(
    padding: MaterialStateProperty.all(const EdgeInsets.symmetric(horizontal: 20, vertical: 0)),
    minimumSize: MaterialStateProperty.all(Size.zero),
    tapTargetSize: MaterialTapTargetSize.shrinkWrap,
  );

  Widget scrollButton(int value) => TextButton(
        key: ValueKey<String>('Scroll$value'),
        onPressed: () {
          scrollTo(value);
        },
        child: Text('$value'),
        style: _scrollButtonStyle,
      );

  Widget jumpButton(int value) => TextButton(
        key: ValueKey<String>('Jump$value'),
        onPressed: () {
          jumpTo(value);
        },
        child: Text('$value'),
        style: _scrollButtonStyle,
      );

  void scrollTo(int index) async {
    await itemScrollController.scrollTo(
      index: index,
      duration: scrollDuration,
      curve: Curves.easeInCubic,
      alignment: alignment,
    );
  }

  void jumpTo(int index) => itemScrollController.jumpTo(index: index, alignment: alignment);

  Widget item(int i, Orientation orientation) {
    return SizedBox(
      height: 200,
      child: Column(
        children: [
          Expanded(
            child: Container(
              color: Colors.grey[400],
              child: Center(
                child: Text('Item $i'),
              ),
            ),
          ),
          Container(
            height: 80,
            color: Colors.amber,
          )
        ],
      ),
    );
  }
}

限制

  • ItemScrollController.getAutoScrollController 不适用于以下方法:
    • highlight()
    • cancelAllHighlights()
    • jumpTo()

希望这些信息对你有所帮助!如果你有任何问题或需要进一步的帮助,请随时提问。


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

1 回复

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


当然,以下是一个关于如何使用 scrollable_positioned_list_extended 插件的示例代码。这个插件允许你在 Flutter 中创建一个可滚动的列表,并能够定位到特定的列表项。

首先,你需要在你的 pubspec.yaml 文件中添加这个插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  scrollable_positioned_list_extended: ^0.2.0  # 请注意版本号,可能需要更新到最新版本

然后,你可以在你的 Flutter 应用中使用这个插件。以下是一个完整的示例:

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

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

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

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
  final ItemScrollController itemScrollController = ItemScrollController();
  final List<String> items = List.generate(100, (index) => "Item ${index + 1}");

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Scrollable Positioned List Extended Demo'),
      ),
      body: Column(
        children: [
          Expanded(
            child: ScrollablePositionedList.builder(
              itemCount: items.length,
              itemBuilder: (context, index) {
                return ListTile(
                  title: Text(items[index]),
                );
              },
              itemScrollController: itemScrollController,
            ),
          ),
          ElevatedButton(
            onPressed: () {
              // 滚动到第10项
              itemScrollController.scrollTo(
                index: 9,
                duration: Duration(seconds: 1),
                alignment: 0.5,  // 0.0表示左对齐,1.0表示右对齐,0.5表示居中对齐
              );
            },
            child: Text('Scroll to Item 10'),
          ),
          ElevatedButton(
            onPressed: () {
              // 滚动到第50项
              itemScrollController.scrollTo(
                index: 49,
                duration: Duration(seconds: 1),
                alignment: 0.5,
              );
            },
            child: Text('Scroll to Item 50'),
          ),
        ],
      ),
    );
  }
}

解释

  1. 依赖添加:在 pubspec.yaml 文件中添加 scrollable_positioned_list_extended 依赖。
  2. 创建应用:使用 MaterialAppScaffold 创建基本的 Flutter 应用结构。
  3. 状态管理:创建一个 StatefulWidget 并使用 SingleTickerProviderStateMixin 以便能够使用动画。
  4. 列表数据:定义一个包含100个字符串项的列表。
  5. 列表构建:使用 ScrollablePositionedList.builder 构建一个可滚动的列表,并传入 itemCountitemBuilder
  6. 滚动控制:使用 ItemScrollController 控制列表项的滚动。
  7. 按钮控制:添加两个按钮,分别用于滚动到第10项和第50项。

这个示例展示了如何使用 scrollable_positioned_list_extended 插件创建一个可滚动的列表,并通过按钮点击事件滚动到特定的列表项。你可以根据需要调整这个示例以适应你的应用。

回到顶部