沃梦达 / IT编程 / 移动开发 / 正文

Android 超详细SplashScreen入门教程

Android12正式版即将发布,有一个非常显著的视觉变化就是,Android12强制给所有的App都增加了SplashScreen的功能。是的,即使你什么都不做,只要你的App安装到了Android12手机上,都会自动拥有这个新功能

这次的Android系统变化当中,UI的变化无疑是巨大的。Google在Android 12中采取了一种叫作Material You的界面设计,一切以你为中心,以你的喜好为风格。相信大家一旦上手Android 12之后应该能立刻察觉到这些视觉方面的变化。

关于这个SplashScreen,今天就值得好好讲一讲了。

什么是SplashScreen

SplashScreen其实通俗点讲就是指的闪屏界面。这个我们国内开发者一定不会陌生,因为绝大多数的国内App都会有闪屏界面这个功能,很多的App还会利用闪屏界面去打广告。下图是QQ的闪屏界面:


class MainActivity : AppCompatActivity() {
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        Thread.sleep(3000)
    }

}

或者也可以这样写:


class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }

    override fun onResume() {
        super.onResume()
        Thread.sleep(3000)
    }

}

可以看到,我们分别在onCreate()和onResume()方法中让主线程沉睡了3秒钟。然后运行一下程序:


class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val contentView: View = findViewById(android.R.id.content)
        contentView.post {
            Thread.sleep(3000)
        }
    }

}

这里可以借助任何一个View的实例调用一下它的post函数,并在post的回调当中让主线程沉睡3秒。然后再次运行程序:


class MainActivity : AppCompatActivity() {
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val contentView: View = findViewById(android.R.id.content)
        contentView.viewTreeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
            override fun onPreDraw(): Boolean {
                return false
            }
        })
    }

}

这里我们在回调函数onPreDraw()中返回了一个false,也就意味着,我们的PreDraw阶段始终没有准备好。既然PreDraw都还没准备好,App肯定是不会开始绘制第一帧的,那么SplashScreen自然也就不会消失了。

于是上述代码将会实现一个永久显示SplashScreen的效果。

有了这个原理,那么我们就可以根据自己的需求编写一些逻辑了。比如刚才提到的从磁盘读取数据的场景,我们可以一开始在onPreDraw()中函数中返回false,然后开启子线程去读取数据,等到数据读取完成再将返回值改成true即可。示例代码如下:


class MainActivity : AppCompatActivity() {

    @Volatile
    private var isReady = false
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val contentView: View = findViewById(android.R.id.content)
        contentView.viewTreeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
            override fun onPreDraw(): Boolean {
                if (isReady) {
                    contentView.viewTreeObserver.removeOnPreDrawListener(this)
                }
                return isReady
            }
        })
        thread { 
            // Read data from disk
            ...
            isReady = true
        }
    }

}

注意,在SplashScreen的显示过程中,onPreDraw()函数是以很高的频率在持续刷新的。所以它依然会将主线程阻塞住,导致应用程序无法响应用户的输入事件,直到我们在onPreDraw()函数返回true才会停止刷新。

自定义SplashScreen样式

接下来终于到了可能许多朋友最为关心的部分,自定义SplashScreen的样式。

虽然默认的SplashScreen界面并不难看,对于大多数的App来说可能也已经完全足够了,但是Google仍然给了我们比较高的控制权来自定义SplashScreen的样式。

这里我就将几个比较重要的自定义样式属性来跟大家介绍一下。

刚才有提到过,SplashScreen默认会使用windowBackground属性指定的颜色作为界面的背景颜色。但如果我想要单独给SplashScreen界面指定一个背景色呢?可以在主题文件中定义如下属性:


<item name="android:windowSplashScreenBackground">#CCCCCC</item>

这里我们单独将SplashScreen的背景指定成了浅灰色,效果如下图所示:


<item name="android:windowSplashScreenAnimatedIcon">@drawable/splash_screen_icon</item>

这里我们给SplashScreen界面指定了一个单独的图标,注意这个图标可以是一张静态的图片,也可以是一个动画资源。由于制作动画比较复杂,不在本文的讨论范围内,所以我们只以静态图片来举例。

我准备了这样一张图,并将它命名为splash_screen_icon.jpg。


<item name="android:windowSplashScreenIconBackgroundColor">#BB86FC</item>

这样,只要前景图标是有透明度的图片,背景颜色就可以显示出来了,如下图所示:


<item name="android:windowSplashScreenBrandingImage">@drawable/brand_logo</item>

这里可以传入一张品牌图片,我没能在官网找到Google对这张图片尺寸比例的定义,但如果你随便传入一张图片的话,可能会出现拉伸的情况。

为此,我通过自己做实验,大概总结出了这里应该使用一张2.4:1的图片,最终的效果如下图所示:

}

第二步,修改主题文件,如下所示:


<style name="MySplashTheme" parent="Theme.SplashScreen">
    <item name="windowSplashScreenBackground">#CCCCCC</item>
    <item name="windowSplashScreenAnimatedIcon">@drawable/splash_screen_icon</item>
    <item name="postSplashScreenTheme">@style/Theme.SplashTest</item>
</style>

注意这里的变动至关重要。我们新定义了一个主题,这个主题的名字叫什么都可以,但它一定要继承自Theme.SplashScreen。

然后我们可以使用windowSplashScreenBackground和windowSplashScreenAnimatedIcon这两个属性来分别指定SplashScreen的背景色和中央图标。

不过我比较疑惑的是,我们不能像刚才那样在SplashScreen界面指定图标的背景色和品牌图片,因为这里并没有那两个属性。不知道是不是因为现在库还属性比较早期的阶段,以后或许会加上这些属性。

另外,我们还必须要指定postSplashScreenTheme这个属性,将它的值指定成你的App原来的主题。这样,当SplashScreen结束时,你的主题就能够被复原,从而不会影响到你的App的主题外观。

第三步,修改AndroidManifest.xml文件,应用我们刚刚新定义的主题:


<manifest>
   <application android:theme="@style/MySplashTheme">
    <!-- or -->
        <activity android:theme="@style/MySplashTheme">
	...

这里视你之前代码的写法来决定是替换application标题里的theme,还是activity标题里的theme。

第四步,在你的启动Activity中加入如下代码:


class MainActivity : AppCompatActivity() {
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        installSplashScreen()
        setContentView(R.layout.activity_main)
        ...
    }

}

如果你还在使用Java语言的话,那么需要改成如下写法:


public class MainActivity extends AppCompatActivity {

    @Override
	protected void onCreate(Bundle savedInstanceState) {
	    super.onCreate(savedInstanceState);
	    SplashScreen.installSplashScreen(this);
	    setContentView(R.layout.activity_main);
	    ...
	}
    
}

注意,installSplashScreen()这句代码一定要加入到setContentView()的前面。

这样,当我们刚刚进入App的时候,就会先显示一个SplashScreen界面,然后当App初始化完成之后,SplashScreen会自动消失,并且主题也会变成原来App的主题样式。

接下来我们只需要把过去自己实现的SplashScreen移除即可,不然的话仍然还是会产生双重SplashScreen的现象。

以上步骤是官方提供的适配旧版SplashScreen的解决方案,但是我按照上述步骤进行了一下实现,最终的测试效果却非常差。

主要问题集中在于旧版Android系统上中央图标不会被mask,而在Android 12上中央图标却会被mask,从而导致新旧系统的SplashScreen界面差别很大,也很难看。

不过毕竟我们现在使用的SplashScreen库还处于alpha阶段,后面发生变动的可能性很大,或许这些问题在正式版出现之后都会被修复。

另外,即使官方的库有问题,我们还是完全有办法去规避它。比如说在代码中进行逻辑判断,如果是Android 12系统就不显示自己的SplashScreen界面,因为系统有默认的SplashScreen。而在Android 12以下的系统,就显示自己的SplashScreen界面。

方法总比困难多,不是吗?

那么本篇文章的内容就到这里,让我们一起静静等待Android 12的到来吧。

到此这篇关于Android 超详细SplashScreen入门教程的文章就介绍到这了,更多相关Android SplashScreen内容请搜索编程学习网以前的文章希望大家以后多多支持编程学习网!

本文标题为:Android 超详细SplashScreen入门教程