首页 > 其他分享 >Flutter可滚动组件(1):Sliver

Flutter可滚动组件(1):Sliver

时间:2024-10-11 16:15:04浏览次数:1  
标签:Widget const 列表 组件 滚动 Flutter Sliver

一、常见滚定组件

Flutter 提供了多种滚动组件,可以用于处理各种滚动效果。

Sliver 的子组件都能滚动,但并不是所有能滚动的组件都是Sliver子组件。比如,ListView和Grid就不是Sliver子组件。

重要说3遍

ListView和Grid就 不是 Sliver子组件。

ListView和Grid就 不是 Sliver子组件。

ListView和Grid就 不是 Sliver子组件。


1.1 在 Flutter 中,可滚动组件通常由三个角色组成

  • Scrollable:一个可滚动组件的基类,它定义了一个可滚动组件所需要的基本行为和接口。比如 ListView 和 GridView
  • Viewport:表示一个视口,它用来显示可滚动组件中的内容。Viewport 可以是一个矩形,也可以是任意形状,它负责将滚动区域中的内容渲染到屏幕上。
  • Sliver:一个 Scrollable 的子组件,它是用来描述可滚动区域中的一段可滚动内容的。Sliver 可以是一个矩形,也可以是任意形状,它可以包含多个子组件,例如 SliverList、SliverGrid 等。

1.2 Sliver的子组件及其作用

Sliver 的子组件都能滚动

Sliver子组件 描述
SliverAppBar 可折叠的应用栏,随着滚动进行展开和收起
SliverList 垂直的线性列表,用于显示动态数量的列表项
SliverGrid 二维网格布局,可在水平和垂直方向上滚动
SliverToBoxAdapter 将普通的非 Sliver 组件包装为 Sliver 组件,用于在 Sliver 布局中使用
SliverFixedExtentList 与 SliverList 类似,但所有列表项的高度都是固定的,可提高性能
SliverPersistentHeader 创建一个持久化的 Header,始终可见,并可包含其他子组件
SliverPadding 为子组件提供填充,控制子组件与边界之间的间距
SliverOpacity 设置子组件的透明度,可根据滚动位置或其他条件调整子组件的显示效果
SliverAnimatedList 动态、带动画效果的列表,用于在滚动视图中显示数据的变化
SliverAnimatedOpacity 根据滚动位置或其他条件,以动画的方式调整子组件的透明度

二、Flutter 中的 Sliver

在 Flutter 中,Sliver 是一种特殊的 Widget,它可以用于创建可滚动的、高性能的列表或网格。相比于普通的列表或网格,使用 Sliver 可以提高滑动性能,减少内存占用,并且可以支持更多的交互效果。


2.1 Sliver 的基本概念

在 Flutter 中,Sliver 是指一种可以滚动的可视区域,它可以有多个子节点,每个子节点可以是一个 Widget 或者一个 LayoutBuilder。根据子节点的类型和滚动方向的不同,可以将 Sliver 分为以下几种类型:

  • SliverAppBar:一个可以随着滚动渐变、折叠、固定在顶部或底部的 AppBar。
  • SliverList:一个垂直方向的可滚动列表。
  • SliverGrid:一个网格布局的可滚动列表。
  • SliverToBoxAdapter:一个包含单个子节点的 Sliver,可以用于将一个普通的 Widget 包装成一个可滚动的 Widget。
  • SliverFillRemaining:一个占满剩余空间的 Sliver,通常用于在 CustomScrollView 中填充屏幕剩余的空间。

2.2 使用 Sliver 创建可滚动列表

在 Flutter 中,创建一个可滚动的列表通常需要使用 ListViewGridView。但是这些 Widget 的性能并不总是最优,尤其是在列表项较多时。相比之下,使用 Sliver 可以更好地控制列表项的渲染和排布,从而提高性能。


2.3 创建 SliverList

SliverList 是一个用于显示可滚动列表的 Sliver 组件,它可以高效地渲染大量的列表项,并且可以和其他 Sliver 组件一起使用,构建复杂的可滚动布局。与普通的列表组件不同,SliverList 不会提前将所有列表项都渲染出来,而是在滚动时动态地渲染当前可见的部分,从而节省内存和渲染时间。

下面是一个简单的例子,演示如何使用 SliverList 显示一个包含 50 个列表项的可滚动列表:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'SliverList Demo',
      home: Scaffold(
        body: CustomScrollView(
          slivers: <Widget>[
            SliverList(
              delegate: SliverChildBuilderDelegate(
                (BuildContext context, int index) {
                  debugPrint('Building item $index'); // 打印日志
                  return ListTile(
                    title: Text('Item $index'),
                    leading: CircleAvatar(child: Text('$index')),
                  );
                },
                childCount: 50,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

效果图如下所示:

Flutter_sliver_A.png


在这个例子中,我们创建了一个 CustomScrollView,其中包含了一个 SliverListSliverList 使用 SliverChildBuilderDelegate 来构建列表项,它会根据 childCount 属性的值来确定列表项的数量。在 SliverChildBuilderDelegate 中,我们可以使用 BuildContextindex 参数来构建每个列表项。在这个例子中,我们为每个列表项添加了一个圆形图标,以及一个显示编号的文本。当我们向上或向下滚动列表时,SliverList 会动态地渲染当前可见的列表项,从而保证了滚动的流畅性和性能。


2.4 创建 SliverGrid

SliverGrid 是一个用于显示网格布局的 Sliver 组件,它可以高效地渲染大量的网格项,并且可以和其他 Sliver 组件一起使用,构建复杂的可滚动布局。与普通的网格布局组件不同,SliverGrid 不会提前将所有网格项都渲染出来,而是在滚动时动态地渲染当前可见的部分,从而节省内存和渲染时间。

下面是一个例子,演示如何使用 SliverGrid 显示一个包含 50 个格子的网格布局:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'SliverGrid Demo',
      home: Scaffold(
        body: CustomScrollView(
          slivers: <Widget>[
            // 创建一个包含 50 个格子的 SliverGrid
            SliverGrid(
              gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
                // 指定每行包含 3 个格子
                crossAxisCount: 3,
              ),
              delegate: SliverChildBuilderDelegate(
                (BuildContext context, int index) {
                  // 构建格子
                  return Container(
                    color: Colors.blue[100 * (index % 9 + 1)],
                    alignment: Alignment.center,
                    child: Text('Grid $index'),
                  );
                },
                childCount: 50, // 格子数量
              ),
            ),
          ],
        ),
      ),
    );
  }
}

效果图如下所示:

Flutter_sliver_B.png


三、Sliver 的高级用法

除了基本的 Sliver 类型外,Flutter 还提供了一些高级的 Sliver 类型,例如 SliverPersistentHeaderSliverFillViewportSliverOverlapInjector


3.1 使用 SliverPersistentHeader 创建自定义 Header

SliverPersistentHeader 是一个可以自定义的 Header,它可以随着滚动渐变、折叠、固定在顶部或底部,并且可以包含任意的子节点。

与普通的头部或底部组件不同,SliverPersistentHeader 可以随着滚动而动态地改变自身的高度,从而实现更加灵活的布局效果。

下面是一个例子,演示如何使用 SliverPersistentHeader 实现一个固定在页面顶部的头部组件:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'SliverPersistentHeader Demo',
      home: Scaffold(
        appBar: AppBar(
          title: const Text('SliverPersistentHeader Demo'),
        ),
        body: CustomScrollView(
          slivers: <Widget>[
            // 创建一个固定在页面顶部的 SliverPersistentHeader
            SliverPersistentHeader(
              pinned: true, // 固定在页面顶部
              delegate: _MyHeaderDelegate(),
            ),
            // 添加一个普通的 SliverList
            SliverList(
              delegate: SliverChildBuilderDelegate(
                (BuildContext context, int index) {
                  return ListTile(
                    title: Text('Item $index'),
                    leading: CircleAvatar(child: Text('$index')),
                  );
                },
                childCount: 50,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

// 定义一个 SliverPersistentHeaderDelegate
class _MyHeaderDelegate extends SliverPersistentHeaderDelegate {
  @override
  Widget build(
      BuildContext context, double shrinkOffset, bool overlapsContent) {
    // 获取状态栏高度
    final double statusBarHeight = MediaQuery.of(context).padding.top;

    // 构建头部组件
    return Container(
      padding: EdgeInsets.only(top: statusBarHeight),
      color: Colors.blue,
      alignment: Alignment.center,
      child: const Text('Header'),
    );
  }

  @override
  double get maxExtent => 100.0; // 最大高度

  @override
  double get minExtent => 50.0; // 最小高度

  @override
  bool shouldRebuild(_MyHeaderDelegate oldDelegate) {
    return false; // 不需要重新构建
  }
}

效果图如下所示:

Flutter_sliver_A.gif


在这个例子中,我们创建了一个 CustomScrollView,其中包含了一个固定在页面顶部的 SliverPersistentHeader。我们使用 pinned 属性将头部组件固定在页面顶部,并使用 _MyHeaderDelegate 类来构建头部组件。在 _MyHeaderDelegate 中,我们实现了 buildmaxExtentminExtentshouldRebuild 四个方法,分别用于构建头部组件、指定最大和最小高度以及控制是否需要重新构建头部组件。在这个例子中,我们只是简单地为头部组件添加了一个背景颜色和一个文本。当我们向上或向下滚动列表时,头部组件会随着滚动而动态地改变自身的高度,从而实现了更加灵活的布局效果


不够吗?再来一个例子

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'SliverPersistentHeader Demo',
      home: Scaffold(
        body: CustomScrollView(
          slivers: <Widget>[
            // 创建一个固定在页面顶部的 SliverPersistentHeader
            SliverPersistentHeader(
              pinned: true, // 固定在页面顶部
              delegate: _MyHeaderDelegate(),
            ),
            // 添加一个普通的 SliverList
            SliverList(
              delegate: SliverChildBuilderDelegate(
                (BuildContext context, int index) {
                  return ListTile(
                    title: Text('Item $index'),
                    leading: CircleAvatar(child: Text('$index')),
                  );
                },
                childCount: 50,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

// 定义一个 SliverPersistentHeaderDelegate
class _MyHeaderDelegate extends SliverPersistentHeaderDelegate {
  @override
  Widget build(
      BuildContext context, double shrinkOffset, bool overlapsContent) {
    // 计算当前 Header 的高度
    double height = maxExtent - shrinkOffset;
    if (height < minExtent) {
      height = minExtent;
    }

    // 计算当前 Header 的背景颜色
    final double alpha = (maxExtent - height) / (maxExtent - minExtent);
    final Color backgroundColor = Colors.blue.withOpacity(alpha);

    // 构建 Header
    return Stack(
      fit: StackFit.expand,
      children: [
        // 背景图片
        Image.network(
          'https://picsum.photos/id/1/800/600',
          fit: BoxFit.cover,
        ),
        // 渐变遮罩层
        Container(
          decoration: BoxDecoration(
            gradient: LinearGradient(
              begin: Alignment.topCenter,
              end: Alignment.bottomCenter,
              colors: [
                backgroundColor.withOpacity(0.5),
                backgroundColor,
              ],
            ),
          ),
        ),
        // 折叠的内容
        Positioned(
          top: 100 - shrinkOffset,
          left: 16.0,
          right: 16.0,
          child: Opacity(
            opacity: 1 - alpha,
            child: const Text(
              'Header',
              style: TextStyle(
                  fontSize: 24.0,
                  fontWeight: FontWeight.bold,
                  color: Colors.white),
            ),
          ),
        ),
      ],
    );
  }

  @override
  double get maxExtent => 200.0; // 最大高度

  @override
  double get minExtent => 50.0; // 最小高度

  @override
  bool shouldRebuild(_MyHeaderDelegate oldDelegate) {
    return false; // 不需要重新构建
  }
}

效果图如下所示:

Flutter_sliver_B.gif


3.2 SliverPersistentHeader 对比 NestedScrollView

其实,NestedScrollView 也能实现类似的功能。

选择使用 SliverPersistentHeader 还是 NestedScrollView 取决于你的实际需求。下面是一些参考因素:

  • 如果你只需要一个简单的固定在顶部的 Header,那么使用 SliverPersistentHeader 可能更加简单明了。
  • 如果你需要在 Header 和内容之间添加一些复杂的交互逻辑,比如下拉刷新、上拉加载、折叠、渐变等效果,那么使用 NestedScrollView 可能更加灵活方便。
  • 如果你需要在页面中嵌套多个滚动组件,并且需要让它们进行联动,那么使用 NestedScrollView 是必要的选择。

总的来说,SliverPersistentHeaderNestedScrollView 都是非常强大和灵活的 Flutter 组件,可以帮助开发者实现各种复杂的布局效果。你可以根据自己的实际需求来选择使用哪一个。

四、使用 SliverFillViewport 创建全屏的可滚动区域

SliverFillViewport 是 Flutter 中一个重要的 Widget,它的作用是使其子元素填充视口(也就是屏幕可见的部分)。

这个 Widget 最常见的用途是在 PageView 或者 CustomScrollView 里使用,用来创建用户可以左右滑动查看的各种 "pages" 或者 "cards"。

SliverFillViewport 的主要特点是它可以让其子元素以特定的方式来填充滚动视图。举例来说,如果你希望在用户滚动视图时,每个元素都可以占据滚动视图的整个视口,那么 SliverFillViewport 就是一个很好的选择。

简单的例子:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'SliverFillViewport 示例',
      home: Scaffold(
        appBar: AppBar(title: const Text('SliverFillViewport 示例')),
        body: Container(
          width: 300,
          height: 400,
          color: Colors.grey,
          child: CustomScrollView(
            slivers: <Widget>[
              SliverFillViewport(
                viewportFraction: 0.2, // 子组件高度占满视口的比例
                delegate: SliverChildListDelegate(
                  [
                    Container(color: Colors.blue),
                    Container(color: Colors.green),
                    Container(color: Colors.yellow),
                  ],
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

在这个示例中,我们将 viewportFraction 属性设置为 0.2,表示子组件的高度占视口高度的 20%。

运行该代码,你将看到在 300x400 的容器内,子组件的高度只占据了视口高度的 20%,而其余空间则留白。

这个示例演示了将 viewportFraction 属性设置为不同值时,子组件占用视口高度的比例发生变化的效果。

效果图如下所示:

Flutter_sliver_C.png


再来一个例子:

import 'package:flutter/material.dart';

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

// 定义旅游景点类
class TouristAttraction {
  final String name; // 名称
  final String description; // 描述
  final Color color; // 背景色

  TouristAttraction(
      {required this.name, required this.description, required this.color});
}

class MyApp extends StatelessWidget {
  MyApp({super.key});
  // 旅游景点列表
  final List<TouristAttraction> attractions = [
    TouristAttraction(
      name: '埃菲尔铁塔',
      description:
          '埃菲尔铁塔是法国巴黎的一座铁塔,位于马斯菲尔德公园(Champ de Mars)内,是巴黎地标之一。铁塔的设计者是古斯塔夫·埃菲尔,铁塔的建造是为了纪念法国大革命一百周年。',
      color: Colors.lightBlue, // 设置该景点的颜色
    ),
    TouristAttraction(
      name: '自由女神像',
      description:
          '自由女神像是位于美国纽约港的一座巨型铜像,是纽约市的象征之一,也是美国和法国友谊的象征。这座雕像是由法国雕塑家弗雷德里克·奥古斯特·巴托尔迪设计并制作,1886年10月28日揭幕。',
      color: Colors.pink, // 设置该景点的颜色
    ),
    TouristAttraction(
      name: '泰姬陵',
      description:
          '泰姬陵是位于印度北部城市阿格拉的一座白色大理石陵墓,于17世纪由莫卧儿帝国皇帝沙贾汗为其逝去的爱妃慕塔芝·马哈尔而建造。泰姬陵被认为是世界上最美的建筑之一。',
      color: Colors.orange, // 设置该景点的颜色
    ),
    TouristAttraction(
      name: '长城',
      description:
          '长城是一道蜿蜒于中国北部的防御工事,由石头、砖头、土坯等材料砌成,是中国古代的一项伟大工程。长城的修建始于公元前7世纪,历经2000多年的修建和扩建,成为了世界上最长的城墙。',
      color: Colors.yellow, // 设置该景点的颜色
    ),
    TouristAttraction(
      name: '比萨斜塔',
      description:
          '比萨斜塔是意大利比萨市的一座独立的钟楼,以其明显的倾斜而闻名于世。斜塔的建造始于12世纪,由于斜塔的基础建设不够坚固,导致了斜塔的倾斜。',
      color: Colors.green, // 设置该景点的颜色
    ),
  ];

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'SliverFillViewport 演示',
      home: Scaffold(
        body: CustomScrollView(
          slivers: <Widget>[
            const SliverAppBar(
              title: Text('旅游景点'),
              floating: true,
            ),
            SliverFillViewport(
              delegate: SliverChildBuilderDelegate(
                // 构建子元素
                (BuildContext context, int index) {
                  final attraction = attractions[index];
                  return Container(
                    padding: const EdgeInsets.all(16.0),
                    color: attraction.color, // 设置背景色
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: <Widget>[
                        Text(
                          attraction.name,
                          style: const TextStyle(
                            fontSize: 24,
                            fontWeight: FontWeight.bold,
                            color: Colors.white,
                          ),
                        ),
                        const SizedBox(height: 8),
                        Text(
                          attraction.description,
                          style: const TextStyle(
                            fontSize: 16,
                            color: Colors.white,
                          ),
                        ),
                      ],
                    ),
                  );
                },
                childCount: attractions.length,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

效果图如下所示:

Flutter_sliver_C.gif


在这个例子中,我们创建了一个 TouristAttraction 类,用于表示旅游景点的名称和描述。我们将多个景点添加到 attractions 列表中,并在 CustomScrollView 中使用 SliverFillViewport 来展示它们的介绍。

SliverFillViewport 中,我们使用 SliverChildBuilderDelegate 来构建子元素,并通过 childCount 属性指定子元素的数量。在 SliverChildBuilderDelegate 的回调函数中,我们遍历 attractions 列表,并根据每个景点的名称和描述创建一个子元素。

由于 SliverFillViewport 会铺满整个 Viewport,因此所有的子元素都会占用整个屏幕。最后,我们将 CustomScrollView 放到 Scaffoldbody 中,并在 SliverAppBar 中设置标题和浮动属性。

五、使用 SliverOverlapInjector 实现重叠效果

SliverOverlapInjector 是一个特殊的 Sliver Widget,用于在两个 Sliver 之间插入一个非滚动的 Widget,这个 Widget 可以覆盖在上一个 Sliver 的底部,同时也可以被下一个 Sliver 的内容覆盖。这个 Widget 主要用于解决两个 Sliver 之间的重叠问题。

最常见的使用场景是在 Flutter 的自定义滚动视图(CustomScrollView)中,通常在具有弹性头部(SliverAppBar)的列表上方添加额外的内容,这些内容将在列表滚动时滑入视图并在列表内容滚动到顶部时停止。

以下是一个简单的示例,用于演示如何使用 SliverOverlapInjector,我已添加详细的中文注释以帮助理解:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'SliverOverlapInjector 示例',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: "SliverOverlapInjector 示例"),
    );
  }
}

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

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final GlobalKey<NestedScrollViewState> _key =
      GlobalKey<NestedScrollViewState>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: NestedScrollView(
        key: _key,
        headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
          return <Widget>[
            SliverAppBar(
              title: Text(widget.title),
              expandedHeight: 200.0,
              floating: false,
              pinned: true,
              flexibleSpace: FlexibleSpaceBar(
                background: Image.network('https://picsum.photos/400/200',
                    fit: BoxFit.cover),
              ),
            ),
          ];
        },
        body: Builder(
          builder: (BuildContext context) {
            return CustomScrollView(
              slivers: <Widget>[
                SliverOverlapAbsorber(
                  handle:
                      NestedScrollView.sliverOverlapAbsorberHandleFor(context),
                  sliver: SliverList(
                    delegate: SliverChildBuilderDelegate(
                      (BuildContext context, int index) {
                        return ListTile(
                          title: Text('列表项 #$index'),
                        );
                      },
                      childCount: 50,
                    ),
                  ),
                ),
                SliverOverlapInjector(
                  handle:
                      NestedScrollView.sliverOverlapAbsorberHandleFor(context),
                ),
              ],
            );
          },
        ),
      ),
    );
  }
}

效果图如下所示:

Flutter_sliver_D.gif


在这个示例中,SliverAppBar 提供了一个可以伸展的 AppBar,SliverOverlapAbsorber 吸收了其中的重叠部分,并通过一个 NestedScrollView.sliverOverlapAbsorberHandleFor 共享给 SliverOverlapInjector。这样,当我们在 CustomScrollView 中滚动时,SliverAppBar 下方的列表会根据滚动的情况逐渐滑入视图,形成重叠效果。

六、总结

在 Flutter 中,`Sliver以上是关于使用 Sliver 构建可滚动区域的基础介绍和示例代码,希望能够帮助你更好地理解和使用 Sliver 相关的 Widget。使用 Sliver 可以方便地构建出各种复杂的可滚动效果,同时也可以通过 SliverOverlapInjector 实现重叠效果,为用户提供更加丰富的交互体验。如果你有任何问题或疑问,欢迎继续提问。


标签:Widget,const,列表,组件,滚动,Flutter,Sliver
From: https://www.cnblogs.com/linuxAndMcu/p/18458638

相关文章

  • Flutter容器(6):页面骨架(Scaffold)
    Material组件库提供了丰富多样的组件,这里介绍一下最常用的Scaffold组件,其余的读者可以自行查看文档或FlutterGallery中Material组件部分的示例。注意:FlutterGallery是Flutter官方提供的FlutterDemo,源码位于flutter源码中的examples目录下,笔者强烈建议用户将F......
  • Flutter可滚动组件(5):PageView与页面缓存
    一、PageView如果要实现页面切换和Tab布局,我们可以使用PageView组件。需要注意,PageView是一个非常重要的组件,因为在移动端开发中很常用,比如大多数App都包含Tab换页效果、图片轮动以及抖音上下滑页切换视频功能等等,这些都可以通过PageView轻松实现。PageView({Key?......
  • Flutter可滚动组件(4):GridView
    网格布局是一种常见的布局类型,GridView组件正是实现了网格布局的组件,下面重点介绍一下它的用法。一、默认构造函数GridView可以构建一个二维网格列表,其默认构造函数定义如下:GridView({Key?key,AxisscrollDirection=Axis.vertical,boolreverse=false,......
  • Flutter可滚动组件(3):滚动监听及控制
    前一篇博客介绍了Flutter中常用的可滚动组件,也说过可以用ScrollController来控制可滚动组件的滚动位置,本节先介绍一下ScrollController,然后以ListView为例,展示一下ScrollController的具体用法。最后,再介绍一下路由切换时如何来保存滚动位置。一、ScrollControllerScrollContro......
  • Flutter可滚动组件(8):CustomScrollView 和 Slivers
    CustomScrollView前面介绍的ListView、GridView、PageView都是一个完整的可滚动组件,所谓完整是指它们都包括Scrollable、Viewport和Sliver。假如我们想要在一个页面中,同时包含多个可滚动组件,且使它们的滑动效果能统一起来,比如:我们想将已有的两个沿垂直方向滚动的ListView......
  • Flutter可滚动组件(7):TabBarView
    TabBarView是Material组件库中提供了Tab布局组件,通常和TabBar配合使用。一、TabBarViewTabBarView封装了PageView,它的构造方法很简单TabBarView({Key?key,requiredthis.children,//tab页this.controller,//TabControllerthis.physics,this.dra......
  • Flutter可滚动组件(6):可滚动组件子项缓存
    本节将介绍可滚动组件中缓存指定子项的通用方案。首先回想一下,在介绍ListView时,有一个addAutomaticKeepAlives属性我们并没有介绍,如果addAutomaticKeepAlives为true,则ListView会为每一个列表项添加一个AutomaticKeepAlive父组件。虽然PageView的默认构造函数和PageVi......
  • Flutter功能性组件(1):对话框
    Material库提供了三种基本对话框组件AlertDialog通常用于提示型对话框SimpleDialog通常用于列表型对话框Dialog通常用于自定义布局元素的对话框弹出对话框时,调用showDialog函数,将对话框控件传入,由于对话框本身是路由,所以关闭对话框时,需使用Navigator.of(context).pop......
  • Flutter可滚动组件(9):嵌套可滚动组件 NestedScrollView
    一、NestedScrollView上一节中,我们知道CustomScrollView只能组合Sliver,如果有孩子也是一个可滚动组件(通过SliverToBoxAdapter嵌入)且它们的滑动方向一致时便不能正常工作。为了解决这个问题,Flutter中提供了一个NestedScrollView组件,它的功能是组合(协调)两个可滚动组件,下面我......
  • Flutter功能性组件(2):弹出框
    一、showModalBottomSheet(模态底部弹出框)showModalBottomSheet用于显示一个模态底部弹出框。属性解析:Future<T?>showModalBottomSheet<T>({requiredBuildContextcontext,//表示底部弹出框所处的上下文,通常来自当前widget。requiredWidgetBuilderbuilder,//用......