初始化配置
// 设置屏幕宽高比
//If the design is based on the size of the iPhone6 (iPhone6 750*1334)
ScreenUtil.instance = ScreenUtil(width: 750, height: 1334)..init(context);
print('设置像素密度:${ScreenUtil.pixelRatio}');
print('设置的高度:${ScreenUtil.screenHeight}');
print('设置的宽度:${ScreenUtil.screenWidth}');
使用
1.设置字体大小
fontSize: ScreenUtil().setSp(26)
2.设置宽高
width: ScreenUtil.setWidth(750),
height: ScreenUtil.setHeight(333),
依赖下载
# 屏幕适配 https://github.com/OpenFlutter/flutter_screenutil
flutter_screenutil: ^0.6.0
适配要点
- 顶部
NavigationBar
上部预留安全区域 - 底部
NavigationBar
底部预留安全区域
对于安全区域的适配有两种方案
- 1.采用
SafeArea
来包裹页面,SafeArea
是Flutter中一个用于适配全面屏的组件,它类似于RN中的SafeAreaView
主要是用于解决适配全屏手机的安全区域问题 - 2.借助MediaQuery.of(context).padding 获取屏幕四周的padding,然后根据padding自己手动实现对安全区域的控制
- 方案一:相对简单,只需要引入SafeArea,但不够灵活
- 方案二:需要借助MediaQuery.of(context).padding 自己实现对安全区域的控制,相对复杂些,但灵活度高;
①采用SafeArea
适应全面屏
import 'package:flutter/material.dart';
class MemberPage extends StatefulWidget {
@override
_MemberPageState createState() => _MemberPageState();
}
class _MemberPageState extends State {
@override
void initState() {
// TODO: implement initState
super.initState();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '全面屏适配',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Container(
decoration: BoxDecoration(color: Colors.white),
child: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("顶部"),
Text("底部"),
],
),
),
),
);
}
}
②借助MediaQuery.of(context).padding 自己实现对安全区域的控制
补充常见问题
1.部件溢出
A RenderFlex overflowed by 22 pixels on the bottom.
//原因:在水平或者垂直方向上的内容超过了父部件的大小
//解决办法
包一层SingleChildScrollView,让你的页面可以滑动起来。
在Scaffold中设置resizeToAvoidBottomInset为false。默认为ture,防止部件被遮挡。如果使用了这个方法,如果底部有输入框,则会造成遮挡。
2.输入框遮挡
Column配合Expanded来实现
3.SafeArea
一旦有部件固定在顶部或者底部(严谨点的话可以说是在屏幕的四边)。那我我们最好使用SafeArea来包一下。因为Android 和 IOS都有状态栏,甚至IOS还有叫做“HomeIndicator”的横条。所以一不留神就会出现适配问题
使用方法为
Material( // 需要颜色填充到边界区域可以使用
color: Colors.white,
child: SafeArea(
child: Container(),
),
)
4.注意平台差异
注意部分组件在Android与IOS平台之间的差异。
Scaffold
的 AppBar
,AppBar
中默认的title
在Android中靠左显示,IOS中居中显示。如果需要两个平台效果统一,需要设置在AppBar
中主动设置centerTitle
属性。同时AppBar
的返回箭头图标也不相同,统一的话需要自定义leading
。
页面跳转如果使用MaterialPageRoute来做过渡效果,注意Android中新的页面会从屏幕底部滑动到屏幕顶部,IOS中新的页面会从屏幕右侧滑动到屏幕左侧。
如果需要两个平台效果统一,我们不使用自带效果,可以自定义一个。
①.SlideTransition
///自定义跳转
Navigator.push(context, PageRouteBuilder(transitionDuration: Duration(milliseconds: 300),
pageBuilder: (context, animation, secondaryAnimation){
return new SlideTransition( //实现相对自身的位移
position: Tween(
begin: const Offset(0.0, 0.02),
end: Offset.zero,
).animate(animation),
child: DiscoverChildPage(title: widget.title,),
);
})
);
②2.FadeTransition
///自定义跳转
Navigator.push(context, PageRouteBuilder(transitionDuration: Duration(milliseconds: 300),
pageBuilder: (context, animation, secondaryAnimation){
return new FadeTransition( //使用渐隐渐入过渡,
opacity: animation,
child: DiscoverChildPage(title: widget.title,),
);
})
);
5.依赖版本设置
首先这里建议凡是Flutter的插件在填写版本号时不要使用^
符号。
^符号意味着你可以使用此插件的最新版本(大于等于当前版本)。这会导致什么问题呢?可能你前一天代码还能跑起来,今天就编译出错了。因为这些插件中包括Android、IOS的所用依赖环境配置,常见的就是新版本使用了AndroidX的依赖,但是还有些插件并没有使用AndroidX,导致了两者的冲突。
6.Flutter iOS 和 Android 统一左上角返回按钮
思路:自定义leading
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {
print('返回上一页');
Navigator.pop(context);
},
),
title: Text('商品详细页'),
),
自定义leading
static Widget leading (BuildContext context, {Color color}) {
return GestureDetector(
onTap: () {
Navigator.of(context).maybePop();
},
child: Icon(
Icons.arrow_back_ios,
size: 20,
color: color ?? Colors.white
),
);
}
屏幕相关
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:ui' as ui show window;
class Screen {
static double get width {
MediaQueryData mediaQuery = MediaQueryData.fromWindow(ui.window);
return mediaQuery.size.width;
}
static double get height {
MediaQueryData mediaQuery = MediaQueryData.fromWindow(ui.window);
return mediaQuery.size.height;
}
static double get scale {
MediaQueryData mediaQuery = MediaQueryData.fromWindow(ui.window);
return mediaQuery.devicePixelRatio;
}
static double get textScaleFactor {
MediaQueryData mediaQuery = MediaQueryData.fromWindow(ui.window);
return mediaQuery.textScaleFactor;
}
static double get navigationBarHeight {
MediaQueryData mediaQuery = MediaQueryData.fromWindow(ui.window);
return mediaQuery.padding.top + kToolbarHeight;
}
static double get topSafeHeight {
MediaQueryData mediaQuery = MediaQueryData.fromWindow(ui.window);
return mediaQuery.padding.top;
}
static double get bottomSafeHeight {
MediaQueryData mediaQuery = MediaQueryData.fromWindow(ui.window);
return mediaQuery.padding.bottom;
}
static updateStatusBarStyle(SystemUiOverlayStyle style) {
SystemChrome.setSystemUIOverlayStyle(style);
}
}