flutter:flutter_screenutil第三方适配库

是什么

flutter_screenutil的核心作用就是:按照设计稿的尺寸,自动帮你换算成不同设备上的逻辑像素,从而实现屏幕自适应。

  • 不用自己每次去除以 devicePixelRatioMediaQuery
  • 你只要在写布局时加上 .w.h.sp 等,就能保证在不同分辨率设备上大小一致。

基本使用

安装依赖

dependencies:
  flutter_screenutil: ^5.9.0   # 版本号可能会更新

初始化

你需要在 MaterialApp 外层初始化 ScreenUtil

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

void main() {
  runApp(
    ScreenUtilInit(
      designSize: Size(375, 812), // 设计稿的尺寸(比如 iPhone X 的 375x812)
      minTextAdapt: true,         // 是否根据宽度/高度缩放文字
      splitScreenMode: true,      // 是否支持分屏模式
      builder: (context, child) {
        return MaterialApp(
          debugShowCheckedModeBanner: false,
          title: 'Demo',
          home: child,
        );
      },
      child: MyHomePage(),
    ),
  );
}

designSize 就是 UI 设计稿的逻辑分辨率(常见 375×812、414×896、360×690 等)。

designSize的作用是得到一个缩放比例

scaleWidth  = screenWidth  / designSize.width;
scaleHeight = screenHeight / designSize.height;

这个缩放比例可以用过计算后面的长宽和字体大小等。

独立开发时的处理方式

很多独立开发者其实没有设计师,也不会真的有一份「375×812 的 Sketch/PS/Figma 设计稿」,这个时候自己就选一个基准设备作为“伪设计稿”。

比如最常见的是选一台 常见手机的逻辑分辨率

  • iPhone X (375×812)
  • Android 主流机型 (360×690)

比如你习惯在 iPhone 模拟器上写界面,就直接用:

designSize: Size(375, 812)

使用方法

尺寸适配

Container(
  width: 200.w,   // 根据设计稿宽度200,自适应换算
  height: 100.h,  // 根据设计稿高度100,自适应换算
  color: Colors.blue,
);

字体适配

Text(
  "Hello Flutter",
  style: TextStyle(fontSize: 16.sp), // 根据屏幕缩放字体
);

边距/圆角适配

Padding(
  padding: EdgeInsets.all(10.w), // 水平垂直统一缩放
  child: Container(
    decoration: BoxDecoration(
      borderRadius: BorderRadius.circular(8.r), // 圆角适配
    ),
  ),
);

常用属性

.w → 宽度适配

.h → 高度适配

.sp → 字体大小适配

.r → 圆角、边框等适配

如何计算

designSize = Size(375, 812)可以得到两个缩放比例

scaleWidth  = screenWidth  / designSize.width;
scaleHeight = screenHeight / designSize.height;

然后可以更加这个计算出.w.h.sp.r

200.w  = 200 * scaleWidth = screenWidth * (200/designSize.width);
100.h  = 100 * scaleHeight = screenHeight * (100/designSize.height);

// 如果 minTextAdapt = false(默认):字体只随宽度缩放
fontSize = designFontSize * scaleWidth;
// 如果 minTextAdapt = true:字体会取 宽高中最小的缩放比例,避免因为屏幕特别长导致字体太大。
fontSize = designFontSize * min(scaleWidth, scaleHeight);

8.r = 8 * min(scaleWidth, scaleHeight);

案例

import 'package:flutter/material.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(
      // 基准设计稿尺寸(假设用 iPhone X 375×812)
      designSize: const Size(375, 812),
      minTextAdapt: true, // 字体也能跟随缩放
      builder: (context, child) {
        return MaterialApp(
          debugShowCheckedModeBanner: false,
          home: const HomePage(),
        );
      },
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.grey[100],
      body: Center(
        child: Container(
          width: 300.w, // ✅ 尺寸适配:宽度随屏幕比例变化
          height: 150.h, // ✅ 尺寸适配:高度随屏幕比例变化
          padding: EdgeInsets.all(16.w), // ✅ 边距适配
          decoration: BoxDecoration(
            color: Colors.blue,
            borderRadius: BorderRadius.circular(20.r), // ✅ 圆角适配
          ),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text(
                "标题文本",
                style: TextStyle(
                  fontSize: 24.sp, // ✅ 字体适配
                  fontWeight: FontWeight.bold,
                  color: Colors.white,
                ),
              ),
              SizedBox(height: 10.h), // ✅ 间距适配
              Text(
                "这是副标题,文字会随屏幕缩放",
                style: TextStyle(
                  fontSize: 14.sp, // ✅ 字体适配
                  color: Colors.white70,
                ),
                textAlign: TextAlign.center,
              ),
            ],
          ),
        ),
      ),
    );
  }
}

这是MacOS的模拟器。首先,里面的元素确实都会根据窗口的大小进行调整(通过scaleWidth和scaleHeight)。

但是,如果我们把macOS 的大小变成下面的矩形(width>height),就会报错报错。注意是现在容器高度变小了,字体超出了容器。

两个属性

minTextAdapt

minTextAdapt字体在缩放时,不仅仅跟随宽度,还会考虑高度,取一个最小的缩放因子来保证适配

默认行为(minTextAdapt: false

  • ScreenUtil 计算字体缩放时,通常是根据宽度(screenWidth / designWidth)来算的。
  • 如果某个设备特别「长」或特别「宽」,就可能导致字体大小不合适。

开启后(minTextAdapt: true

  • screenWidth / designWidthscreenHeight / designHeight 两个比例都会算出来。
  • 最小的那个比例作为字体缩放因子。
  • 这样字体在“特别长”或“特别宽”的屏幕上也不会失真。

**举例:**假设设计稿是 375 × 812

设备 实际宽 实际高 宽度比例 高度比例 字体缩放因子
普通 iPhone 375 812 1.0 1.0 1.0
平板横屏 800 600 2.13 0.74 0.74(min)
长屏安卓 360 900 0.96 1.10 0.96(min)

如果没有 minTextAdapt: true,字体可能被放大得很夸张;加上之后,就保持了更自然的效果。

splitScreenMode

splitScreenMode支持分屏/多窗口模式下的适配

默认行为(splitScreenMode: false

  • ScreenUtil 默认取整个物理屏幕的宽高来计算。
  • 但如果你的应用被放在「分屏窗口」里(比如安卓分屏,或者平板的多任务模式),计算出来的比例就不对了。

开启后(splitScreenMode: true

  • ScreenUtil 会使用 当前应用窗口的宽高 进行计算,而不是整个屏幕的宽高。
  • 保证在分屏模式下,布局和字体依然正确。

举例:假设一台平板,物理屏幕是 1600 × 1200。你开了分屏,App 窗口只占一半(800 × 1200)。

模式 获取的宽度 ScreenUtil 基准 结果
默认 1600 按全屏算 字体太大,布局溢出
分屏模式 800 按窗口算 正常显示,和全屏一致比例

案例

import 'package:flutter/material.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),
      // 打开下面两个开关后,对比效果会明显
      minTextAdapt: true, // 是否根据宽高最小值适配字体
      splitScreenMode: true, // 是否支持分屏
      builder: (context, child) {
        return MaterialApp(title: 'ScreenUtil Demo', home: const HomePage());
      },
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("ScreenUtil Demo")),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            // 尺寸适配
            Container(
              width: 200.w,
              height: 100.h,
              decoration: BoxDecoration(
                color: Colors.blue,
                borderRadius: BorderRadius.circular(16.r), // 圆角适配
              ),
              child: Center(
                child: Text(
                  "适配的盒子",
                  style: TextStyle(fontSize: 18.sp), // 字体适配
                ),
              ),
            ),
            const SizedBox(height: 20),

            // 对比字体效果
            Text("字体大小: 18.sp", style: TextStyle(fontSize: 18.sp)),
            Text("字体大小: 固定18", style: const TextStyle(fontSize: 18)),
          ],
        ),
      ),
    );
  }
}

即使设置了 splitScreenMode: false,在 分屏模式 下页面比例依旧正常。

【GPT回答】

flutter_screenutil 文档说,false 时是“只按主屏幕全尺寸计算缩放比例”。

但在实际运行时,很多设备(特别是 Android 和 macOS 窗口应用)里,Flutter 报给 ScreenUtil 的尺寸本身就是 当前窗口的大小
所以就算 splitScreenMode: false,拿到的基准值已经是分屏后的结果了。
自然你就感觉比例“正常”。


它更多是为 某些特殊设备(比如平板、可折叠屏、桌面系统的外接显示器)准备的。
在这些设备上,如果不设 true,可能 ScreenUtil 会坚持用“最大屏幕”来算比例 → 分屏后比例就不对。
但在大多数手机/桌面 Flutter 应用里,窗口变化已经被 Flutter 自动处理,所以 falsetrue 的区别不大。

×

喜欢就点赞,疼爱就打赏