Flutter自适应显示插件adaptive_display的使用

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

Flutter 自适应显示插件 adaptive_display 的使用

adaptive_display

BoxConstraints 的包装器,使其更加可控、更少缩进并可重用。

short-gif-adaptive-display

特性

在您的 Flutter 项目中使用此插件来:

  • 自适应状态有状态小部件:适用于有状态小部件的自适应状态。
  • 自适应无状态小部件:适用于无状态小部件的自适应状态。
  • 自适应小部件:适用于无状态小部件的自适应小部件,具有 BoxConstrains 值。
  • 自适应包裹小部件:适用于无状态小部件的自适应包裹小部件,具有 BoxConstrains 值。

开始使用

安装依赖

  1. pubspec.yaml 文件中添加 adaptive_display 依赖:

    dependencies:
      adaptive_display: latest_version
    
  2. 运行 flutter pub get 来安装依赖。

  3. 如果您的小部件使用了 StatelessWidget,则将其替换为下面提供的小部件之一。如果您使用的是 StatefulWidget,可以将 State 类切换到 AdaptiveWrapState

  4. 享受定义项目的布局吧!

使用方法

该包向您的 StatefulStateless 小部件添加了一些构建器。

这些构建器有两种类型的 UI 定义:

  • 默认构建。[自适应无状态小部件, 自适应小部件]
  • 包裹构建。[自适应包裹状态, 自适应包裹小部件]

对于默认构建器,我们采用移动优先的方法,因此我们的构建方法是基础构建,然后是 xs,接着是 sm,依此类推。

对于包裹构建器,我们的构建方法会包裹所有内容,所以您应该首先定义 xs 并在构建方法中调用 [adaptive]

当您实例化这些小部件中的任何一个时,您可以获得五个可选的构建器,它们按顺序构建您的视图。

[@override](/user/override)
Widget xs(BuildContext context) { ... }

[@override](/user/override)
Widget sm(BuildContext context) { ... }

[@override](/user/override)
Widget md(BuildContext context) { ... }

[@override](/user/override)
Widget lg(BuildContext context) { ... }

[@override](/user/override)
Widget xl(BuildContext context) { ... }

注意:使用 AdaptiveWidgetAdaptiveWrapWidget 可以访问约束值 🤗

[@override](/user/override)
Widget xs(BuildContext context, BoxConstraints constraints) { ... }

自适应包裹状态用于有状态小部件

通过这个抽象小部件,您可以将自适应显示小部件与有状态小部件结合起来,只需添加包并切换 State 类到 AdaptiveWrapState 即可访问构建器。

class StatefulAdaptive extends StatefulWidget {
  const StatefulAdaptive({super.key});

  [@override](/user/override)
  // ⬇ 在这里
  State<StatefulAdaptive> createState() => _StatefulAdaptiveState();
}
//                                    ⬇ 在这里
class _StatefulAdaptiveState extends AdaptiveWrapState<StatefulAdaptive> {

  [@override](/user/override)
  Widget build(BuildContext context) {
    return adaptive; // 您应该在这里调用 [adaptive]。
                     // 您可以将其包装在任何小部件中。
                     // 在 [AdaptiveStateLessWidget] 中,[xs] 是默认小部件
  }

  [@override](/user/override)
  // 通过使构建方法能够包裹逻辑,
  // xs 方法成为强制性的,并且是第一个被调用的方法。
  Widget xs(BuildContext context) { ... } // 创建自定义 UI
}

自适应无状态小部件

对于 AdaptiveStatelessWidget,您应该将其从 StatelessWidget 替换。

class StateLessAdaptive extends AdaptiveStatelessWidget {

[@override](/user/override)
Widget build(BuildContext context) {
    ... // 您不应该在这里调用 [adaptive]。
        // 逻辑会在小部件树中自动应用,
        // 在 [AdaptiveStatelessWidget] 中,[build] 是默认小部件
  }
}

自适应小部件

它保持与 AdaptiveStatelessWidget 相同的逻辑,但在每个构造方法中,它允许我们访问约束值。 如果您决定在构建方法中调用 "adaptive",请务必小心。

class StateLessAdaptive extends AdaptiveWidget {
  [@override](/user/override)
  Widget xs(BuildContext context, BoxConstraints constraints) {
    final text = 'XS! ${constraints.maxWidth} value';
    return Center(child: Text(text, style: textStyle));
  }
}

自适应包裹小部件

它保持与 AdaptiveWrapState 相同的逻辑,但适用于 StatelessWidget。您也可以在构建方法中使用约束值。

配置

在此包中,默认值如下:

大小 宽度
超小 (xs) 480 px
小 (sm) 768 px
中 (md) 1024 px
大 (lg) 1440 px
超大 (xl) 1920 px

您可以通过在 main 方法中调用 Adaptive.setDefault() 方法来更改断点。但是,在设置值时必须遵循某些规则。这些规则是:

  • XL 必须大于 LG
  • LG 必须大于 MD
  • MD 必须大于 SM
  • SM 必须大于 XS
  • XS 必须大于 0
void main() {
  Adaptive.setDefault(xs: 420.0, xl: 1820.0); // xs, sm, md, lg, xl
}

完整示例

import 'package:adaptive_display/adaptive_display.dart';
import 'package:flutter/material.dart';
import 'package:widget_adaptive/widgets/adaptive_colorful.dart';
import 'package:widget_adaptive/widgets/adaptive_stateful.dart';
import 'package:widget_adaptive/widgets/adaptive_stateless.dart';
import 'package:widget_adaptive/widgets/adaptive_widget.dart';
import 'package:widget_adaptive/widgets/adaptive_wrap.dart';

///                         ⬇ 这里任何自适应小部件
class SelectorPage extends AdaptiveWrapWidget {
  const SelectorPage({super.key});

  [@override](/user/override)
  // [build] 方法包裹所有定义的构建器
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        centerTitle: true,
        title: const Text('自适应显示小部件'),
      ),
      body: Center(
          /// ⬇ 这里是 [adaptive] 小部件
          child: adaptive),
    );
  }

  /// 在 [AdaptiveWrapWidget] 中 xs 成为强制性的
  [@override](/user/override)
  Widget xs(BuildContext context, BoxConstraints constraints) {
    return ListView(
      padding: const EdgeInsets.all(32),
      children: [
        ElevatedButton(
          onPressed: () => _goToWidgetAdaptive(context),
          child: const Text('自适应小部件'),
        ),
        const SizedBox(height: 16),
        ElevatedButton(
          onPressed: () => _goToWidgetWrap(context),
          child: const Text('自适应包裹小部件'),
        ),
        const SizedBox(height: 16),
        ElevatedButton(
          onPressed: () => _goToWidgetStateless(context),
          child: const Text('无状态小部件'),
        ),
        const SizedBox(height: 16),
        ElevatedButton(
          onPressed: () => _goToWidgetStateful(context),
          child: const Text('有状态小部件'),
        ),
        const SizedBox(height: 16),
        ElevatedButton(
          onPressed: () => _goToWidgetColorful(context),
          child: const Text('多彩小部件'),
        ),
      ],
    );
  }

  // 从 sm 开始的所有构建器都是可选的,
  // 如果它们未定义,则将采用其前一个构建器的值
  [@override](/user/override)
  Widget md(BuildContext context, BoxConstraints constraints) {
    return Row(
      children: [
        Expanded(
          child: ListView(
            padding: const EdgeInsets.all(32),
            children: [
              ElevatedButton(
                onPressed: () => _goToWidgetAdaptive(context),
                child: const Text('自适应小部件'),
              ),
              const SizedBox(height: 16),
              ElevatedButton(
                onPressed: () => _goToWidgetWrap(context),
                child: const Text('自适应包裹小部件'),
              ),
              const SizedBox(height: 16),
              ElevatedButton(
                onPressed: () => _goToWidgetStateless(context),
                child: const Text('无状态小部件'),
              ),
              const SizedBox(height: 16),
            ],
          ),
        ),
        Expanded(
          child: ListView(
            padding: const EdgeInsets.all(32),
            children: [
              ElevatedButton(
                onPressed: () => _goToWidgetStateful(context),
                child: const Text('有状态小部件'),
              ),
              const SizedBox(height: 16),
              ElevatedButton(
                onPressed: () => _goToWidgetColorful(context),
                child: const Text('多彩小部件'),
              ),
            ],
          ),
        ),
      ],
    );
  }
}

void _goToWidgetAdaptive(BuildContext context) {
  Navigator.pushNamed(context, '/widget_adaptive');
}

void _goToWidgetStateless(BuildContext context) {
  Navigator.pushNamed(context, '/widget_stateless');
}

void _goToWidgetStateful(BuildContext context) {
  Navigator.pushNamed(context, '/widget_stateful');
}

void _goToWidgetWrap(BuildContext context) {
  Navigator.pushNamed(context, '/widget_wrap');
}

void _goToWidgetColorful(BuildContext context) {
  Navigator.pushNamed(context, '/widget_colorful');
}

final routes = {
  '/': (context) => const SelectorPage(),
  '/widget_adaptive': (context) => const WidgetAdaptive(),
  '/widget_wrap': (context) => const WidgetWrapAdaptive(),
  '/widget_stateless': (context) => const StateLessAdaptive(),
  '/widget_stateful': (context) => const StatefulAdaptive(),
  '/widget_colorful': (context) => const ColorfulAdaptive(),
};

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

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '自适应小部件',
      color: Colors.black,
      builder: (context, child) => child!,
      debugShowCheckedModeBanner: false,
      initialRoute: '/',
      routes: routes,
    );
  }
}

更多关于Flutter自适应显示插件adaptive_display的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter自适应显示插件adaptive_display的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter项目中使用adaptive_display插件来实现自适应显示的代码案例。adaptive_display插件允许你根据设备的显示特性(如亮度模式、刷新率等)来调整你的应用界面。

首先,你需要在你的pubspec.yaml文件中添加adaptive_display依赖:

dependencies:
  flutter:
    sdk: flutter
  adaptive_display: ^0.1.0  # 请检查最新版本号

然后运行flutter pub get来安装依赖。

接下来,在你的Flutter项目中,你可以使用以下代码来检测并响应设备的显示特性变化。

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

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

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

class AdaptiveDisplayScreen extends StatefulWidget {
  @override
  _AdaptiveDisplayScreenState createState() => _AdaptiveDisplayScreenState();
}

class _AdaptiveDisplayScreenState extends State<AdaptiveDisplayScreen> with WidgetsBindingObserver {
  AdaptiveDisplayMode? _currentDisplayMode;

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance?.addObserver(this);
    _listenToAdaptiveDisplayModeChanges();
  }

  @override
  void dispose() {
    WidgetsBinding.instance?.removeObserver(this);
    AdaptiveDisplay.instance?.stopListeningToDisplayModeChanges();
    super.dispose();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (state == AppLifecycleState.resumed) {
      // Optionally re-subscribe to changes if needed when the app is resumed
      _listenToAdaptiveDisplayModeChanges();
    }
  }

  void _listenToAdaptiveDisplayModeChanges() {
    AdaptiveDisplay.instance?.listenToDisplayModeChanges((AdaptiveDisplayMode mode) {
      setState(() {
        _currentDisplayMode = mode;
      });
    });

    // Initial check to set the state based on the current display mode
    AdaptiveDisplay.instance?.getCurrentDisplayMode().then((mode) {
      setState(() {
        _currentDisplayMode = mode;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Adaptive Display Demo'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'Current Display Mode:',
              style: TextStyle(fontSize: 20),
            ),
            SizedBox(height: 10),
            Text(
              _currentDisplayMode == null ? 'Unknown' : _currentDisplayMode!.toString(),
              style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
            ),
          ],
        ),
      ),
    );
  }
}

代码解释

  1. 依赖添加:在pubspec.yaml中添加adaptive_display依赖。

  2. 初始化:在initState方法中,我们添加了WidgetsBinding观察者,并调用_listenToAdaptiveDisplayModeChanges方法来开始监听显示模式的变化。

  3. 监听显示模式变化_listenToAdaptiveDisplayModeChanges方法订阅了显示模式的变化,并在变化时更新状态。

  4. 获取当前显示模式:通过调用AdaptiveDisplay.instance?.getCurrentDisplayMode()获取当前的显示模式,并在组件首次加载时设置状态。

  5. UI显示:在UI中,我们显示当前的显示模式。如果显示模式未知,则显示“Unknown”。

  6. 生命周期管理:在dispose方法中,移除WidgetsBinding观察者,并停止监听显示模式的变化。在didChangeAppLifecycleState方法中,当应用恢复时,可以重新订阅显示模式的变化(如果需要)。

请确保你已经正确安装并配置了adaptive_display插件,并根据需要调整代码中的细节。由于插件的版本和API可能会变化,请参考插件的官方文档获取最新的使用方法和API参考。

回到顶部