Flutter嵌套布局插件nester的使用

Flutter嵌套布局插件nester的使用

nester

Flutter库用于将一个Widget列表转换为一组嵌套的Widget。这是一个美化插件,以简化代码语法。

特性

  • 简化代码语法
  • 可以像处理普通列表一样管理
  • 可以像处理队列一样管理

安装

添加依赖

dependencies:
  nester: ^1.2.1

导入包

import 'package:nester/nester.dart';

示例用法

NESTER LIST

将作为简单的列表处理。每个项目在列表中只允许有一个"next"引用。这是使用Nester最简单的方式。建议在你的列表中大多数情况下只有一个子Widget时使用。

原始代码

return MaterialApp(
  title: 'Flutter Demo',
  theme: ThemeData(
    primarySwatch: Colors.blue,
  ),
  home: Scaffold(
    appBar: AppBar(
      title: const Text("Example"),
    ),
    body: Padding(
      padding: const EdgeInsets.all(20),
      child: Container(
        color: Colors.black12,
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: const <Widget>[Text("Just a description")],
          ),
        ),
      ),
    ),
  ),
);

使用Nester

return Nester.list([
  (next) => MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(primarySwatch: Colors.blue),
        home: next,
      ),
  (next) => Scaffold(
        appBar: AppBar(title: const Text("Example")),
        body: next,
      ),
  (next) => Padding(
        padding: const EdgeInsets.all(20),
        child: next,
      ),
  (next) => Container(
        color: Colors.black12,
        child: next,
      ),
  (next) => Center(child: next),
  (_) => Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: const <Widget>[Text("Just a text")],
      ),
]);

注意: 列表中的最后一个next项将始终是一个空的Container对象。因此传递它是多余的。


NESTER QUEUE

Widget列表将被当作队列处理。每次"next"调用都会消耗列表中的下一个元素。这在你使用包含多个子Widget的Widget时非常有用。

原始代码

return MaterialApp(
  title: 'Flutter Demo',
  theme: ThemeData(primarySwatch: Colors.blue),
  home: Scaffold(
    appBar: AppBar(
      title: const Text("Example"),
    ),
    body: Padding(
      padding: const EdgeInsets.all(50),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: const [
          Text("Left", textAlign: TextAlign.left),
          Text("Center", textAlign: TextAlign.center),
          Text("Right", textAlign: TextAlign.right),
        ],
      ),
    ),
  ),
);

使用Nester

return Nester.queue([
  (next) => MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(primarySwatch: Colors.blue),
        home: next(),
      ),
  (next) => Scaffold(
        appBar: next() as PreferredSizeWidget,
        body: next(),
      ),
  (_) => AppBar(title: const Text("Example")),
  (next) => Padding(
        padding: const EdgeInsets.all(50),
        child: next(),
      ),
  (next) => Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: next(take: 3), // 或者 [ next(), next(), next() ],
      ),
  (_) => const Text("Left", textAlign: TextAlign.left),
  (_) => const Text("Center", textAlign: TextAlign.center),
  (_) => const Text("Right", textAlign: TextAlign.right),
]);

Skip 和 Take

next({int skip, int take})函数接受两个参数。

  • 参数skip会跳过队列列表中的n个调用。请注意,该函数不会检查嵌套调用,只是跳过列表中的下一个n个项目。skip总是先于take应用。
  • 参数take会消耗同一级别的n个项目。如果一个项目有嵌套调用,则不会被计算为已消耗。结果将是一个Widget数组。

约束条件

  • 如果skiptake小于0,则被视为0。
  • 如果skip不是null或0且take为null,则返回一个空的Container

抛出范围异常

queue构造函数接受throwRangeException(默认值为false)来避免RangeError检查。如果为true,则每次调用next超出列表边界时都会抛出RangeError异常。

当使用take参数时,结果数组不会超过列表中剩余项目的数量。如果不使用takenext调用超出列表边界,则返回一个空的Container


深度在队列模式下

使用skiptake参数可能会造成混淆,因此编写一些示例来更好地解释它们的行为。

假设有一个布尔变量trigger用于跳过Column组件中的某些项。

return Nester.queue([
  ...,
 (next) => Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: [
          next(skip: trigger ? 0: 2),
          next(),
          next(),
        ]),
  (next) => Padding(..., child: next()),
  (_) => const Text("If trigger true"),
  (_) => const Text("Always show"),
  (_) => const Text("Always show"),
]);

或者

return Nester.queue([
  ...,
 (next) => Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: []
          ..addAll(next(skip: trigger ? 0: 2, take: trigger ? 1: 0))
          ..addAll(next(take: 2)),
        ),
  (next) => Padding(..., child: next()),
  (_) => const Text("If trigger true"),
  (_) => const Text("Always show"),
  (_) => const Text("Always show"),
]);

如果triggertrue,则skip为0且take为1。如果triggerfalse,则skip为2且take为0。

为什么skip为2?

因为skip不会进入树中检查嵌套项。它只会跳过原始列表中的项。因此需要跳过下一个PaddingText(两个项)。而take会消耗所有树中的项。take为1意味着消耗下一个Padding然后消耗下一个Text(两个项)。

为什么使用addAll?

因为在使用take参数时,结果总是会是一个Widget数组,即使取值为0或1。


NESTER EXTENDED

Queue的一个扩展。将以与queue相同的方式处理,但通过在next函数中添加一个额外的参数来传递dynamic值。

return Nester.extended([
  (next, _) => MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(primarySwatch: Colors.blue),
        home: next(),
      ),
  (next, _) => Scaffold(
        appBar: next(param: "Example") as PreferredSizeWidget,
        body: next(),
      ),
  (_, title) => AppBar(title: Text(title)),
  (next, _) => Padding(
        padding: const EdgeInsets.all(50),
        child: next(),
      ),
  (next, _) => Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: next(take: 3, param: ["Left", "Center", "Right"]),
      ),
  (_, param) => Text(param[0], textAlign: TextAlign.left),
  (_, param) => Text(param[1], textAlign: TextAlign.center),
  (_, param) => Text(param[2], textAlign: TextAlign.right),
]);

更多关于Flutter嵌套布局插件nester的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter嵌套布局插件nester的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter中使用nested_scroll_view插件(虽然nester不是Flutter官方或广泛认知的插件名,但基于您的要求,我假设您指的是实现嵌套滚动功能的插件或模式,这在Flutter中通常通过NestedScrollView实现)的示例代码。

NestedScrollView是Flutter中用于创建嵌套滚动视图的强大组件,它允许内部滚动视图(如ListView)与外部滚动视图(如Column中包含的其他可滚动部件)协同工作。

以下是一个简单的示例,展示了如何使用NestedScrollView结合SliverAppBarSliverList来实现一个带有可折叠工具栏的嵌套布局:

import 'package:flutter/material.dart';

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

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

class NestedScrollViewDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('NestedScrollView Demo'),
      ),
      body: NestedScrollView(
        headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
          return <Widget>[
            SliverAppBar(
              title: Text('SliverAppBar'),
              pinned: true,
              expandedHeight: 200.0,
              flexibleSpace: FlexibleSpaceBar(
                background: Image.network(
                  'https://via.placeholder.com/1500x500',
                  fit: BoxFit.cover,
                ),
              ),
              actions: <Widget>[
                IconButton(
                  icon: Icon(Icons.search),
                  tooltip: 'Search',
                  onPressed: () {},
                ),
              ],
            ),
          ];
        },
        body: Builder(
          builder: (BuildContext context) {
            return Column(
              children: <Widget>[
                Container(
                  color: Colors.amber[600],
                  height: 50,
                  child: Center(
                    child: Text('Fixed Header'),
                  ),
                ),
                Expanded(
                  child: ListView.builder(
                    itemCount: 50,
                    itemBuilder: (context, index) {
                      return ListTile(
                        title: Text('Item $index'),
                      );
                    },
                  ),
                ),
              ],
            );
          },
        ),
      ),
    );
  }
}

代码解释

  1. NestedScrollView:

    • headerSliverBuilder: 构建头部Sliver组件的回调。在这个例子中,我们返回了一个SliverAppBar
    • body: 内部滚动视图,通常是一个不可滚动的组件,如Column,其中可以包含固定高度的组件和一个可扩展的滚动视图(如ListView)。
  2. SliverAppBar:

    • pinned: 当true时,AppBar会在滚动时保持固定在顶部。
    • expandedHeight: 展开时的高度。
    • flexibleSpace: 允许在AppBar下方放置一个可伸缩的空间,如图片。
  3. Column:

    • 包含了一个固定高度的Container(作为固定头部)和一个ExpandedListView,后者占据了剩余的空间并允许垂直滚动。

这个示例展示了如何在Flutter中使用NestedScrollView来实现一个具有可折叠工具栏和嵌套滚动视图的复杂布局。根据具体需求,您可以进一步定制和扩展这个基础示例。

回到顶部