Flutter屏幕适配插件adaptix的使用

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

Flutter屏幕适配插件adaptix的使用

adaptix 是一个功能强大且轻量级的软件包,用于构建响应式和自适应的应用程序。

使用

初始化

  1. 将你的小部件子树(通常是应用的起点)包装在 AdaptixInitializer 中,并将 AdaptixConfigs 的实例传递给 configs 参数。
AdaptixInitializer(
  configs: const AdaptixConfigs.canonical(),
  builder: (context) {
    return MaterialApp(
      home: ...,
    );
  },
);
  1. 通过 BuildContext 访问数据。你可以使用 Adaptix.of(context) 访问 AdaptixConstraints,或者使用为语义设计的扩展方法。
AdaptixInitializer(
  configs: const AdaptixConfigs.canonical(),
  builder: (context) {
    // 访问adaptix
    print(Adaptix.of(context));

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Container(
                color: Colors.red,
                width: 50.adaptedPx(context),
                height: 50.adaptedPx(context),
                child: Text('${50.adaptedPx(context).round()} px'),
              ),
            ],
          ),
        ),
      ),
    );
  },
);

响应式断点

ResponsiveBreakpoint 实例表示一种布局模式的起始点,当设备布局发生变化时,Adaptix 将切换到该断点。这些断点通过其 templateDeviceWidth 字段区分。在这个软件包中,ResponsiveBreakpointtemplateDeviceWidth 是设备宽度,用于决定是否使用该断点来切换布局。

如果在配置中设置了 DeviceBreakpointDecisionStrategy.useOriginalWidth,则会使用设备的实际宽度进行比较;否则,如果设置了 DeviceBreakpointDecisionStrategy.useShortestSide,则会选择设备的最短边进行比较。

如何决定使用哪个断点?

基本逻辑如下:

  • 如果设备的最短边大于或等于某个断点的 templateDeviceWidth 并小于下一个断点的 templateDeviceWidth,则选择该断点。
  • 如果设备的最短边小于第一个断点的 templateDeviceWidth,则选择第一个断点。
  • 如果设备的最短边大于最后一个断点的 templateDeviceWidth,则选择最后一个断点。

自定义配置

你可以使用 AdaptixConfigs 的默认构造函数来自定义配置。

AdaptixConfigs(
  /// 定义断点
  /// 使用模板设备的宽度作为断点的templateDeviceWidth
  breakpoints: const [
    ResponsiveBreakpoint(templateDeviceWidth: 375, key: 'iphone7'),
    ResponsiveBreakpoint(templateDeviceWidth: 414, key: 'iphone11'),
    ResponsiveBreakpoint(templateDeviceWidth: 768, key: 'ipadMini'),
  ],

  /// 定义每个断点的像素比例规则
  pixelScaleRules: const {
    'iphone7': 1,
    'iphone11': 1.1,
    'ipadMini': 1.2,
  },
)

扩展方法

.adaptedPxdouble

获取根据当前 Adaptix 断点缩放后的逻辑像素。

print(1.adaptedPx(context));

.widthFractiondouble

给出设备宽度的百分比。

// 表示设备宽度的50%
print(50.widthFraction(context));

.heightFractiondouble

给出设备高度的百分比。

// 表示设备高度的50%
print(50.heightFraction(context));

.shortestSideFractiondouble

给出设备最短边的百分比。

// 表示设备最短边的50%
print(50.shortestSideFraction(context));

.longestSideFractiondouble

给出设备最长边的百分比。

// 表示设备最长边的50%
print(50.longestSideFraction(context));

.orientationSwitchcontext

返回根据当前方向的文本。

print(
  context.orientationSwitch<String>(
    onLandscape: 'Landscape text',
    onPortrait: 'Portrait text'
  )
);

.responsiveSwitchcontext

如果你想根据当前 Adaptix 断点显示某些小部件或文本,可以使用此扩展方法。

AdaptixInitializer(
  configs: AdaptixConfigs(
    /// 定义断点
    /// 使用模板设备的宽度作为断点的值
    breakpoints: const [
      ResponsiveBreakpoint(templateDeviceWidth: 375, key: 'iphone7'),
      ResponsiveBreakpoint(templateDeviceWidth: 414, key: 'iphone11'),
      ResponsiveBreakpoint(templateDeviceWidth: 768, key: 'ipadMini'),
    ],

    /// 定义每个断点的像素比例规则
    pixelScaleRules: const {
      'iphone7': 1,
      'iphone11': 1.1,
      'ipadMini': 1.2,
    },
  ),
  builder: (context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Container(
                color: Colors.red,
                width: 50.adaptedPx(context),
                height: 50.adaptedPx(context),
                child: Text(
                  context.responsiveSwitch(
                    const GenericResponsiveSwitchArgs<String>(
                      defaultValue: 'This is a default text',
                      rules: const {
                        'iphone7': 'Hello, I am a pattern based on width of iphone7',
                        'iphone11':
                            'Hello, I am a pattern based on dimensions of iphone11',
                        'ipadMini':
                            'Hello, I am a pattern based on dimensions of ipadMini',
                      },
                    ),
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  },
);

注意:如果你使用了 AdaptixConfigs.canonical,那么在调用 .responsiveSwitch 方法时需要传递 CanonicalResponsiveBreakpoint.createCanonicalSwitchArguments 参数。

context.responsiveSwitch(CanonicalResponsiveBreakpoint
.createCanonicalSwitchArguments<String>(
  defaultValue: 'Some default text',
  xSmall: 'Text of xSmall devices',
  small: 'Text of small devices',
  medium: 'Text of medium devices',
  tablet: 'Text of tablets',
  desktop: 'Text of desktop apps'));

最佳实践

建议使用值对象模式实现优雅的语义和可维护的架构。可以使用 Dart 2.17 提供的增强枚举来实现这一点。

enum MyResposivenessPattern implements ResponsiveBreakpoint {
  iphone11(templateDeviceWidth: 414, pixelScale: 1.1),
  iphone7(templateDeviceWidth: 375, pixelScale: 1),
  ipadMini(templateDeviceWidth: 768, pixelScale: 1.12),
  someDesktopDevice(templateDeviceWidth: 1024, pixelScale: 1.2);

  static final myPixelScaleRules = {
    for (var value in values) value.key: value.pixelScale,
  };

  @override
  final double templateDeviceWidth;

  final double pixelScale;

  const MyResposivenessPattern(
      {required this.templateDeviceWidth, required this.pixelScale});

  @override
  String get debugLabel => key;

  @override
  bool hasSameValueAs(ResponsiveBreakpoint other) =>
      other.templateDeviceWidth == templateDeviceWidth;

  @override
  bool isSameAs(ArgsComparisonMixin other) {
    return ResponsiveBreakpoint.breakpointEquality(
      this,
      other,
    );
  }

  /// key 作为枚举元素的名称
  @override
  String get key => name;

  static GenericResponsiveSwitchArgs<T> myResponsiveSwitchArguments<T>({
    required T defaultValue,
    T? iphone7Value,
    T? iphone11Value,
    T? ipadMiniValue,
    T? someDesktopDeviceValue,
  }) {
    return GenericResponsiveSwitchArgs(
      defaultValue: defaultValue,
      rules: {
        iphone7.key: iphone7Value ?? defaultValue,
        iphone11.key: iphone11Value ?? defaultValue,
        ipadMini.key: ipadMiniValue ?? defaultValue,
        someDesktopDevice.key: someDesktopDeviceValue ?? defaultValue,
      },
    );
  }

  static AdaptixConfigs configs() => AdaptixConfigs(
        breakpoints: MyResposivenessPattern.values,
        pixelScaleRules: MyResposivenessPattern.myPixelScaleRules,
      );
}

使用它的方式如下:

AdaptixInitializer(
  configs: MyResposivenessPattern.configs(),
  builder: (context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Container(
                color: Colors.red,
                width: 50.adaptedPx(context),
                height: 50.adaptedPx(context),
                child: Text(context.responsiveSwitch(
                  MyResposivenessPattern.myResponsiveSwitchArguments<String>(
                    defaultValue: 'Unrecognized device pattern',
                    iphone7Value: 'iphone7 device pattern',
                    iphone11Value: 'iphone11 device pattern',
                    ipadMiniValue: 'ipadMini device pattern',
                  ),
                )),
              ),
              SizedBox(
                child: Text(context.orientationSwitch<String>(
                  onLandscape: 'Landscape text',
                  onPortrait: 'Portrait text',
                )),
              ),
            ],
          ),
        ),
      ),
    );
  },
);

更多关于Flutter屏幕适配插件adaptix的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter屏幕适配插件adaptix的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,关于如何在Flutter项目中使用adaptix插件进行屏幕适配,下面是一个具体的代码案例。adaptix是一个流行的Flutter屏幕适配库,它可以帮助开发者轻松处理不同屏幕尺寸和分辨率的适配问题。

首先,确保你已经在pubspec.yaml文件中添加了adaptix依赖:

dependencies:
  flutter:
    sdk: flutter
  adaptix: ^x.y.z  # 请替换为最新版本号

然后,运行flutter pub get来获取依赖。

接下来,在你的Flutter项目的入口文件(通常是main.dart)中进行配置:

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

void main() {
  // 初始化Adaptix
  AdaptixConfig config = AdaptixConfig(
    designWidth: 375, // 设计稿的宽度,单位px
    designHeight: 667, // 设计稿的高度,单位px
  );
  Adaptix.init(context, config);

  runApp(MyApp());
}

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

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // 使用Adaptix的px方法将设计稿中的px转换为适配后的屏幕尺寸
    double adaptedWidth = Adaptix.px(375); // 这将返回屏幕宽度的一半(假设屏幕宽度为750px)
    double adaptedHeight = Adaptix.px(100); // 这将根据屏幕宽度比例缩放高度

    return Scaffold(
      appBar: AppBar(
        title: Text('Adaptix Demo'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Container(
              width: adaptedWidth,
              height: adaptedHeight,
              color: Colors.blue,
              child: Center(
                child: Text(
                  'Adapted Box',
                  style: TextStyle(color: Colors.white),
                ),
              ),
            ),
            SizedBox(height: Adaptix.px(20)), // 20px的间距,适配后
            Text(
              'Screen Width: ${Adaptix.screenWidth}\nScreen Height: ${Adaptix.screenHeight}',
              style: TextStyle(fontSize: Adaptix.sp(16)), // 16sp的文字大小,适配后
            ),
          ],
        ),
      ),
    );
  }
}

在这个示例中,我们做了以下几件事情:

  1. 初始化Adaptix:在main函数中,通过Adaptix.init方法传入设计稿的宽度和高度来初始化Adaptix。
  2. 使用Adaptix的方法:在MyHomePage中,我们使用Adaptix.px方法将设计稿中的px值转换为适配后的屏幕尺寸值,使用Adaptix.sp方法将sp值转换为适配后的文字大小。
  3. 展示适配后的UI:创建了一个容器和一个文本,容器的尺寸和文字的大小都是经过适配的。

这样,无论设备屏幕尺寸如何变化,UI都能保持与设计稿一致的比例和布局。

请确保你根据项目的实际需求调整设计稿的宽度和高度,以及其他具体的UI元素尺寸。

回到顶部