Flutter响应式布局插件responsiveness的使用

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

Flutter响应式布局插件responsiveness的使用

1. 背景介绍

当我第一次被要求为所有屏幕尺寸开发Flutter应用程序时,我感到不知所措。尽管Flutter提供了LayoutBuilderMediaQuery等小部件以实现响应式UI开发,但要以简单、可读且可预测的方式利用这些小部件相当困难。因为仍然需要考虑:

  • 您想要使用的断点是什么?
  • 如何根据屏幕宽度识别当前断点?
  • 如何基于当前断点定义易于阅读的UI?

此包是我尝试回答上述问题的结果,并提供了一种有见地的方法来使用Flutter进行响应式UI开发。

2. 断点设置

该包默认使用Bootstrap断点:

简称 完整名称 最小宽度(px) 设备类型
xs extra small 0 竖屏手机
sm small 576 横屏手机
md medium 768 平板电脑
lg large 992 桌面设备
xl extra large 1200 大型桌面
xxl xx-large 1400 更大型桌面

您也可以提供自定义断点,如这里所示。

3. 创建UI

以下是三个用于定义响应式UI的小部件:

ResponsiveValue

ResponsiveValue允许您根据当前屏幕大小提供不同的值。提供的值可以是任何类型的,从doubleWidget

定义:

static const fontSize = ResponsiveValue<double>(xs: 20.0, sm: 21.0, md: 22.0);
static const fontColor = ResponsiveValue<Color>(md: Colors.green, lg: Colors.red);

使用:

@override
Widget build(BuildContext context) {
  return Text(
    "Hello World",
    style: TextStyle(
      fontSize: fontSize.of(context),
      color: fontColor.of(context),
    ),
  );
}

注意,您不需要为每个屏幕大小指定一个值。只需要至少提供一个xs的值,也可以提供更多甚至全部。如果未为某个屏幕大小提供值,则将使用最近较小定义的屏幕大小的值。

ResponsiveChild

ResponsiveChild小部件允许您根据当前屏幕大小提供不同的小部件。与ResponsiveValue类似,您不需要为六个不同可能的屏幕大小中的每一个指定一个小部件。只有xs屏幕大小的小部件是必需的。

代码示例:

@Override
Widget build(BuildContext context) {
  return ResponsiveChild(
    xs: Text("show when screen size is xs"),
    sm: Text("show when screen size is sm"),
    md: Text("show when screen size is md"),
    lg: Text("show when screen size is lg"),
    xl: Text("show when screen size is xl"),
    xxl: Text("show when screen size is xxl"),
  );
}

ResponsiveParent

ResponsiveParent小部件允许您根据当前屏幕大小用不同的小部件包装给定的对象。您需要为至少xs屏幕大小指定一个回调函数。这个回调接收给定的child作为参数并返回一个新的Widget

代码示例:

//displays a column or row based on the current screen size
@override
Widget build(BuildContext context) {
  return ResponsiveParent<List<Widget>>(
    xs: (child) => Column(children: child),
    md: (child) => Row(children: child),
    child: [], //some children Widgets
  );
}

在上面的例子中,对于屏幕尺寸xs和sm显示Column,而对于屏幕尺寸md - xxl显示Row

4. 自定义断点

您可以使用代码生成提供自定义断点。例如,如果您想使用小、中、大三种屏幕尺寸,可以按照以下步骤操作:

  1. 在项目的根目录下创建一个名为’screen_sizes.json’的文件。

  2. 在’screen_sizes.json’中定义不同的屏幕尺寸。键是屏幕尺寸的名称,值是该屏幕尺寸的最小宽度。键必须是字符串,而值必须是整数。

    示例screen_sizes.json:

    {
      "small": 0,
      "medium": 500,
      "large": 1000
    }
    
  3. 从项目的根目录运行命令dart run responsiveness。这将在项目的lib目录下生成一个名为’responsiveness.dart’的文件。

  4. 在文件顶部导入生成的文件,而不是直接导入此包:

    import "package:<your-project-name>/responsiveness.dart";
    

5. 使用建议

为了快速且轻松地应用这些工具来构建响应式UI,我的建议如下: 首先,专注于为移动电话(例如屏幕尺寸xs)构建UI。完成这一步后,再开始考虑其他屏幕尺寸。这样可以使复杂度降低,使开发过程更加简单。

示例Demo

下面是一个完整的示例demo,展示了如何使用responsiveness插件构建响应式布局:

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

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key});

  static const containerSize = ResponsiveValue<Size>(
    xs: Size(double.infinity, 700),
    sm: Size(double.infinity, 300),
  );

  static const actions = ResponsiveValue<List<Widget>>(
    xs: [_MyPopupMenuButton()],
    sm: [_Page1Button(), _Page2Button()],
  );

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        appBar: AppBar(
          title: const Text("Responsiveness Example"),
          actions: actions.of(context),
        ),
        body: ResponsiveParent(
          //for screen sizes xs, xxl light theme
          //for screen sizes sm, md, lg, xl dark theme
          xs: (child) => Theme(data: ThemeData.light(), child: child),
          sm: (child) => Theme(data: ThemeData.dark(), child: child),
          xxl: (child) => Theme(data: ThemeData.light(), child: child),
          child: Builder(builder: (context) {
            final textStyle = Theme.of(context).textTheme.bodyMedium;
            return Container(
              color: Theme.of(context).cardColor,
              width: containerSize.of(context).width,
              height: containerSize.of(context).height,
              margin: const EdgeInsets.symmetric(vertical: 10, horizontal: 10),
              child: Center(
                child: ResponsiveChild(
                  xs: Text("Screen Size xs", style: textStyle),
                  sm: Text("Screen Size sm", style: textStyle),
                  md: Text("Screen Size md", style: textStyle),
                  lg: Text("Screen Size lg", style: textStyle),
                  xl: Text("Screen Size xl", style: textStyle),
                  xxl: Text("Screen Size xxl", style: textStyle),
                ),
              ),
            );
          }),
        ),
      ),
    );
  }
}

class _Page1Button extends StatelessWidget {
  const _Page1Button();

  @override
  Widget build(BuildContext context) {
    return TextButton(
      onPressed: () {},
      child: const _LinkText("Page One"),
    );
  }
}

class _Page2Button extends StatelessWidget {
  const _Page2Button();

  @override
  Widget build(BuildContext context) {
    return TextButton(onPressed: () {}, child: const _LinkText("Page Two"));
  }
}

class _MyPopupMenuButton extends StatelessWidget {
  const _MyPopupMenuButton();

  @override
  Widget build(BuildContext context) {
    return PopupMenuButton(
      itemBuilder: (context) {
        return [
          PopupMenuItem(
            onTap: () {},
            child: const Text("Page One"),
          ),
          PopupMenuItem(
            onTap: () {},
            child: const Text("Page Two"),
          ),
        ];
      },
    );
  }
}

class _LinkText extends StatelessWidget {
  const _LinkText(this.text);

  final String text;

  @override
  Widget build(BuildContext context) {
    return Text(
      text,
      style: const TextStyle(color: Colors.white),
    );
  }
}

希望以上内容能帮助您更好地理解和使用responsiveness插件。祝您的项目顺利!


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

1 回复

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


在Flutter中,responsiveness插件并不是官方的Flutter库,但假设你提到的是一个用于响应式布局的第三方库或者是一个自定义实现的响应式逻辑,我可以展示一个典型的响应式布局的实现方法,这种方法通常涉及使用LayoutBuilderMediaQuery等Flutter内置的功能。

不过,为了贴近你的要求,我会展示一个自定义响应式逻辑的示例,它模拟了一个响应式框架可能提供的功能。这个示例将包括一个简单的响应式布局,它根据屏幕尺寸调整UI布局。

示例代码

首先,我们创建一个Flutter项目,然后在lib目录下创建一个新的文件,比如responsive_layout.dart,用于定义我们的响应式逻辑。

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

enum ScreenSize {
  small,
  medium,
  large,
}

class ResponsiveLayout extends StatelessWidget {
  final Widget smallScreenWidget;
  final Widget mediumScreenWidget;
  final Widget largeScreenWidget;

  ResponsiveLayout({
    required this.smallScreenWidget,
    required this.mediumScreenWidget,
    required this.largeScreenWidget,
  });

  @override
  Widget build(BuildContext context) {
    ScreenSize screenSize = getScreenSize(context);

    return LayoutBuilder(
      builder: (context, constraints) {
        if (screenSize == ScreenSize.small) {
          return smallScreenWidget;
        } else if (screenSize == ScreenSize.medium) {
          return mediumScreenWidget;
        } else {
          return largeScreenWidget;
        }
      },
    );
  }

  ScreenSize getScreenSize(BuildContext context) {
    double width = MediaQuery.of(context).size.width;
    if (width < 600) {
      return ScreenSize.small;
    } else if (width >= 600 && width < 960) {
      return ScreenSize.medium;
    } else {
      return ScreenSize.large;
    }
  }
}

接下来,在你的主应用文件中(通常是main.dart),使用这个ResponsiveLayout来创建响应式UI。

// main.dart
import 'package:flutter/material.dart';
import 'responsive_layout.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Responsive Layout Demo'),
        ),
        body: ResponsiveLayout(
          smallScreenWidget: Center(
            child: Text('Small Screen'),
          ),
          mediumScreenWidget: Column(
            children: <Widget>[
              Text('Medium Screen Top'),
              Text('Medium Screen Bottom'),
            ],
          ),
          largeScreenWidget: Row(
            children: <Widget>[
              Expanded(child: Text('Large Screen Left')),
              Expanded(child: Text('Large Screen Right')),
            ],
          ),
        ),
      ),
    );
  }
}

解释

  1. ResponsiveLayout

    • 接受三个Widget作为参数,分别对应小屏幕、中屏幕和大屏幕。
    • 使用LayoutBuilderMediaQuery来确定当前屏幕尺寸。
    • 根据屏幕尺寸返回相应的Widget
  2. getScreenSize 方法

    • 根据屏幕宽度返回ScreenSize枚举值。
  3. main.dart

    • 创建了一个简单的Flutter应用。
    • 使用ResponsiveLayout来展示不同屏幕尺寸下的UI布局。

这种方法展示了如何在Flutter中实现基本的响应式布局。虽然responsiveness插件可能提供更高级的功能和更简洁的API,但理解这些基础概念对于任何响应式布局实现都是至关重要的。

回到顶部