React-native android 启动屏

2020-03-14  本文已影响0人  马六甲的笔记

前言

android 启动时会使用一个 白色 或 黑色 的启动背景,在 app 界面成功加载后,启动背景被 app 界面覆盖。

若 app 启动时,没有什么耗时的异步操作,可以秒载入界面,那么就没必要继续往下看了,因为没必要再弄一个启动屏耽误事,但如果启动后需要初始化一些信息才能显示界面,期望在异步载入时显示一个自定义欢迎屏,请继续

方案一

做一个静态 activey 欢迎页,启动后立即显示这个,待实际界面准备好之后,替换这个 activey 为实际界面,比如 react-native-splash-screen 就是采用的这种方案。

但这带来一个问题,就是这个欢迎页本身的绘制也需要时间,虽然非常快,但启动时第一眼看到的仍然会是一闪而过的启动背景,即白屏。消除这个白屏可以在 android/app/src/main/res/values/styles.xml 进行样式设置(下面是 RN 的 theme)

<resources>
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
         .....
         <!--启动背景改为透明-->
         <item name="android:windowIsTranslucent">true</item>
    </style>
</resources>

经过上面的修改,没有启动白屏了,但会发现,点击 app 图标后,会有一下停顿感,然后显示欢迎屏。其实很好理解,这个停顿感其实就是正在显示透明的启动背景,等同于把白屏体验改为停顿感了。

方案二

既然 app 启动瞬间显示的是启动背景,那么直接美化启动背景,当做欢迎屏不就可以了嘛。

同样是修改 android/app/src/main/res/values/styles.xml,改为下面这样

<resources>
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        ...
        <!--设置启动背景为一个资源文件-->
        <item name="android:windowBackground">@drawable/splash</item>
    </style>
</resources>

创建启动背景资源文件 @drawable/splash,保存路径为 android/app/src/main/res/drawable/splash.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item><color android:color="#ffffff"/></item>
    <item>
        <bitmap android:src="@drawable/splash_img"
            android:antialias="true"
            android:filter="true"
            android:gravity="center" />
    </item>
</layer-list>

启动背景资源文件解释:

  1. 第一个 item 设置背景,因为 android 有众多分辨率,不可能启动背景图刚好覆盖满,所以图片的边缘最好是纯色,通过设置背景颜色自动衔接即可。

  2. @drawable/splash_img 指定启动背景图,参考 android不同分辨率适配drawable 文件可以创建一个,也可以创建多个,当屏幕分辨率对上号了,优先使用最匹配的 drawable,若匹配不上,则选用最接近的一个,并按照比例进行缩放;

    一般情况下,只需针对最大像素密度(当前为 drawable-xxhdpi)制作一张图片即可,当用户分辨率小时,会使用该图片并自动按照像素密度缩小,可能导致图片锐化。可以测试一下,如果锐化导致图片过于失真,可考虑多制作几张,如 drawable/splash_img.pngdrawable-hdpi/splash_img.png 等等;

  3. Bitmap配置,可根据文档自行调整图片位置;若碰到较为复杂的启动屏,单纯一张图不好搞时,可看看九宫格类型图片(NinePatchXml.9图片) 是否可实现需求。

React-Native JS 端

以上是 android 启动背景配置,不是针对 RN 的,只要是 android 项目都适合;

最后说一下 RN 的 JS 部分,一般情况下,我们会在 app 启动时,初始化一些东西,期望在初始化完成前,持续显示启动屏,那么只需要在入口 app.js 完成初始化之后再渲染界面即可,代码示例:

export default class extends React.Component {
  state = {
    ready: false
  }

  componentDidMount() {
      // 执行完异步任务后, 开始绘制
      doAsyncWork().then(() => {
         this.setState({
            ready:true
         });
      })
  }

  render(){
    if (!this.state.ready) {
      return null;
    }
    return <View/>;
  }
}

番外:启动配置

以下是实测结果:

<resources>
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">

          <!--
              通用: 全屏显示,状态栏不显示,启动背景显示到最顶端。
             但对于有刘海屏的机器,状态栏会变成一个大黑边,无字
             对于有虚拟导航栏的手机,虚拟导航栏以浮动的状态位于底部,
             即启动背景最下方会被导航栏覆盖
          -->
          <item name="android:windowFullscreen">true</item>

           <!--
              API 28:  在  windowFullscreen 开启后,通过该设置可去除刘海屏手机顶部的大黑边
             启动背景将显示到手机的最顶端。
           -->
          <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
          
           <!--
              API 21:  在  windowFullscreen 开启后,通过该属性设置为 false
             启动背景最低端 为 导航栏上沿,即导航栏不会覆盖启动背景了
             低版本无法使用,不过低版本 android 那会,好像还没有虚拟导航栏
           -->
          <item name="android:windowDrawsSystemBarBackgrounds">false</item>




          <!--
              API 19:  状态栏/虚拟导航栏 半透明,开启后,将以半透明背景的状态浮动在顶/底部
              1. 不能与 windowFullscreen=true 同时使用,因为状态直接不显示了,该设置无意义
              2. 对于有刘海屏的,状态栏与刘海齐平,启动背景显示在状态栏(包括刘海)下方
              3. 不支持 windowDrawsSystemBarBackgrounds 设置,启动背景总是铺满全屏
           -->
         <item name="android:windowTranslucentStatus">true</item>
         <item name="android:windowTranslucentNavigation">true</item>

   
          <!--
              API 21:  状态栏/虚拟导航栏 完全透明
              1. 同样的,不能与 windowFullscreen=true 同时使用,理由同上
              2. 也不能与 windowTranslucentStatus / windowTranslucentNavigation 同时使用
                   优先级低于上述属性,同时使用,这里将不生效
              3. 对于有刘海屏的,刘海区域也属于启动背景的可用区域,即启动背景铺满全屏
           -->
         <item name="android:statusBarColor">@android:color/transparent</item>
         <item name="android:navigationBarColor">@android:color/transparent</item>


           <!--
              API 23 / 27:  状态栏/虚拟导航栏 是否启用浅色模式(指背景浅色),文字为深色
              1. windowLightStatusBar 要求 API 23,windowLightNavigationBar 要求 API 27
              2. 使用半透明 状态栏/导航栏 ,该设置没什么必要性
              3. 使用完全透明的 状态栏/导航栏, 可根据启动背景色调进行设置
           -->
          <item name="android:windowLightStatusBar">true</item>
          <item name="android:windowLightNavigationBar">true</item>

    </style>
</resources>

推荐配置

  1. /values/styles.xml 中仅设置启动背景就好了,兼容特低版本
  2. /values-v19/styles.xml:Android4.4 以上,支持状态栏半透明
<resources>
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        ...
        <item name="android:windowBackground">@drawable/splash</item>
        <item name="android:windowTranslucentStatus">true</item>
    </style>
</resources>
  1. 让状态栏完全透明,根据启动背景色调。
    如果是深色, /values-v21/styles.xml: Android5.0 以上,状态栏背景完全透明,文字为浅色
<resources>
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        ...
        <item name="android:windowBackground">@drawable/splash</item>
        <item name="android:statusBarColor">@android:color/transparent</item>
    </style>
</resources>

如果是浅色,/values-v23/styles.xml: Android6.0 以上,状态栏背景完全透明,文字为深色

<resources>
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        ...
        <item name="android:windowBackground">@drawable/splash</item>
        <item name="android:statusBarColor">@android:color/transparent</item>
        <item name="android:windowLightStatusBar">true</item>
    </style>
</resources>

虚拟导航栏没什么必要去处理,一是因为那里并不影响美观,二是因为全面屏手机越来越多。

上一篇 下一篇

猜你喜欢

热点阅读