flutter sliver 多种滚动组合开发指南

2024-02-23 08:20

本文主要是介绍flutter sliver 多种滚动组合开发指南,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

flutter sliver 多种滚动组合开发指南

视频

https://youtu.be/4mho1kZ_YQU

https://www.bilibili.com/video/BV1WW4y1d7ZC/

前言

有不少同学工作中遇到需要把几个不同滚动行为组件(顶部 appBar、内容固定块、tabBar 切换、tabBarView视图、自适应高度、横向滚动)黏贴成一个组件。

这时候就需要 sliver 出场了,本文将会写一个多种滚动的组合。

业务场景分析

下面是淘宝、小红书的常见情况。

原文 https://ducafecat.com/blog/flutter-sliver-scroll

知识点 sliver

Sliver 是 Flutter 中用于构建可滚动视图的基本构建块之一。Sliver 是可滚动区域中的一小部分,具有固定的大小和位置,可以根据需要动态加载和卸载。Sliver 通常用于创建高性能、高度灵活的可滚动视图,例如列表、网格、瀑布流等。

在 Flutter 中,有许多不同类型的 Sliver 组件,每个组件都有特定的作用和用途。下面是一些常见的 Sliver 组件:

  • SliverAppBar:一个带有滚动效果的应用栏,可以在向上滚动时隐藏,并在向下滚动时显示。
  • SliverList:将子组件放置在一个垂直列表中,可以根据需要动态加载和卸载列表项。
  • SliverGrid:将子组件放置在一个网格中,可以根据需要动态加载和卸载网格项。
  • SliverPadding:为子组件提供填充,以使它们与其他 Sliver 组件的大小和位置保持一致。
  • SliverToBoxAdapter:将一个普通的组件包装成一个 Sliver 组件,以便将其放置在 CustomScrollView 中。

参考

步骤

第一步:Sliver 横向滚动

lib/page.dart

  Widget _mainView() {
    return CustomScrollView(
      slivers: [
        // 横向滚动
        SliverToBoxAdapter(
          child: SizedBox(
            height: 100,
            child: PageView(
              children: [
                Container(
                  color: Colors.yellow,
                  child: const Center(child: Text('横向滚动')),
                ),
                Container(color: Colors.green),
                Container(color: Colors.blue),
              ],
            ),
          ),
        ),
        ...

SliverToBoxAdapter 进行包装才能 slivers 使用。

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Sliver Scroll')),
      body: _mainView(),
    );
  }

第二步:固定高度的 tabView

    return CustomScrollView(
      slivers: [
      ...
        // 固定高度内容
        SliverToBoxAdapter(
          child: Container(
            height: 200,
            color: Colors.greenAccent,
            child: const Center(child: Text('固定高度内容')),
          ),
        ),
        // tabView 内容
        SliverToBoxAdapter(
          child: DefaultTabController(
            length: 3,
            child: Column(
              children: [
                const TabBar(
                  tabs: [
                    Tab(text: 'Tab 1'),
                    Tab(text: 'Tab 2'),
                    Tab(text: 'Tab 3'),
                  ],
                ),
                SizedBox(
                  height: 200,
                  child: TabBarView(
                    children: [
                      Container(color: Colors.yellow),
                      Container(color: Colors.green),
                      Container(color: Colors.blue),
                    ],
                  ),
                ),
              ],
            ),
          ),
        ),

外层嵌套 DefaultTabController ,才能让 TabBar、TabBarView 顺利工作。

第三步:自适应高度的 tabView

实现 SliverPersistentHeaderDelegate 抽象类

class _SliverDelegate extends SliverPersistentHeaderDelegate {
  _SliverDelegate({
    required this.minHeight,
    required this.maxHeight,
    required this.child,
  });

  final double minHeight; //最小高度
  final double maxHeight; //最大高度
  final Widget child;

  @override
  double get minExtent => minHeight;

  @override
  double get maxExtent => max(maxHeight, minHeight);

  @override
  Widget build(
      BuildContext context, double shrinkOffset, bool overlapsContent) {
    return SizedBox.expand(child: child);
  }

  @override //是否需要重建
  bool shouldRebuild(_SliverDelegate oldDelegate) {
    return maxHeight != oldDelegate.maxHeight ||
        minHeight != oldDelegate.minHeight ||
        child != oldDelegate.child;
  }
}

编写固定头部 sliver 组件

  Widget _buildPersistentHeader(Widget child,
          {double? minHeight, double? maxHeight}) =>
      SliverPersistentHeader(
          pinned: true,
          delegate: _SliverDelegate(
            minHeight: minHeight ?? 40.0,
            maxHeight: maxHeight ?? 40.0,
            child: child,
          ));

定义 TabController

class _MyPageViewState extends State<MyPageViewwith TickerProviderStateMixin {
 ...

混入 TickerProviderStateMixin

  late TabController _tabController;
  @override
  void initState() {
    _tabController = TabController(length: 3, vsync: this);
    super.initState();
  }
  @override
  void dispose() {
    _tabController.dispose(); // 释放内存
    super.dispose();
  }

加入 slivers

  Widget _mainView() {
    return CustomScrollView(
      slivers: [
        ...
        
    // TabBar 固定
        _buildPersistentHeader(TabBar(
          controller: _tabController,
          tabs: const [
            Tab(text: 'Tab 1'),
            Tab(text: 'Tab 2'),
            Tab(text: 'Tab 3'),
          ],
        )),

使用 SliverFillRemaining 来撑开剩余空间

        // TabBarView 自适应高度
        SliverFillRemaining(
          child: TabBarView(
            controller: _tabController,
            children: [
              // 第一个选项卡的内容
              ListView.builder(
                itemCount: 20,
                itemBuilder: (BuildContext context, int index) {
                  return ListTile(title: Text('Item $index'));
                },
              ),
              // 第二个选项卡的内容
              ListView.builder(
                itemCount: 10,
                itemBuilder: (BuildContext context, int index) {
                  return ListTile(title: Text('Item $index'));
                },
              ),
              // 第三个选项卡的内容
              ListView.builder(
                itemCount: 5,
                itemBuilder: (BuildContext context, int index) {
                  return ListTile(title: Text('Item $index'));
                },
              ),
            ],
          ),
        ),

SliverFillRemaining 是一个可以填充剩余空间的 sliver 组件,它可以将子组件放置在视图区域的剩余空间中,并自动调整子组件的大小以填充整个空间。通常情况下,SliverFillRemaining 用于在滚动视图中放置一个占满整个视图区域的组件,例如底部栏或页脚。

第四步:子 tabBar

还可以加入子 tabBar 组成父子选项切换

        // 子 TabBar 固定
        _buildPersistentHeader(TabBar(
          controller: _tabController,
          tabs: const [
            Tab(text: 'subTab 1'),
            Tab(text: 'subTab 2'),
            Tab(text: 'subTab 3'),
          ],
        )),

父子 tabBar 中间再加一个固定块,查看滚动效果

        // 固定高度内容
        SliverToBoxAdapter(
          child: Container(
            height: 100,
            color: Colors.greenAccent,
            child: const Center(child: Text('固定高度内容')),
          ),
        ),

最后:底部再加入 SliverList

我们在底部再加一个 list 模块,看看效果。

  Widget _mainView() {
    return CustomScrollView(
      slivers: [
        ...
        
        // 固定高度内容
        SliverToBoxAdapter(
          child: Container(
            height: 200,
            color: Colors.greenAccent,
            child: const Center(child: Text('固定高度内容')),
          ),
        ),

        // 列表 100 行
        SliverList(
          delegate: SliverChildBuilderDelegate(
            (BuildContext context, int index) {
              return ListTile(title: Text('Item $index'));
            },
            childCount: 100,
          ),
        ),

代码

https://github.com/ducafecat/flutter_develop_tips/tree/main/flutter_application_sliver_scroll

小结

使用 Sliver 组件后我们确实把几种滚动给黏贴上了,但是不难发现过于复杂的滚动,用户体验方面还是要考虑的。

不能只为了堆积功能。

感谢阅读本文

如果我有什么错?请在评论中让我知道。我很乐意改进。


© 猫哥 ducafecat.com

end

这篇关于flutter sliver 多种滚动组合开发指南的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/738039

相关文章

Java中String字符串使用避坑指南

《Java中String字符串使用避坑指南》Java中的String字符串是我们日常编程中用得最多的类之一,看似简单的String使用,却隐藏着不少“坑”,如果不注意,可能会导致性能问题、意外的错误容... 目录8个避坑点如下:1. 字符串的不可变性:每次修改都创建新对象2. 使用 == 比较字符串,陷阱满

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后

使用 sql-research-assistant进行 SQL 数据库研究的实战指南(代码实现演示)

《使用sql-research-assistant进行SQL数据库研究的实战指南(代码实现演示)》本文介绍了sql-research-assistant工具,该工具基于LangChain框架,集... 目录技术背景介绍核心原理解析代码实现演示安装和配置项目集成LangSmith 配置(可选)启动服务应用场景

查询SQL Server数据库服务器IP地址的多种有效方法

《查询SQLServer数据库服务器IP地址的多种有效方法》作为数据库管理员或开发人员,了解如何查询SQLServer数据库服务器的IP地址是一项重要技能,本文将介绍几种简单而有效的方法,帮助你轻松... 目录使用T-SQL查询方法1:使用系统函数方法2:使用系统视图使用SQL Server Configu

SQL Server数据库迁移到MySQL的完整指南

《SQLServer数据库迁移到MySQL的完整指南》在企业应用开发中,数据库迁移是一个常见的需求,随着业务的发展,企业可能会从SQLServer转向MySQL,原因可能是成本、性能、跨平台兼容性等... 目录一、迁移前的准备工作1.1 确定迁移范围1.2 评估兼容性1.3 备份数据二、迁移工具的选择2.1

基于Python开发PPTX压缩工具

《基于Python开发PPTX压缩工具》在日常办公中,PPT文件往往因为图片过大而导致文件体积过大,不便于传输和存储,所以本文将使用Python开发一个PPTX压缩工具,需要的可以了解下... 目录引言全部代码环境准备代码结构代码实现运行结果引言在日常办公中,PPT文件往往因为图片过大而导致文件体积过大,

在 Windows 上安装 DeepSeek 的完整指南(最新推荐)

《在Windows上安装DeepSeek的完整指南(最新推荐)》在Windows上安装DeepSeek的完整指南,包括下载和安装Ollama、下载DeepSeekRXNUMX模型、运行Deep... 目录在www.chinasem.cn Windows 上安装 DeepSeek 的完整指南步骤 1:下载并安装

nginx-rtmp-module构建流媒体直播服务器实战指南

《nginx-rtmp-module构建流媒体直播服务器实战指南》本文主要介绍了nginx-rtmp-module构建流媒体直播服务器实战指南,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有... 目录1. RTMP协议介绍与应用RTMP协议的原理RTMP协议的应用RTMP与现代流媒体技术的关系2

Spring Boot统一异常拦截实践指南(最新推荐)

《SpringBoot统一异常拦截实践指南(最新推荐)》本文介绍了SpringBoot中统一异常处理的重要性及实现方案,包括使用`@ControllerAdvice`和`@ExceptionHand... 目录Spring Boot统一异常拦截实践指南一、为什么需要统一异常处理二、核心实现方案1. 基础组件