Flutter滑动定位插件sliver_snap的使用

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

Flutter滑动定位插件sliver_snap的使用

Sliver Snap 简介

Sliver-Snap Banner Image

🚀 Sliver Snap 是一个Flutter包,它简化了在应用程序中添加可折叠和可展开的应用栏(AppBar)的过程。它提供了对用户滚动无缝响应的平滑过渡,并且当用户停止滚动时会自动调整到适当的状态。💻 它高度可定制,提供友好的用户体验。告别手动实现,使您的Flutter应用程序更加交互式和直观。

Platform Pub Package License: MIT

预览

basic Performance
Android Basic Performance image

安装

1. Depend on it

将以下内容添加到您的 pubspec.yaml 文件:

dependencies:
  sliver_snap: ^2.0.0

或者您可以通过命令行添加最新版本:

flutter pub add sliver_snap

2. Install it

通过命令行安装包:

$ flutter pub get

3. Import it

现在可以在您的 Dart 代码中使用:

import 'package:sliver_snap/sliver_snap.dart';

基本用法

SliverSnap(
  onCollapseStateChanged: (isCollapsed, scrollingOffset, maxExtent) {},
  collapsedBackgroundColor: Colors.black,
  expandedBackgroundColor: Colors.transparent,
  backdropWidget: Image.network(
    "https://picsum.photos/800/1200",
    fit: BoxFit.cover,
  ),
  bottom: const PreferredSize(
    preferredSize: Size.fromHeight(50),
    child: Icon(
      Icons.directions_boat,
      color: Colors.blue,
      size: 45,
    ),
  ),
  expandedContentHeight: 400,
  expandedContent: const Center(
    child: Icon(
      Icons.ac_unit_sharp,
      color: Colors.amber,
      size: 70,
    ),
  ),
  collapsedContent: const Icon(Icons.car_crash, color: Colors.green, size: 45),
  body: const Material(
    elevation: 7,
    child: Placeholder(),
  ),
);

属性说明

Property Type Default Value Description
expandedContent Widget N/A 展开时显示的内容。是必需属性。
collapsedContent Widget N/A 收缩时显示的内容。是必需属性。
body Widget N/A 应用栏下方显示的内容。是必需属性。
pinned boolean true 应用栏是否固定在滚动视图顶部。更多信息请参阅 Flutter Docs
collapsedBarHeight double 60.0 收缩内容的高度。
animationDuration Duration 300 milliseconds 滚动动画的持续时间。
animationCurve Curve Curves.easeInOut 滚动动画的曲线。
snap boolean false 应用栏在滚动时的行为方式。更多信息请参阅 Flutter Docs
floating boolean false 应用栏在用户向应用栏滚动时是否立即可见。更多信息请参阅 Flutter Docs
stretch boolean false 应用栏是否拉伸以填充过滚动区域。更多信息请参阅 Flutter Docs
expandedContentHeight double? N/A 展开内容的高度。
bottom PreferredSizeWidget? N/A 显示在应用栏底部的小部件,例如 TabBar。该小部件必须实现 PreferredSizeWidget
automaticallyImplyLeading bool? false 控制 AppBar 的 leading 小部件。当设置为 true 时,框架将自动添加 leading 小部件;当设置为 false 时,不会自动添加。更多信息请参阅 Flutter Docs
leading Widget? N/A expandedContentcollapsedContent 开始处的领先小部件,通常是 IconIconButton。也可以是 BackButton
actions List<Widget> N/A collapsedContent 小部件之后显示的一排操作小部件。
backdropWidget Widget? N/A 应用栏下方显示的内容。通常只是页面内容。
expandedBackgroundColor Color? N/A expandedContent 小部件的背景颜色。
collapsedBackgroundColor Color? N/A collapsedContent 小部件的背景颜色。
scrollController ScrollController? N/A 可以传递自己的 scrollController 以进一步自定义应用栏。
scrollBehavior ScrollBehaviour? N/A 滚动小部件的行为,可以是 MaterialCupertino 滚动行为。
onCollapseStateChanged CollapsingStateCallback? N/A 当应用栏折叠或展开时触发的回调函数,可用于自定义动画和行为。
elevation double 0.0 应用栏的阴影高度。
forceElevated bool false 是否在内容未滚动到应用栏下方时也显示与 elevation 相匹配的阴影。默认为 false,即只有在应用栏显示在滚动内容上方时才应用阴影。

额外组件

1. Collapsed AppBar Content widget

用于创建自定义 collapsedContent 小部件。具有以下属性:

  • leading: collapsedContent 应用栏的领先小部件。
  • title: collapsedContent 应用栏中间的小部件。
  • trailing: collapsedContent 应用栏最右侧的小部件。
CollapsedAppBarContent(
  leading: const Text('Leading Widget'),
  title: const Text('title'),
  trailing: SizedBox(
    height: 40,
    child: Image.network(
      'https://picsum.photos/800/1200',
      fit: BoxFit.cover,
    ),
  ),
),

2. Expanded Content widget

用于创建自定义 expanded 小部件。具有以下属性:

  • leading: expandedContent 应用栏的领先小部件。
ExpandedContent(
  leading: const Text('Leading Widget'),
  child: const Text('Expanded Content'),
);

示例代码

import 'dart:io';

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

void main() async {
  runApp(const MyApp());
  if (Platform.isAndroid) {
    await FlutterDisplayMode.setHighRefreshRate();
  }
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: CustomScrollView(
          slivers: [
            SliverSnap(
              onCollapseStateChanged: (isCollapsed, scrollingOffset, maxExtent) {
                // 处理状态变化的逻辑
              },
              collapsedBackgroundColor: Colors.black,
              expandedBackgroundColor: Colors.transparent,
              backdropWidget: Image.network(
                "https://picsum.photos/800/1200",
                fit: BoxFit.cover,
              ),
              bottom: const PreferredSize(
                preferredSize: Size.fromHeight(50),
                child: Icon(
                  Icons.directions_boat,
                  color: Colors.blue,
                  size: 45,
                ),
              ),
              expandedContentHeight: 400,
              expandedContent: const Center(
                child: Icon(
                  Icons.ac_unit_sharp,
                  color: Colors.amber,
                  size: 70,
                ),
              ),
              collapsedContent: const Icon(Icons.car_crash, color: Colors.green, size: 45),
              body: const Material(
                elevation: 7,
                child: Placeholder(),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

更多信息

更多使用信息,请参考 示例代码

如果您遇到任何问题,请随时在 GitHub Issues 中提交问题或功能请求。欢迎提交 Pull Request。


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

1 回复

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


在Flutter中,sliver_snap 并不是一个官方的插件,但听起来它类似于一个用于 Sliver 列表项定位与吸附的库。如果你正在寻找一个插件来实现类似的效果,比如让 Sliver 列表中的某个项在用户滚动时能够吸附到屏幕边缘,那么你可以考虑使用 flutter_sticky_headers 或者通过自定义 Sliver 组件来实现。

不过,为了说明如何在 Flutter 中实现一个基本的滑动定位功能,我们可以使用 Flutter 自带的 SliverListScrollController 来创建一个简单的示例,这个示例将展示如何定位到列表中的特定项。请注意,这个示例不会直接提供“吸附”效果,但它是实现更复杂功能的基础。

以下是一个基本的 Flutter 应用示例,它展示了如何使用 ScrollController 跳转到 SliverList 中的特定项:

import 'package:flutter/material.dart';

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

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

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

class _MyHomePageState extends State<MyHomePage> {
  final ScrollController _scrollController = ScrollController();
  final List<String> _items = List.generate(100, (index) => 'Item $index');

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

  void _scrollToIndex(int index) {
    final SliverGeometry geometry = _getSliverGeometryAtIndex(index);
    if (geometry != null) {
      final double scrollOffset = geometry.paintExtent - geometry.scrollOffset;
      _scrollController.animateTo(
        scrollOffset,
        duration: Duration(milliseconds: 300),
        curve: Curves.easeInOut,
      );
    }
  }

  SliverGeometry? _getSliverGeometryAtIndex(int index) {
    final RenderSliver? sliver = _sliverContextAtIndex(index)?.findRenderObject() as RenderSliver?;
    if (sliver != null) {
      final SliverConstraints constraints = sliver.constraints;
      final SliverGeometry geometry = sliver.getGeometryForChildIndex(index);
      return geometry;
    }
    return null;
  }

  BuildContext? _sliverContextAtIndex(int index) {
    final List<SliverPersistentHeaderDelegate?>? headers = <SliverPersistentHeaderDelegate?>[]; // Not used in this example but can be extended for sticky headers
    final SliverMultiBoxAdaptorElement? element = _findSliverMultiBoxAdaptorElement(context);
    if (element != null) {
      final int firstIndex = element.firstChild!.index;
      final int lastIndex = element.lastChild!.index;
      if (index >= firstIndex && index <= lastIndex) {
        return element.childAfter(element.indexOf(element.firstChild!) + index - firstIndex)!;
      }
    }
    return null;
  }

  SliverMultiBoxAdaptorElement? _findSliverMultiBoxAdaptorElement(BuildContext context) {
    Element? element = context.findAncestorElementThatMatchesPredicate(
      (Element candidate) => candidate is SliverMultiBoxAdaptorElement,
    );
    return element as SliverMultiBoxAdaptorElement?;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('SliverSnap Example'),
      ),
      body: CustomScrollView(
        controller: _scrollController,
        slivers: <Widget>[
          SliverList(
            delegate: SliverChildBuilderDelegate(
              (BuildContext context, int index) {
                return ListTile(
                  title: Text(_items[index]),
                );
              },
              childCount: _items.length,
            ),
          ),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => _scrollToIndex(50), // Scroll to the 50th item
        tooltip: 'Scroll to Item 50',
        child: Icon(Icons.arrow_downward),
      ),
    );
  }
}

注意

  1. _scrollToIndex 方法尝试滚动到指定索引的项,但它依赖于 _getSliverGeometryAtIndex_sliverContextAtIndex 方法来获取 Sliver 项的几何信息。这些方法在这个简单示例中可能不会总是有效,特别是在复杂的 Sliver 布局中。
  2. 对于更复杂的“吸附”效果,你可能需要更深入地了解 Flutter 的 Sliver 架构,并可能需要自定义 Sliver 组件或使用第三方库。
  3. 在生产环境中,建议进行更全面的错误处理和边界情况检查。

如果你确实在寻找一个名为 sliver_snap 的特定插件,请确保你查找的是正确的包名或在 Flutter 社区中询问以获取更多信息。

回到顶部