Flutter布局管理插件layoutr的使用

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

Flutter布局管理插件layoutr的使用

layoutr

pub package

一套简洁的Dart/Flutter工具,帮助你进行响应式布局,减少冗余。

为什么

已经有很多布局/UI库了,但这个库只是为了解决同样的问题:响应式布局。

这个包旨在成为一个单一依赖,处理Flutter应用程序中的响应式用例,同时保持代码的简洁性。我们知道在这些小部件中使用起来会变得非常冗长(更难阅读)。

使用

在了解该包的API之前,确保通过以下方式安装此包:

dependencies:
  layoutr: ^x.y.z

安装完成后,让我们了解一下这个包的功能:

布局解析器

这些是核心布局类,应该使处理多个布局的小部件变得更加简洁。我们可以在有BuildContext可用时(通常在小部件的build函数中)使用这些解析器。

虽然魔法应该发生在抽象的LayoutResolver内部,但我们必须扩展这个类来提供所需的Breakpoint。这是因为当构建任何类型的UI时,存在大量的用例——这意味着这些断点完全是主观的,基于每个项目的“约束”。

尽管如此,我们还是希望有一些内置的布局解析器,它们可能适合最常见的用例。为了说明解析器的工作原理,我们可以看看CommonLayout是如何工作的。

示例:使用CommonLayout

在深入概念之前,确保为你的小部件提供一个CommonLayout。这可以通过多种方式完成,但最简单的方法是将你的顶层小部件包装在CommonLayoutWidget中:

import 'package:layoutr/common_layout.dart';

// ...
CommonLayoutWidget(
  child: /* 我的小部件,可能是MaterialApp/WidgetsApp */,
);
// ...

现在,CommonLayout分为四个断点:desktoptabletphonetinyHardware。你可以像下面这样返回一个响应式的Text小部件,其值和样式都根据当前设备的约束进行定制:

import 'package:layoutr/common_layout.dart';

// ...

Widget build(BuildContext context) {
  final layout = context.commonLayout;
  final textTheme = Theme.of(context).textTheme;

  return layout.value(
    desktop: () => Text('Desktop layout', style: textTheme.headline1),
    phone: () => Text('Phone layout', style: textTheme.headline4),
    tinyHardware: () => Text('Tiny Hardware layout', style: textTheme.headline6),
  );
}
// ...

TLDR: 不需要提供所有断点,布局将自动找到当前断点最合适的值。

详细版本:可以看到,tablet 没有传递给 layout.value,这是为了说明一个常见的场景,我们可能只想提供两个或三个参数——这意味着不是所有的场景都被“覆盖”——这就是解析器的用途所在:如果当前断点的值未传递给 layout.value,它将回退到最近的可用值,以适应最适合你的特定值的布局。这种“最近逻辑”可能会令人困惑,但你可以了解更多如何在 LayoutResolver.closestValue 中实现。

除了 layout.valueCommonLayout 还提供了简单的布尔比较实用程序:

import 'package:layoutr/common_layout.dart';

// ...

Widget build(BuildContext context) {
  final layout = context.commonLayout;
  const pageTitle = '标题';

  final myAppBar = layout.isTabletOrSmaller ? AppBar(title: const Text(pageTitle)) : null;

  return Scaffold(
    // 如果当前布局是平板或更小,则添加一个 `AppBar`
    appBar: myAppBar,
    body: Center(
      child: Column(
        children: [
          // 如果当前布局是桌面,则添加一个自定义标题 `AppBar`
          if (layout.isDesktop)
            Text(pageTitle, style: Theme.of(context).textTheme.headline3),
          // ... 其他小部件
        ],
      ),
    ),
  );
}
// ...

覆盖CommonLayout解析器

要覆盖每个断点的大小,可以提供自己的 CommonLayout 实例:

import 'package:layoutr/common_layout.dart';
// ...
CommonLayoutWidget(
  resolverBuilder: (constraints) => CommonLayout(constraints.maxWidth, desktop: 800, tablet: 520),
  child: /* 我的小部件 */,
);
// ...

TLDR: 你的应用不一定需要使用 MaterialAppWidgetsApp,只需将其添加到你的顶级小部件上方。

详细版本:最好将解析器小部件添加到你的树的顶级小部件之上,因为所有内置的小部件都使用了一个 LayoutBuilder 来提供这样的响应功能,如果它们在嵌套的小部件中创建,这可能会导致不一致,因为它们只会使用父级的 BoxConstraints。如果你想要创建一个与设备大小无关的解析器,这可能是有用的,但我目前无法看到在这种情况下有什么有用的情景。

覆盖CommonLayout间距

要覆盖每个断点的间距,可以提供自己的 RawSpacings 实例:

import 'package:layoutr/common_layout.dart';
// ...
CommonLayoutWidget(
  spacings: const RawSpacings(4, 12, 20, 24, 32, 40, 48, 56, 60),
  child: /* 我的小部件 */,
);
// ...

上述内容将自定义所有断点的所有间距,但这还不具备响应性,这也没关系。你可能只想使用间距作为类型安全实用程序的好处。如果你还想让它们具有响应性,有一个构造函数可以做到这一点:

import 'package:layoutr/common_layout.dart';

// ...
CommonLayoutWidget.withResponsiveSpacings(
  desktopSpacings: RawSpacings(8, 16, 24, 32, 40, 52, 60, 68, 80),
  phoneSpacings: RawSpacings(4, 8, 12, 20, 28, 36, 40, 48, 60),
  child: /* 我的小部件 */,
);
// ...

不知道间距是什么?查看间距

提示

  • 我们可以轻松地将此包与常见的库如 provider (见于 provider_usage)和 river_pod (见于 river_pod_usage)一起使用;
  • 这里解释的一切对于所有内置解析器(如 GranularLayout)都是相同的,它们只在断点的数量和类型上有所不同。

可用的内置LayoutResolver

  • CommonLayout:一个分为四个断点的解析器:desktoptabletphonetinyHardware。通过 package:layoutr/common_layout.dart 导入此解析器(见于 common_layout);
  • GranularLayout:一个分为六个断点的解析器:xxLargexLargelargemediumsmallxSmall。通过 package:layoutr/granular_layout.dart 导入此解析器(见于 granular_layout)。

自定义LayoutResolver

如果上述内置解析器不符合需求,可以通过扩展 LayoutResolver 来自定义它,利用抽象类中内置的工具。要扩展并实现自定义的 LayoutResolver,导入 package:layoutr/layoutr.dart。参见 custom_layout 的自定义实现示例。

间距

所有间距功能围绕 Spacing 枚举器展开。这些是命名范围,通常适用于野外的大多数用例。它们相当直观:xxxSmallxxSmallxSmallsmallmedium 等等。

间距是一个额外的帮助,用于在我们需要类型安全性、响应性或两者兼有时的情况。具体来说:

  • 类型安全性:即使你不打算将其用作响应值,你仍然会从类型安全系统中受益,该系统将防止你在应用中出现不一致的间距、边距和填充;
  • 响应性:间距可以根据一个、一些或所有断点进行定制,这意味着如果你使用 Spacing 类型系统,就不必更改任何东西。

所有内置的 LayoutResolver 都将提供间距,因此无需添加其他内容,只需在根小部件中添加即可。但这可能不适合大多数人。如果想要,可以仅使用此包的功能(带有 SpacingsInheritedWidget),如下所示:

import 'package:layoutr/layoutr.dart';

// ...
LayoutBuilder(
  builder: (context, constraints) {
    // 如果我们想,我们可以使用这种间距类型安全/响应性,而无需解析器本身
    final myCustomSpacings = constraints.maxWidth > 800
        ? RawSpacings(16, 24, 32, 40, 52, 60, 68, 76, 80)
        : RawSpacings(8, 12, 24, 32, 40, 48, 56, 64, 72);

    return SpacingsInheritedWidget(
      spacings: myCustomSpacings,
      child: // ...,
    );
  },
);
// ...

单独使用这可能有些用处,但它的潜力在与内置实用程序和解析器小部件结合时会增强——你可以甚至通过扩展任何 BuildContextWidget 或任何布局相关的元素来自建。

带有一些实用程序的示例用法:

import 'package:layoutr/layoutr.dart';

// SpacingMixin 只是为了让你调用间距像 `smallSpacing`,而不是 `Spacing.smallSpacing`,使其总体上更简洁。
class MyPage extends StatelessWidget with SpacingMixin {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          Text('我的页面'),
          // 创建一个垂直响应/类型安全间距
          context.verticalBox(xxxLargeSpacing), 
          Container(
            // 创建一个垂直对称的内边距响应/类型安全间距
            margin: context.symmetricInsets(vertical: smallSpacing),
            color: Colors.amber,
            // 使用所有内边距包裹此小部件
            child: Placeholder().withAllPadding(context, mediumSpacing),
          ),
        ],
      ),
    );
  }
}

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

1 回复

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


当然,作为IT专家,以下是一个关于如何使用Flutter布局管理插件layoutr的代码案例。请注意,layoutr 并不是一个官方或广泛认可的 Flutter 插件名,这里我假设它是一个自定义的或小众的插件,用于简化布局管理。如果layoutr实际上并不存在,这段代码存在的将插件展示):如何使用 一个 假设```的布局yaml 管理dependencies插件:的基本 实际的 结构flutter。:

sdk首先:, flutter你需要

确保 你的layoutrpub:spec ^.xyaml.y文件中.已经z包含了 # lay替换outr为插件(如果它是一个实际版本号


然后,运行`flutter pub get`来安装插件。

接下来,是一个使用假设的`layoutr`插件的Flutter代码示例:

```dart
import 'package:flutter/material.dart';
import 'package:layoutr/layoutr.dart';  // 假设layoutr插件的导入路径

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

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

class MyHomePage extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Layoutr Plugin Example'),
      ),
      body: LayoutrBuilder(  // 假设LayoutrBuilder是layoutr插件提供的一个widget
        // 定义布局配置
        layoutConfig: LayoutConfig(
          orientation: Orientation.vertical,
          spacing: 16.0,
          padding: EdgeInsets.all(16.0),
        ),
        children: [
          LayoutrItem(
            child: Container(
              color: Colors.red,
              height: 100,
            ),
          ),
          LayoutrItem(
            flex: 2,  // 假设支持flex布局属性
            child: Container(
              color: Colors.green,
              child: Center(child: Text('Flex 2')),
            ),
          ),
          LayoutrItem(
            child: Container(
              color: Colors.blue,
              height: 100,
            ),
          ),
        ],
      ),
    );
  }
}

// 假设LayoutConfig和LayoutrItem是layoutr插件定义的类
// 这些类可能包含用于配置布局的属性
class LayoutConfig {
  final Orientation orientation;
  final double spacing;
  final EdgeInsets padding;

  LayoutConfig({
    required this.orientation,
    required this.spacing,
    required this.padding,
  });
}

class LayoutrItem {
  final Widget child;
  final double? flex;  // 可选属性,用于flex布局

  LayoutrItem({
    required this.child,
    this.flex,
  });
}

// 注意:上面的LayoutConfig和LayoutrItem类只是示例,实际使用时请参考layoutr插件的文档。
// 由于layoutr插件可能并不真实存在,这些类只是为了展示如何使用一个假设的布局管理插件。

在这个示例中,我们假设layoutr插件提供了一个LayoutrBuilder widget,它接受一个LayoutConfig对象来定义布局配置,并接受一个LayoutrItem列表作为子元素。每个LayoutrItem可以包含一个Widget和一个可选的flex属性,用于控制其在布局中的大小。

请注意,由于layoutr可能并不是一个实际存在的插件,上述代码仅用于演示如何在一个假设的布局管理插件中使用自定义布局配置和子元素。如果你正在使用一个真实存在的布局管理插件,请参考该插件的官方文档来获取正确的使用方法和API。

回到顶部