什么黑科技?实现Flutter跨平台屏幕适配

1,116 阅读4分钟
原文链接: mp.weixin.qq.com

码个蛋(codeegg)第 713 次推文

作者:buaashui

博客:https://www.jianshu.com/p/143fb2111f96

前言

采用flutter开发APP已经1年多了,平时开发的过程中踩过很多坑,今天想分享一个flutter应用跨平台适配的解决方案,目的是让你的flutter应用可以灵活高效的自动适配各种平台,实现UI最大化复用,业务逻辑代码在不同平台间能够共享。

下图描述了flutter-adapter的整体实现方案,我们在APP的入口处设置当前APP所运行的平台,这个平台可以在实际使用的时候动态设置,然后对于每个widget,我们只需要实现特定平台的样式适配即可。个别widget在不同平台的表现可能仅仅是部分属性的数值不同而已,对于属性值的垮平台适配我们提供了一个通用的函数superObjectAdapter去解决这个问题。

不同平台适配效果

手机竖屏

平板竖屏

平板横屏

使用方式

flutter_adapter插件内置了3类平台,分别是:手机(TEAdaptPlatform.phone)、pad横屏(TEAdaptPlatform.padLandscape)、pad竖屏(TEAdaptPlatform.padPortrait)。 如果你只适配部分平台,那么只需要对待适配的widget实现特定平台的build函数即可,其他未适配的平台默认会返回Phone的样式。使用的时候只需要在APP的入口处采用ScreenAdaptWidget,然后设置当前APP需要适配的平台名称即可。

如果你需要扩展适配的平台,对于StatelessWidget只需要实现一个继承自FlexibleStatelessWidget的抽象类,然后实现新平台的build函数并注册该平台即可;对于StatefulWidget只需要实现一个继承自FlexibleState的抽象类,然后实现新平台的build函数并注册该平台即可。

插件使用示例:

ScreenAdaptWidget(  platform: TEAdaptPlatform.phone.toString(),  child: 任意widget)),

如果你的某个StatelessWidget需要适配特定平台,只需要将该widget继承自FlexibleStatelessWidget,然后实现特定平台的build函数即可。

StatelessWidget适配示例:

class MyStatelessPage extends FlexibleStatelessWidget {  @override  Widget buildPhone(BuildContext context) {    return Text('Phone',style: TextStyle(fontSize: 18.0),);  }  @override  Widget buildPadPortrait(BuildContext context) {    return Text('PadPortrait',style: TextStyle(fontSize: 22.0),);  }  @override  Widget buildPadLandscape(BuildContext context) {    return Text('PadLandscape',style: TextStyle(fontSize: 30.0),);  }

StatefulWidget适配示例:

如果你的某个StatefulWidget需要适配特定平台,只需要将该StatefulWidget对应的的State继承自FlexibleState,然后实现特定平台的build函数即可,例如:

class MyStatefulPageState extends FlexibleState<MyStatefulPage> {  @override  Widget buildPhone(BuildContext context) {    return Text('Phone',style: TextStyle(fontSize: 18.0),);  }  @override  Widget buildPadPortrait(BuildContext context) {    return Text('PadPortrait',style: TextStyle(fontSize: 22.0),);  }  @override  Widget buildPadLandscape(BuildContext context) {    return Text('PadLandscape',style: TextStyle(fontSize: 30.0),);  }}

普通Widget适配示例:

如果你的某个widget仅仅需要在不同平台中改变个别属性的值,那么只需要对特定的属性值进行跨平台适配即可,flutter_adapter提供了superObjectAdapter函数来解决属性值的跨平台适配难题。

class MyNormalPage extends StatelessWidget {  final String textStr;   MyNormalPage(this.textStr); @override  Widget build(BuildContext context) {   return Scaffold(    appBar: AppBar(    title: const Text('page normal'),   ),   body: Column(    children: <Widget>[    Container(     padding: EdgeInsets.all(10.0),     margin: EdgeInsets.only(bottom: 30.0),     width: double.infinity,     height: 100.0,     color: superObjectAdapter(context, {TEAdaptPlatform.phone.toString(): Colors.yellow, TEAdaptPlatform.padPortrait.toString(): Colors.greenAccent}),     child: Center(      child: Text(       '$textStr ${superObjectAdapter(context, {       TEAdaptPlatform.phone.toString(): "[Phone]",       TEAdaptPlatform.padPortrait.toString(): "[PadPortrait]"       })}',       style: TextStyle(        fontSize: superObjectAdapter(context, {TEAdaptPlatform.phone.toString(): 18.0, TEAdaptPlatform.padPortrait.toString(): 38.0}),        color: Colors.black),        ),       ),      ),     ],    ),   );  }}

属性跨平台适配-手机

属性跨平台适配-平板

扩展需要适配的平台

插件内置的3个平台在实际使用的过程中可能不够用,因此我们提供了用户自定义平台的适配解决方案。

StatelessWidget适配新平台:

对于StatelessWidget只需要实现一个继承自FlexibleStatelessWidget的抽象类,然后实现新平台的build函数,之后注册该平台即可。

abstract class CustomFlexibleStatelessWidget extends FlexibleStatelessWidget {@protected Widget buildNewPlatform(BuildContext context) {  return buildPhone(context); // by default, you can return the phone's style } @protected void initAdapter() {  super.initAdapter(); addAdapter(Constant.newPlatform, buildNewPlatform);// register new Platform }}

StatelessWidget适配新平台示例:

class MyStatelessPage extends CustomFlexibleStatelessWidget { @override Widget buildPhone(BuildContext context) {  return Text('Phone',style: TextStyle(fontSize: 18.0),); } @override Widget buildPadPortrait(BuildContext context) {  return Text('PadPortrait',style: TextStyle(fontSize: 22.0),); } @override Widget buildNewPlatform(BuildContext context) {  return Text('buildNewPlatform',style: TextStyle(fontSize: 30.0),); }}

StatefulWidget适配新平台:

对于StatefulWidget只需要实现一个继承自FlexibleState的抽象类,然后实现新平台的build函数,之后注册该平台即可。

abstract class CustomFlexibleState<T extends StatefulWidget> extends FlexibleState<T> { @protected Widget buildNewPlatform(BuildContext context) {  return buildPhone(context); // by default, you can return the phone's style } @protected void initAdapter() {  super.initAdapter(); addAdapter(Constant.newPlatform, buildNewPlatform);// register new Platform }}

StatefulWidget适配新平台示例:

class MyStatefulPageState extends CustomFlexibleState<MyStatefulPage> { @override Widget buildPhone(BuildContext context) {  return Text('Phone',style: TextStyle(fontSize: 18.0),); } @override Widget buildPadPortrait(BuildContext context) {  return Text('PadPortrait',style: TextStyle(fontSize: 22.0),); } @override Widget buildNewPlatform(BuildContext context) {  return Text('NewPlatform',style: TextStyle(fontSize: 30.0),); }}

用户自定义平台

本项目已经开源,开源地址:

Flutter-adapterhttps://github.com/buaashuai/flutter_adapter

近期文章:

日问题:

多平台都跨了,怎么能缺屏幕适配?

专属升级社区:《这件事情,我终于想明白了》