笔者在这篇文章ReactNative全面屏(Android)适配问题提及了现在的全面屏问题,不仅是Android平台,IOS平台也是,给我的感觉就是手机越来越长了。 现在的手机长宽比早就不是之前的16:9了,比如iphoneX 的长宽比为13:6,而现在多数的Android手机都到了19.5:9,有的甚至达到了21:9。 基于科技的发展(适配的血泪史),Flutter开发自然也需要注意这个问题。 在Flutter开发中,通常使用Scaffold的appBar和bottomNavigationBar组件的页面是没有适配问题,它内部对全面屏进行了适配。 适配问题主要是出现在没有使用Scaffold的情况下。 看一下这段代码,没有使用Scaffold:
1class MyApp extends StatelessWidget { 2 @override 3 Widget build(BuildContext context) { 4 return MaterialApp( 5 title: 'Flutter Demo', 6 theme: ThemeData( 7 primarySwatch: Colors.blue, 8 ), 9 home: Container( 10 color: Colors.white, 11 child: Column( 12 mainAxisAlignment: MainAxisAlignment.spaceBetween, 13 children: <Widget>[ 14 Container( 15 color: Colors.lightBlue, 16 child: Text('头部'), 17 ), 18 Container( 19 color: Colors.redAccent, 20 child: Text('底部'), 21 ) 22 ], 23 ), 24 ) 25 ); 26 } 27}
运行效果如下:

可以看到上面和下面的组件已经被遮挡了,这就出现了适配问题,适配的主要问题就是集中在如下两点:
- 顶部的NavigationBar预留安全区域
- 底部的NavigationBar预留安全区域
对于以上两种问题,Flutter给出了除上面使用Scaffold,还有如下两种方案:
- 使用Flutter框架提供的SafeArea,Widget进行包裹组件来适配全面屏,这个组件和ReactNative框架中的SafeAreaView这个组件差不多效果,从两个名字就可以看出来,😀。
- 可以通过Flutter系统提供的MediaQuery.of(context).padding 这个Api来获取上下左右的安全padding,根据这个padding进行适配,更加灵活性。
接下来具体看一下这两个方案的使用
使用SafeArea适配
这个使用比较简单,只要需要将组件进行包裹即可,
1home: SafeArea(child: Container( 2 color: Colors.white, 3 child: Column( 4 mainAxisAlignment: MainAxisAlignment.spaceBetween, 5 children: <Widget>[ 6 Container( 7 color: Colors.lightBlue, 8 child: Text('头部'), 9 ), 10 Container( 11 color: Colors.redAccent, 12 child: Text('底部'), 13 ) 14 ], 15 ), 16 ))
使用MediaQuery.of(context).padding适配
1home位置修改为如下代码: 2home: SafePage() 3------------------- 4创建一个SafePage 5class SafePage extends StatelessWidget{ 6 @override 7 Widget build(BuildContext context) { 8 EdgeInsets paddings = MediaQuery.of(context).padding; 9 return Container( 10 color: Colors.white, 11 padding: EdgeInsets.fromLTRB(0, paddings.top, 0, paddings.bottom), 12 child: Column( 13 mainAxisAlignment: MainAxisAlignment.spaceBetween, 14 children: <Widget>[ 15 Container( 16 color: Colors.lightBlue, 17 child: Text('头部'), 18 ), 19 Container( 20 color: Colors.redAccent, 21 child: Text('底部'), 22 ) 23 ], 24 ), 25 ); 26 } 27}
以上两种方案运行效果如下图,可以看到头部和底部已经正常显示了。 
上面这两种方案适用于IOS和Android两个平台,对于Android平台的适配在ReactNative全面屏(Android)适配问题也提到了另外的一种方案,看大家的实际需要,来采取合适的适配方案。
查看一下SafeArea这个Widget组件的源码,可以看到其实内部也是采用了上面提到的第二种方案,相当于SafeArea对第二种方案的封装,开发中使用起来更方便一下,源码如下
1@override 2 Widget build(BuildContext context) { 3 assert(debugCheckHasMediaQuery(context)); 4 /// 如下五行代码就是SafeArea可以进行适配的原因, 5 final MediaQueryData data = MediaQuery.of(context); 6 EdgeInsets padding = data.padding; 7 // Bottom padding has been consumed - i.e. by the keyboard 8 if (data.padding.bottom == 0.0 && data.viewInsets.bottom != 0.0 && maintainBottomViewPadding) 9 padding = padding.copyWith(bottom: data.viewPadding.bottom); 10 11 return Padding( 12 padding: EdgeInsets.only( 13 left: math.max(left ? padding.left : 0.0, minimum.left), 14 top: math.max(top ? padding.top : 0.0, minimum.top), 15 right: math.max(right ? padding.right : 0.0, minimum.right), 16 bottom: math.max(bottom ? padding.bottom : 0.0, minimum.bottom), 17 ), 18 child: MediaQuery.removePadding( 19 context: context, 20 removeLeft: left, 21 removeTop: top, 22 removeRight: right, 23 removeBottom: bottom, 24 child: child, 25 ), 26 ); 27 }
截图可能看起来更方便,注意看红框部分 
关于Flutter的全面屏适配先分享这些。
欢迎关注我的公众号:君伟说。分享移动开发技术,职场生活和工作中的酸甜苦辣。