移动应用 活跃维护

flutter_screenutil

OpenFlutter/flutter_screenutil

Flutter 屏幕适配、字体适配、获取屏幕信息

4016
Stars 标星
509
Forks 分支
57
Watchers 关注
33
Open Issues
Dart
主要语言
Apache-2.0
开源协议
3.8 MB
仓库大小
1 年前
最后推送
一键安装扩展 / 插件指令
dsh plugin --profile web add github:OpenFlutter/flutter_screenutil
git clone https://github.com/OpenFlutter/flutter_screenutil.git
git clone git@github.com:OpenFlutter/flutter_screenutil.git
README.md master

英文原文正文为项目原始 README(英文),本站后续会翻译为中文,当前仅剔除图片与无关章节并统一排版。

flutter_screenutil

一个用于适配屏幕和字体大小的 Flutter 插件。让你的 UI 在不同屏幕尺寸上显示合理的布局!

注意:该插件仍在开发中,某些 API 可能尚不可用。

中文文档

葡萄牙语自述文件

github

更新日志

使用

添加依赖

安装前请检查最新版本。如果新版本有任何问题,请使用之前的版本

dependencies:
  flutter:
    sdk: flutter
  # add flutter_screenutil
  flutter_screenutil: ^{latest version}

将以下导入添加到你的 Dart 代码中

import 'package:flutter_screenutil/flutter_screenutil.dart';

属性

属性 类型 默认值 描述
designSize 尺寸 尺寸(360,690) 设计稿中设备屏幕的尺寸,单位为 dp
builder 功能 null 返回使用库的属性的小部件(例如:MaterialApp 的主题)
child 小部件 null builder 的一部分,其依赖项/属性不使用该库
rebuildFactor 函数 default 接收旧的和新的屏幕指标并返回在发生变化时是否需要重建的函数。
splitScreenMode 布尔值 false 支持分屏显示
minTextAdapt 布尔值 false 是否根据宽度和高度的最小值调整文本
context BuildContext null 如果未提供,则通过 MediaQuery.of(context) 获取物理设备数据
fontSizeResolver 函数 default 指定如何调整字体大小的函数。默认情况下字体大小随屏幕宽度缩放
responsiveWidgets 可迭代 null 应包含在重建树中的小部件名称列表/集合(参见 如何标记小部件需要重建)
excludeWidgets 可迭代 null 应从重建树中排除的小部件名称列表/集合
enableScaleWH 函数 null 支持启用宽度和高度缩放
enableScaleText 函数 null 支持启用文本缩放

注意:你必须提供 builder、child 或两者都提供。

重建列表

从版本 5.9.0 开始,ScreenUtilInit 不会重建整个小部件树,而只会标记需要重建的小部件,前提是:

  • 小部件不是 flutter 小部件(小部件可在 Flutter 文档 中查找)
  • 小部件名称不以下划线(_)开头
  • 小部件未声明 SU 混入
  • responsiveWidgets 不包含小部件名称

如果你有一个使用该库的小部件且不符合这些条件,你可以添加 SU 混入或将小部件名称添加到 responsiveWidgets 列表中。

初始化并设置适合的尺寸和字体大小,以根据系统的“字体大小”辅助功能选项进行缩放

请在使用前设置设计稿的尺寸,即设计稿的宽度和高度。

第一种方法(您应该在应用中使用一次)

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    //Set the fit size (Find your UI design, look at the dimensions of the device screen and fill it in,unit in dp)
    return ScreenUtilInit(
      designSize: const Size(360, 690),
      minTextAdapt: true,
      splitScreenMode: true,
      // Use builder only if you need to use library outside ScreenUtilInit context
      builder: (_ , child) {
        return MaterialApp(
          debugShowCheckedModeBanner: false,
          title: 'First Method',
          // You can use the library anywhere in the app even in theme
          theme: ThemeData(
            primarySwatch: Colors.blue,
            textTheme: Typography.englishLike2018.apply(fontSizeFactor: 1.sp),
          ),
          home: child,
        );
      },
      child: const HomePage(title: 'First Method'),
    );
  }
}

第二种方法:你需要一个技巧来支持应用主题的 textTheme 中的字体适配

混合开发使用第二种方法

不支持这个:

MaterialApp(
  ...
  //To support the following, you need to use the first initialization method
  theme: ThemeData(
    textTheme: TextTheme(
      button: TextStyle(fontSize: 45.sp)
    ),
  ),
)

但是你可以这样做:

void main() async {
  // Add this line
  await ScreenUtil.ensureScreenSize();
  runApp(MyApp());
}
...
MaterialApp(
  ...
  builder: (ctx, child) {
    ScreenUtil.init(ctx);
    return Theme(
      data: ThemeData(
        primarySwatch: Colors.blue,
        textTheme: TextTheme(bodyText2: TextStyle(fontSize: 30.sp)),
      ),
      child: HomePage(title: 'FlutterScreenUtil Demo'),
    );
  },
)
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Flutter_ScreenUtil',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: HomePage(title: 'FlutterScreenUtil Demo'),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    //Set the fit size (fill in the screen size of the device in the design) 
    //If the design is based on the size of the 360*690(dp)
    ScreenUtil.init(context, designSize: const Size(360, 690));
    ...
  }
}

注意:第二次调用 ScreenUtil.init 时,任何未提供的参数将不会被替换为默认值。请改用 ScreenUtil.configure

应用程序接口

启用或禁用缩放

  Widget build(BuildContext context) {
    return ScreenUtilInit(
      enableScaleWH: ()=>false,
      enableScaleText: ()=>false,
      //...
    );
  }

或

ScreenUtil.enableScale(enableWH: () => false, enableText: () => false);

传递设计稿的 dp 尺寸

    ScreenUtil().setWidth(540)  (dart sdk>=2.6 : 540.w) //Adapted to screen width
    ScreenUtil().setHeight(200) (dart sdk>=2.6 : 200.h) //Adapted to screen height , under normal circumstances, the height still uses x.w
    ScreenUtil().radius(200)    (dart sdk>=2.6 : 200.r)    //Adapt according to the smaller of width or height
    ScreenUtil().setSp(24)      (dart sdk>=2.6 : 24.sp) //Adapter font
    12.sm   //return min(12,12.sp)

    ScreenUtil().pixelRatio       //Device pixel density
    ScreenUtil().screenWidth   (dart sdk>=2.6 : 1.sw)    //Device width
    ScreenUtil().screenHeight  (dart sdk>=2.6 : 1.sh)    //Device height
    ScreenUtil().bottomBarHeight  //Bottom safe zone distance, suitable for buttons with full screen
    ScreenUtil().statusBarHeight  //Status bar height , Notch will be higher
    ScreenUtil().textScaleFactor  //System font scaling factor

    ScreenUtil().scaleWidth //The ratio of actual width to UI design
    ScreenUtil().scaleHeight //The ratio of actual height to UI design

    ScreenUtil().orientation  //Screen orientation
    0.2.sw  //0.2 times the screen width
    0.5.sh  //50% of screen height
    20.setVerticalSpacing  // SizedBox(height: 20 * scaleHeight)
    20.horizontalSpace  // SizedBox(height: 20 * scaleWidth)
    const RPadding.all(8)   // Padding.all(8.r) - take advantage of const key word
    EdgeInsets.all(10).w    //EdgeInsets.all(10.w)
    REdgeInsets.all(8)       // EdgeInsets.all(8.r)
    EdgeInsets.only(left:8,right:8).r // EdgeInsets.only(left:8.r,right:8.r).
    BoxConstraints(maxWidth: 100, minHeight: 100).w    //BoxConstraints(maxWidth: 100.w, minHeight: 100.w)
    Radius.circular(16).w          //Radius.circular(16.w)
    BorderRadius.all(Radius.circular(16)).w  

适配屏幕尺寸

传入设计稿的 dp 尺寸(单位与初始化时相同):

适配屏幕宽度:ScreenUtil().setWidth(540),

适配屏幕高度:ScreenUtil().setHeight(200),一般情况下,高度最好适配宽度

如果你的 dart sdk >= 2.6,你可以使用扩展函数:

示例:

代替:

Container(
  width: ScreenUtil().setWidth(50),
  height:ScreenUtil().setHeight(200),
)

你可以这样使用它:

Container(
  width: 50.w,
  height:200.h
)

Note

高度也可以使用 setWidth 来确保不变形(当你想要一个正方形时)

setHeight 方法主要是为了适应高度,用于当你想在 UI 上控制屏幕高度与实际显示一致时。

一般来说,50.w != 50.h。

//for example:

//If you want to display a rectangle:
Container(
  width: 375.w,
  height: 375.h,
),

//If you want to display a square based on width:
Container(
  width: 300.w,
  height: 300.w,
),

//If you want to display a square based on height:
Container(
  width: 300.h,
  height: 300.h,
),

//If you want to display a square based on minimum(height, width):
Container(
  width: 300.r,
  height: 300.r,
),

适配器字体

//Incoming font size(The unit is the same as the unit at initialization)
ScreenUtil().setSp(28) 
28.sp

//for example:
Column(
  crossAxisAlignment: CrossAxisAlignment.start,
  children: <Widget>[
    Text(
      '16sp, will not change with the system.',
      style: TextStyle(
        color: Colors.black,
        fontSize: 16.sp,
      ),
      textScaleFactor: 1.0,
    ),
    Text(
      '16sp,if data is not set in MediaQuery,my font size will change with the system.',
      style: TextStyle(
        color: Colors.black,
        fontSize: 16.sp,
      ),
    ),
  ],
)

设置字体不会随系统字体大小更改

APP 全局:

MaterialApp(
  debugShowCheckedModeBanner: false,
  title: 'Flutter_ScreenUtil',
  theme: ThemeData(
    primarySwatch: Colors.blue,
  ),
  builder: (context, widget) {
    return MediaQuery(
      ///Setting font does not change with system font size
      data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0),
      child: widget,
    );
  },
  home: HomePage(title: 'FlutterScreenUtil Demo'),
),

指定文本:

Text("text", textScaleFactor: 1.0)

指定的组件:

MediaQuery(
  // If there is no context available you can wrap [MediaQuery] with [Builder]
  data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0),
  child: AnyWidget(),
)

组件测试

示例

示例演示

要使用第二种方法运行:flutter run --dart-define=method=2

效果

版本 5.9.0 更新(测试)

在 #515 中报告为错误

在版本 5.9.0 中,为确保测试的兼容性和正确运行,在进行依赖动画或需要完成状态的稳定时间的组件测试时,必须使用方法 tester.pumpAndSettle()。

在之前的版本中,这一步骤并不是严格必要的。然而,为了在测试中保持一致性并避免意外错误,如果您使用的是版本 5.9.0,强烈建议在您的小部件测试中加入 await tester.pumpAndSettle();

示例用法:

testWidgets('Should ensure widgets settle correctly', (WidgetTester tester) async {
await tester.pumpWidget(
  const MaterialApp(
    home: ScreenUtilInit(
      child: MyApp(),
    ),  
  ),
);
// Insertion of recommended method to prevent failures
await tester.pumpAndSettle();
// Continue with your assertions and tests
});
本站来源与版权声明
  • 本文标题:flutter_screenutil - Flutter 屏幕适配
  • 本文链接:https://www.cn121.com/mobile/openflutter-flutter-screenutil.html
  • 原项目:OpenFlutter/flutter_screenutil 版权归原作者 OpenFlutter 及贡献者所有
  • 收录信息:本站于 2026-10-21 收录本项目,本页所列协议与仓库指标均为收录当时的状态;该日期之后原项目的版本更新与协议变更,本页不作同步。
  • 开源协议:收录时本项目采用 Apache-2.0(查看 LICENSE 原文),本站转载其原始文档(未改动文字,仅剔除图片与无关章节);使用、修改、分发请以该仓库 LICENSE 原文为准。本站对原文仅作排版与图片地址适配, 并保留原项目的 NOTICE 与署名要求。
  • 站点出处:本文首发于 OneTwoOne,收录自 GitHub 开源项目 OpenFlutter/flutter_screenutil。
  • 内容说明:本页正文为原项目 README 原文(英文),本站后续会翻译为中文(当前尚未译出,仅将二级标题译为中文,便于按栏目定位;标题原文可在下方原仓库中查看),仅剔除了图片与赞助等无关章节、并把相对链接改为绝对地址;页首简介为机器翻译自仓库描述。
  • 引用声明:商业转载、第三方聚合或 AI 检索训练引用时,请务必保留以上来源出处、本文永久链接,以及原项目的版权声明与许可信息。
  • 下架通道:若原项目此后变更或收紧了许可协议、或作者/权利人认为本站的收录方式(译文、排版适配、简介翻译等)超出其授权范围,请通过 xyd3302001@163.com 发送下架通知,并附上项目地址与本页链接。本站核实后将第一时间删除本页内容,或改为不复制原文的目录性收录;署名更正等其他要求可一并提出。