Flutter进阶(3):屏幕和字体适配专家(ScreenUtil)

 


一、简介

flutter_screenutil 是一个 Flutter 插件,专门用于处理屏幕适配问题。它简化了不同设备间尺寸差异的处理,确保你的应用在各种屏幕上都能保持良好的显示效果。开发者可以通过简单的调用来设置基于设计图尺寸的控件宽高和字体大小。

项目地址:https://github.com/OpenFlutter/flutter_screenutil.git

二、属性

属性 类型 默认值 描述
designSize Size Size(360, 690) 设计稿中设备的尺寸(单位随意,建议 dp,但在使用过程中必须保持一致)
builder Widget Function() Container() 一般返回一个 MaterialApp 类型的 Function()
orientation Orientation portrait 屏幕方向
splitScreenMode bool true 支持分屏尺寸

二、使用方法

(1)添加依赖

在你的项目 pubspec.yaml 文件中添加 flutter_screenutil 依赖:

dependencies:
  flutter_screenutil: ^5.9.3

然后执行 pub get 来下载并安装依赖。


(2)初始化

flutter_screenutil 提供了两种方式进行初始化:ScreenUtilInit 方式和 ScreenUtil.init 方式。首先在使用的地方导入包:

import 'package:flutter_screenutil/flutter_screenutil.dart';

ScreenUtilInit 方式

使用 ScreenUtilInit 方式进行初始化,需要将项目的 MaterialApp 进行一层包裹,然后在 builder 中返回项目本身的 MaterialApp ,在 ScreenUtilInit 的 designSize 参数中传入设计图的尺寸,实现如下:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ScreenUtilInit(
      designSize: Size(360, 690), // 传入设计图尺寸
      builder: () => MaterialApp(
        ...
      ),
    );
  }
}

ScreenUtil.init 方式:

直接使用 ScreenUtil.init 方法,传入屏幕尺寸、设计图尺寸和屏幕方向即可对 flutter_screenutil 进行初始化,代码如下:

ScreenUtil.init(
  BoxConstraints(
    maxWidth: MediaQuery.of(context).size.width,  //屏幕宽度
    maxHeight: MediaQuery.of(context).size.height, //屏幕高度
  ),
  designSize: const Size(360, 690), // 设计图尺寸
  orientation: Orientation.portrait); // 屏幕方向

使用这种方式只需在使用 flutter_screenutil 前进行初始化即可,一般放在根路由即第一个页面加载的时候进行初始化。

注意:ScreenUtil.init 不能在 MyApp 中进行初始化,会报如下错误 No MediaQuery ancestor could be found starting from the context that was passed to MediaQuery.of(). This can happen because you have not added a WidgetsApp, CupertinoApp, or MaterialApp widget (those widgets introduce a MediaQuery), or it can happen if the context you use comes from a widget above those widgets. 因为这个时候还没加载 MaterialApp 无法使用 MediaQuery.of(context ) 获取到屏幕宽高


(3)使用

初始化以后就可以使用 flutter_screenutil 提供的方法获取到适配后的数值进行使用了。

可通过如下 api 获取宽高以及字体的适配数值:

ScreenUtil().setWidth(540)  // 根据屏幕宽度适配尺寸
ScreenUtil().setHeight(200) // 根据屏幕高度适配尺寸(一般根据宽度适配即可)
ScreenUtil().radius(200)    // 根据宽度或高度中的较小者进行调整
ScreenUtil().setSp(24)      // 字体大小适配

传入的参数即为设计图上的大小。在实际使用中的示例如下:

Container(
  width: ScreenUtil().setWidth(200),
  height: ScreenUtil().setHeight(540),
  child: Text("Hello", style: TextStyle(fontSize: ScreenUtil().setSp(24)),),
);

这样即可使用适配的数值进行开发。


但发现这样写太麻烦了,为了获取一个适配的数值,要写一串的很长的代码。flutter_screenutil 提供了更简洁的调用方法,使用 Dart 扩展为 num 类型扩展了一系列属性可以方便开发者调用,上面的 api 可以通过扩展属性进行如下转换:

ScreenUtil().setWidth(540)  =>  540.h
ScreenUtil().setHeight(200) =>  200.w
ScreenUtil().radius(200)    =>  200.r
ScreenUtil().setSp(24)      =>  24.sp

修改后的使用示例如下:

Container(
  width: 200.w,
  height: 540.h,
  child: Text("Hello", style: TextStyle(fontSize: 24.sp),),
);

这样就简洁多了。


四、适配字体

除了上面 4 种扩展属性以外,还提供了 sm 以及 swsh

  • sm :取数值本身与 sp 的值最小的值,如 12.sm 则取 1212.sp 的值进行比较,取最小的值。

  • sw :screen width 的缩写,即屏幕宽度,作用是按屏幕宽度比例返回值。如 0.2.sw 则返回屏幕宽度的 20%,1.sw 则是整个屏幕宽度

  • sh :screen height 的缩写,及屏幕高度,作用与sw类似,返回指定比例的屏幕高度值。如 1.sh 为整个屏幕高度

使用 sp 作为字体单位,默认是会随着系统字体缩放进行变化,如果不想字体随着系统缩放而变化,可设置 textScaleFactor1.0 来实现。

// for example:
Column(
	crossAxisAlignment: CrossAxisAlignment.start,
	children: <Widget>[
		Text(
			'我的文字大小在设计稿上是16dp,因为设置了`textScaleFactor`,所以不会随着系统的文字缩放比例变化',
      style: TextStyle(
      color: Colors.black,
      fontSize: 16.sp,
			),
			textScaleFactor: 1.0,
		),
		Text(
			'我的文字大小在设计稿上是16dp,会随着系统的文字缩放比例变化',
			style: TextStyle(
				color: Colors.black,
				fontSize: 16.sp,
			),
		),
	],
)

设置字体不随系统字体大小进行改变

项目中可对 MaterialApp 进行全局设置或者对 Text 进行单独设置:

全局设置:

MaterialApp(
        debugShowCheckedModeBanner: false,
        title: 'Flutter_ScreenUtil',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        builder: (context, widget) {
          return MediaQuery(
            ///设置文字大小不随系统设置改变
            data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0),
            child: widget,
          );
        },
        home: HomePage(title: 'FlutterScreenUtil Demo'),
      ),

Text 单独设置:

Text("text", textScaleFactor: 1.0)

五、API 参考

ScreenUtil().setWidth(540)  (sdk>=2.6 : 540.w)   // 根据屏幕宽度适配尺寸
ScreenUtil().setHeight(200) (sdk>=2.6 : 200.h)   // 根据屏幕高度适配尺寸(一般根据宽度适配即可)
ScreenUtil().radius(200)    (sdk>=2.6 : 200.r)   // 根据宽度或高度中的较小者进行调整
ScreenUtil().setSp(24)      (sdk>=2.6 : 24.sp)   // 适配字体

ScreenUtil.pixelRatio       // 设备的像素密度
ScreenUtil.screenWidth   (sdk>=2.6 : 1.sw)   // 设备宽度
ScreenUtil.screenHeight  (sdk>=2.6 : 1.sh)   // 设备高度
ScreenUtil.bottomBarHeight  // 底部安全区距离,适用于全面屏下面有按键的
ScreenUtil.statusBarHeight  // 状态栏高度 刘海屏会更高
ScreenUtil.textScaleFactor // 系统字体缩放比例

ScreenUtil().scaleWidth  // 实际宽度设计稿宽度的比例
ScreenUtil().scaleHeight // 实际高度与设计稿高度度的比例

ScreenUtil().orientation  // 屏幕方向

0.2.sw  // 屏幕宽度的0.2倍
0.5.sh  // 屏幕高度的50%

六、代码示例

在应用的入口或 MaterialApp 的 builder 中初始化 ScreenUtil,并设置设计稿的尺寸:

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(360, 690), // 设置设计稿的尺寸
      builder: (_, child) => MaterialApp(
        title: 'Flutter ScreenUtil Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: HomePage(),
      ),
    );
  }
}

然后,在你的 UI 代码中,使用 ScreenUtil 类提供的方法设置尺寸和字体大小:

class HomePage extends StatelessWidget {
  const HomePage({super.key});
  @override
  Widget build(BuildContext context) {
    // 初始化ScreenUtil
    ScreenUtil.init(context, designSize: const Size(360, 690));

    return Scaffold(
      appBar: AppBar(
        title: Text(
          'ScreenUtil Demo',
          style: TextStyle(
            fontSize: 20.sp, // 使用 '.sp' 来设置字体大小
          ),
        ),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'This is a text',
              style: TextStyle(
                fontSize: 24.sp, // 为文字大小使用 'sp'
              ),
            ),
            SizedBox(height: 12.h), // 在高度上使用 '.h'
            Container(
              width: 180.w, // 在宽度上使用 '.w'
              height: 200.h, // 在高度上使用 '.h'
              color: Colors.blue,
              child: Text(
                'This box will adapt to the screen width!',
                style: TextStyle(fontSize: 16.sp),
                textAlign: TextAlign.center,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

在上面的代码示例中:

  • ScreenUtil.init 方法设置了设计稿尺寸(设计时指定的屏幕尺寸)。这应该是你一开始就调用的,以便 ScreenUtil 可以使用这些信息进行适配。
  • sp 单位用来确保文字大小在不同设备上看起来相同。它会考虑设备的文字缩放设置。
  • wh 单位用来按设计稿的尺寸进行宽度和高度的适配。

使用 flutter_screenutil 插件时需要注意的是,使用它设置的尺寸是在运行时计算的,它们会根据实际设备屏幕的尺寸和密度与设计稿之间的比例进行调整。但并不是所有的 UI 元素都需要使用 flutter_screenutil 进行适配,有时候简单的 flex 布局或者媒体查询(MediaQuery)可能就足够了。

适配屏幕大小主要是为了保持布局在不同大小和分辨率的设备上的一致性。例如,对于较为复杂的布局或是具体的定制化设计,使用 flutter_screenutil 可以确保元素的大小更加精确地反映设计师的意图。

效果图如下所示:

Flutter_screen_A.png


posted @   fengMisaka  阅读(1034)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· 【.NET】调用本地 Deepseek 模型
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
点击右上角即可分享
微信分享提示