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 状态栏图标/文字为 白色(适合深色背景)
相关推荐
zhaoyufei1335 小时前
Android13删除Taskbar
android
消失的旧时光-19437 小时前
Flutter 组件:Row / Column
flutter
6***B487 小时前
存储过程(SQL)
android·数据库·sql
学困昇8 小时前
C++中的异常
android·java·c++
Jerry8 小时前
问题记录 - Android IdleHandler 没有执行
android
没有了遇见8 小时前
Android ButterKnife Android 35情况下 适配 Gradle 8.+
android
方白羽9 小时前
Android多层嵌套RecyclerView滚动
android·java·kotlin
程序员老刘9 小时前
Flutter版本选择指南:3.35稳定,3.38发布 | 2025年11月
flutter·客户端
菜就多学10 小时前
SurfaceControlViewHost 实现跨进程UI渲染
android·设计
2501_9151063210 小时前
iOS App 测试工具全景分析,构建从开发调试到线上监控的多阶段工具链体系
android·测试工具·ios·小程序·uni-app·iphone·webview