Flutter的屏幕适配

使用Flutter开发商用项目,则你必不可少要考虑的一个东西,那就是屏幕适配。回顾一下Android的屏幕适配方案,有以下考虑。

  1. dp替换px
  2. fragment适配平板以及使用不同分辨率的布局
  3. 百分比布局与动态计算控件尺寸

那么Flutter也可以借鉴Android原生的思路。

  1. 使用flutter_screenutil库,得到考虑分辨率后的单位
  2. 自适应和动态计算组件大小

适配布局尺寸

如果有设计稿的情况下,适配就变得简单了,建议直接用 flutter_screenutil,方便快捷。

使用 flutter_screenutil 适配

首先在pubspec.yaml文件中安装依赖。

yaml 复制代码
dependencies:
  flutter_screenutil: ^5.6.0

接下来在main.dart中初始化尺寸。

dart 复制代码
import 'package:flutter_screenutil/flutter_screenutil.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return ScreenUtilInit(
      designSize: const Size(375, 812), // 你的设计稿尺寸,例如 iPhone X
      minTextAdapt: true,
      splitScreenMode: true,
      builder: (context, child) {
        return MaterialApp(
          home: const HomePage(),
        );
      },
    );
  }
}

最后我们只要按照它的使用方式使用就行了。即所有尺寸都加 .w.h.r.sp等。比如 设计稿是375x812,宽度标的10,那么你就写10.w,高度标的15,那么你就写15.h,对于圆角半径,你就写比如5.r。sp就跟Android原生类似了,不做过多赘述。

误区

对于r的计算方式,刚接触的可能会想当然的认为是宽和高的平均值。看了源码发现实际上不是,它是取的宽度和高度的较小值确认缩放比例的。通常用于半径、边框宽度这种不太区分是宽还是高的场景。

使用媒体查询计算缩放因子

也可以自己动态计算缩放的比例,这种方式麻烦一些,你只需要知道有这种方式即可。

dart 复制代码
final screenWidth = MediaQuery.of(context).size.width;
final screenHeight = MediaQuery.of(context).size.height;
double scaleWidth(double width) => width * screenWidth / 375.0;
需要注意的地方

在Android中,如果是自己计算,通常还需要考虑系统状态栏和导航栏对布局的影响。

dart 复制代码
// 获取系统状态栏的高度
double statusBarHeight = MediaQuery.of(context).padding.top;
// 获取系统导航栏的高度
double navigationBarHeight = MediaQuery.of(context).padding.bottom;

如果你用的是 Scaffold,并且开启了 resizeToAvoidBottomInset: true,它会在键盘弹出时,自动调整布局,TextField会向上推移,避免被键盘遮挡。并且默认它会占据状态栏进行布局,比如你不想做沉浸式,你需要使用SafeArea组件包裹,这样你的布局就会避开状态栏了。

dart 复制代码
SafeArea(
  child: Scaffold(
    appBar: AppBar(title: Text("My App")),
    body: Column(
      children: [
        Text('This is a safe area'),
        // 更多内容
      ],
    ),
  ),
)

设置布局方向

使用SystemChrome.setPreferredOrientations可以设置布局的屏幕方向。例如:

dart 复制代码
SystemChrome.setPreferredOrientations([
  DeviceOrientation.portraitUp,
  DeviceOrientation.landscapeLeft,
  // ...
]);

只允许竖屏(正向)

dart 复制代码
SystemChrome.setPreferredOrientations([
  DeviceOrientation.portraitUp,
]);

只允许横屏(向左)

dart 复制代码
SystemChrome.setPreferredOrientations([
  DeviceOrientation.landscapeLeft,
]);

支持竖屏正向 & 横屏

dart 复制代码
SystemChrome.setPreferredOrientations([
  DeviceOrientation.portraitUp,
  DeviceOrientation.landscapeLeft,
  DeviceOrientation.landscapeRight,
]);
需要注意的地方

如果你在main函数里面设置,你需要加async关键字,并在调用SystemChrome.setPreferredOrientations()之前先调用WidgetsFlutterBinding.ensureInitialized()以确保初始化完成。

dart 复制代码
void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await SystemChrome.setPreferredOrientations([
      DeviceOrientation.portraitUp, // 只竖屏
  ]);
  runApp(MyApp());
}

否则你会遇到以下错误。

Binding has not yet been initialized

适配状态栏图标和文字颜色

这个功能在Android6.0开始支持,请参见公主。哦,不对,请参考我的开源库Dora 的源代码github.com/dora4/dora/...

dart 复制代码
return AnnotatedRegion<SystemUiOverlayStyle>(
  value: SystemUiOverlayStyle.dark, // 或 light
  child: Scaffold(
    backgroundColor: Colors.white,
    body: YourPage(),
  ),
);
样式 效果
SystemUiOverlayStyle.dark 状态栏图标/文字为 黑色(适合浅色背景)
SystemUiOverlayStyle.light 状态栏图标/文字为 白色(适合深色背景)
相关推荐
恋猫de小郭2 小时前
Flutter 发布官方 Skills ,Flutter 在 AI 领域再添一助力
android·前端·flutter
Kapaseker7 小时前
一杯美式搞懂 Any、Unit、Nothing
android·kotlin
黄林晴7 小时前
你的 Android App 还没接 AI?Gemini API 接入全攻略
android
恋猫de小郭17 小时前
2026 Flutter VS React Native ,同时在 AI 时代 VS Native 开发,你没见过的版本
android·前端·flutter
冬奇Lab18 小时前
PowerManagerService(上):电源状态与WakeLock管理
android·源码阅读
明君879971 天前
Flutter 如何给图片添加多行文字水印
前端·flutter
BoomHe1 天前
Now in Android 架构模式全面分析
android·android jetpack
四眼肥鱼1 天前
flutter 利用flutter_libserialport 实现SQ800 串口通信
前端·flutter
二流小码农1 天前
鸿蒙开发:上传一张参考图片便可实现页面功能
android·ios·harmonyos
鹏程十八少1 天前
4.Android 30分钟手写一个简单版shadow, 从零理解shadow插件化零反射插件化原理
android·前端·面试