使用Flutter开发商用项目,则你必不可少要考虑的一个东西,那就是屏幕适配。回顾一下Android的屏幕适配方案,有以下考虑。
- dp替换px
- fragment适配平板以及使用不同分辨率的布局
- 百分比布局与动态计算控件尺寸
那么Flutter也可以借鉴Android原生的思路。
- 使用flutter_screenutil库,得到考虑分辨率后的单位
- 自适应和动态计算组件大小
适配布局尺寸
如果有设计稿的情况下,适配就变得简单了,建议直接用 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 |
状态栏图标/文字为 白色(适合深色背景) |