Flutter 启动页适配

参考文章

Flutter 开发 Android & IOS 启动页 splash pag
Flutter 启动页(闪屏页)具体实现和原理分析
Flutter启动流程和原理分析

需要知道的

  1. iOS13 开始 苹果要放弃LaunchImage适配启动图 , 改为必须走LaunchScreen.sb来启动
    所以在iOS端,启动图适配,要么使用LaunchScreen.sb 内嵌UIImageView +AutoLayout 来适配(依旧使用整图), 要么就采用 页面布局的方式, 来开发启动页,具体可以参考下面这个链接
    iOS 13使用LaunchScreen.storyboard适配各尺寸启动图

  2. Flutter 的启动顺序,或者说是启动过程
    iOS和Android端的原理其实是一样的, Android的MainActivity继承了FlutterActivity,FlutterActivity又通过FlutterActivityDelegate实现了生命周期的代理, 就是创建一个View并通过MainActivity的onCreate方法去加载显示出来,
    同样的, iOS端也在AppDelegate中处理, AppDelegate: FlutterAppDelegate

所以总结来说, Flutter 的启动顺序依然和RN 一样, 先是各自从原生的Launch启动, 这一部分是iOS/Android原生处理,属于冷启动过程(机器不行就会等待较长时间), 还没有涉及到Flutter部分, 如果不做处理,将会有白屏或者黑屏短暂出现,
直到到Flutter层页面被加载出来, 此时启动就算结束了

  1. Flutter 接管后, 是否需要一个Flutter层面的启动页?
    一般来说,Flutter确实需要这么一个Flutter层面的启动页,
    从刚才的原生层启动后, 按道理就是进入Flutter页面了,内容也都呈现了 为什么说通常意义还需要一个Flutter层面的启动页呢?
    这是因为,一般我们需要在Flutter层面做一些同步耗时的操作, 比如两步认证/token验证/App状态检测等等, 有一个启动页帮助我们缓冲一下,相对比较合适…

举个例子(不算恰当), App登录已超时,如果App启动后直接进入首页, 然后由于某些原因必须退出到登录页, 这样的交互显的不那么完美, 最好的是在启动前,就能从接口处得知登录状态, 若登录失效,就直接进入登录页面,未失效就直接进入首页进行业务处理,
所以,请求的过程放到Flutter的启动页, 会显得比较合适

  1. 由于iOS的冷启动采用页面布局的方式实现(放弃LaunchImage的图片适配方式), 建议Flutter层面的启动页面, 也通过页面布局方式(偷懒就丢一整张图)
    这样适配起来可控, 能做到肉眼不可查, 放图片的话,又是要进行图片的适配,反而麻烦

开始吧

1.首先因为启动图比较简单, 我这边就找UI给了2x/3x 的两个图, 分别在iOS原生层和Flutter层添加这两张图片作
Flutter 启动页适配_第1张图片

iOS原生启动

图片

(截图有点早, 其实这边包括后面Flutter , 都是讲图片居于底部居中的布局方式,此处就不另行截图了)
Flutter 启动页适配_第2张图片
Flutter 启动页适配_第3张图片

iOS端冷启动页面比较简单,就在LaunchScreen.sb中放一个UIImageView, 做好约束就可以了,我这边因为启动页比较简单, 就让UI切一张图即可,背景色到时候改成白色基本就看不出来了,
图片的填充模式记得选择 Aspect Fill 填充

Flutter 启动页适配_第4张图片


Android 原生启动

一个插曲…
刚开始使用AS创建Flutter项目的时候, 它默认创建的android/iOS ,分别是Kotlin和swift 模式, 鉴于对kotlin的不熟悉, 需要换成java的版本, 所以可以删除掉项目文件夹下的 android 文件,然后再终端重新创建一下
查看一下Flutter 的命令行工具
ruby flutter create -h
在这里插入图片描述
可以看到, 创建的默认就是 swift/ kotlin , 需要切换的就可以切换一下

修改Android ruby create -a java .
修改iOS ruby create -i objc

切换过后,
创建好的文件就便是纯java的了, 当然一些文件和配置, 就需要重新设置了…

Flutter 启动页适配_第5张图片

安卓部分

Flutter 启动页适配_第6张图片
如上图部分, FLutter 会在 AndroidManifest.xml中指定好Launch启动页入口

            
            <meta-data
              android:name="io.flutter.embedding.android.SplashScreenDrawable"
              android:resource="@drawable/launch_background"
              />

所以我们可以在launch_background.xml中进行编辑…
对了, 建议在编辑的时候用AS再单独打开android的工程, 不然直接用Flutter下的, 有点辅助显示和跳转都不支持…
一开始我还以为是哪里出了问题


<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@color/colorPrimaryDark" >
    item>

    
    

    <item
        android:gravity="bottom"
        android:bottom="0pt"
        android:left="0pt"
        android:right="0pt">
        <bitmap
            android:src="@drawable/launch_icon" />
    item>
layer-list>

这里我对于xxxhdppi没有放图… 其实后期可以补上…, 但是相应的, 我们也要在Flutter下的4x文件夹放置对应图片

最后的效果是:

Flutter 启动页适配_第7张图片

Flutter 启动页适配_第8张图片

发现, 两个启动图还是不一致…

问题出在哪里… 我稍后排查下, 对于android, 还需要更多的学习…

Flutter阶段启动图

直接上代码吧, LaunchScreen.dart 中的build部分

  @override
  Widget build(BuildContext context) {
     
    // TODO: implement build
    return Container(
        width: DeviceUtils.screenW,
        height: DeviceUtils.screenH,
        color: Color(0xffffffff),
        child: Stack(
          alignment: AlignmentDirectional.bottomCenter,
          children: [
            Positioned(
              child: Image.asset(
                ImagesPath.launch_icon,
                width: 750.px,
                height: 220.px,
                fit: BoxFit.fill,
              ),
              bottom: 60.px,
            )
          ],
        ));
  }

Flutter 启动页适配_第9张图片

一些遇到的问题

1. iOS / Flutter 加载的图片, 高度稍微有差异???

怀疑1
iOS原生和Flutter加载的图片不一样?
为了方便分析 , 干脆图片添加了不同文字来区分,
发现在iPhone 8 plus 上, iOS原生的LaunchScreen添加的是3x图片, Flutter的启动页面添加的是2x图片

原因是,

在Flutter 里面, 如下图, 我忘记去掉图片上面的@2x @3x, 导致Flutter只识别@2x图片, (果然Flutter是谷歌儿子, 玩法都是和安卓一样…), 我丢图的时候忘记修改名字了
Flutter 启动页适配_第10张图片
同时, 我测试发现, 在src/img 下, 其实不必再放1x图片, 现在目前市面上主流手机都是2x图片起步, 所以我这样改造

Flutter 启动页适配_第11张图片
pubspec.yaml中这样

  # 感觉目前手机(比如iOS, 1x的图片几乎没必要再使用了,因此此处img目录下直接存放2x图片,3x,4x图片通配)
  assets:
    - src/img/
    - src/img/3x/
    - src/img/4x/

iOS层和Flutter层中加载的均是3x图了
Flutter 启动页适配_第12张图片
Flutter 启动页适配_第13张图片
但是… 问题没有解决

怀疑2
高度单位换算问题
目前,单位换算基于iPhone6 的宽度 375 pt , 而高度的换算部分也基于375.
怀疑是高度换算不准确, 于是, 修改高度换算代码, 用667 pt 来进行换算, 具体实现网上都有, 这边给出log
原图的pt 是375 * 110 pt

    debugPrint(DeviceUtils.screenW.toString());
    debugPrint(DeviceUtils.screenH.toString());

    debugPrint(750.px.toString());
    debugPrint(220.px.toString());
    debugPrint(220.pxH.toString());
log

iPhone8 
flutter: 414.0
flutter: 736.0
flutter: 414.00000000000006
flutter: 121.44000000000001 220.px
flutter: 121.37931034482759 220.pxH

iPhoneXR
flutter: 414.0
flutter: 896.0
flutter: 414.00000000000006
flutter: 121.44000000000001
flutter: 147.76611694152925

可以看到, 基于375 基于667 换算下来的高度几乎是一样的
(其实在 iPhone XR 上差异就大了)
问题依旧没有解决, 两个启动页面的图片高度还是有高度差异…
(测试发现 . 在iPhoneSE2, iPhoneX 是表现OK的)

然后我突然反应过来…
然后我突然反应过来…
然后我突然反应过来…
此处的图片高度, 根本就不能进行单位换算,
应该直接这样写
(目前这里因为只做了iOS侧, 所以先写110 , 代表110 pt)

           Positioned(
              child: Image.asset(
                ImagesPath.launch_icon,
                width: 750.px,
                height: 110,
//                height: 220.px,
                fit: BoxFit.fill,
              ),
              bottom: 0.pxH,

这个110 和iPhone8 下的121.440000 仅相差10, 也符合我看到的,两个launch页面图片有细微的高度差的描述…

至于为什么不能进行单位换算?

因为在iOS 的LaunchScreen中, 我添加了这张375*110的图片,图片的高度是固定的, 就是110pt, 或者说220px ,
此时我无论是基于375 还是基于667 的基础进行单位换算, 其数值在8 / XR等机型上的高度被计算修改过了( 121.440000 等),
反而 在 iPhone se2 这样的机器上, 换算出来的高度正好就是110
那什么地方需要用到换算?
其他正常布局使用单位换算都可以, 但是遇到这种特殊的情况, 或者一些在各个机型上需要同样高度的, 就不推荐进行单位换算…

Flutter 层的启动页, 图片被挤压了

Flutter 启动页适配_第14张图片
明显看到图片挤压了,有点变形, 是因为设置图片的填充模式

       fit: BoxFit.cover,

就可以了

你可能感兴趣的:(Flutter,iOS,react-native,Flutter启动页,LaunchScreen,LaunchImage,启动页适配,适配)