如何制作启动画面?

619

我希望我的应用程序看起来更加专业,因此我决定添加一个启动画面。

我该如何实现它?


64
为什么应用程序使用启动画面会显得更专业?我不知道有哪个“专业”的安卓应用程序使用了启动画面。 - theomega
9
同意@theomega的观点。启动画面只是很烦人。 - Matt Ball
95
如果你有后台加载的工作需要完成,才应该显示启动画面。否则,尽快让用户得到他们想要的内容可以使你的应用程序看起来更加“专业”。超过100毫秒的延迟会引起用户的注意并感到烦恼,而添加启动画面会使这个阈值提高一个数量级。 - CodeFusionMobile
90
Kindle应用程序、Aldiko阅读器、Dolphin浏览器.... 呃,操作系统 :) 它们都有一个启动画面。Opera Mobile、Mantan Reader、Maps等也有。如果需要加载时间,至少让用户知道你的应用已经开始运行。即使延迟几秒钟,只要屏幕上出现了一些东西,它就能更好地隐藏起来。 - baash05
20
启动画面为您提供了一个绝佳的机会来宣传您的游戏或应用程序公司名称或标志。我喜欢将启动画面设置为可点击,以便用户可以选择跳过到游戏。如果用户每次打开您的应用程序都能看到您公司的标志,即使只有半秒钟,他们更有可能记住您是谁。只要确保他们在使用您的应用程序时有良好的体验即可。 - Chamatake-san
显示剩余10条评论
31个回答

713

请注意,此解决方案不会让用户等待更长时间:启动画面的延迟取决于应用程序的启动时间。

当您打开任何Android应用程序时,默认情况下会出现一个略带黑色背景的屏幕,顶部显示应用程序的标题和图标,您可以通过使用样式/主题来更改它。

首先,在值文件夹中创建一个style.xml并添加一个样式。

<style name="splashScreenTheme" parent="@android:style/Theme.DeviceDefault.Light.NoActionBar">
    <item name="android:windowBackground">@drawable/splash_screen</item>
</style>

使用其他主题作为父主题,而不是使用@android:style/Theme.DeviceDefault.Light.NoActionBar

其次,在您的应用程序Manifest.xml中,将android:theme="@style/splashScreenTheme"添加到您的主活动中。

<activity
        android:name="MainActivity"
        android:label="@string/app_name"
        android:theme="@style/splashScreenTheme" >

第三步,在onCreate()启动活动中更新您的主题。

protected void onCreate(Bundle savedInstanceState) {
    // Make sure this is before calling super.onCreate
    setTheme(R.style.mainAppTheme);
    super.onCreate(savedInstanceState);
}

更新 请查看此帖子

感谢@mat1h和@adelriosantiago


3
“parent”似乎只在API 14及以上版本中受支持。 - user1832478
131
这是正确的闪屏方式。谢谢!带延迟的获得更多赞同的回答只是一种糟糕的做法。不应该让用户等待才能看到第一个功能屏幕。 - dineth
9
我对此的一个问题是<item name="android:background">会覆盖windowBackground。如果没有定义android:background,在任何片段中我的背景都将透明,显示前景内容后面的活动背景。 - William Grand
4
@Abdullah:我按照你说的做了。它运行正常,但在活动切换时启动画面会出现几毫秒。 - nizam.sp
3
@Abdullah 谢谢!那是一种可行的解决方案,不过我找到了这个链接:https://plus.google.com/+AndroidDevelopers/posts/Z1Wwainpjhd。为了避免为每个屏幕尺寸创建不同的图片,也可以创建一个包含图像的 XML 文件,这样它就能在所有屏幕上显示得好看。 - adelriosantiago
显示剩余28条评论

546

进一步阅读:

旧答案:

如何实现: 简单闪屏页

此答案向您展示了如何在应用程序启动时显示一个固定时间的闪屏页,例如出于品牌推广的原因。例如,您可以选择展示3秒钟的闪屏页。但是如果您想要展示一个变量时间长度的闪屏页(例如应用程序启动时间),则应查看阿卜杜拉的答案https://dev59.com/3W035IYBdhLWcg3wVebn#15832037。然而请注意,新设备的应用程序启动可能非常快,因此用户只会看到闪烁的屏幕,这是不好的用户体验。

首先,您需要在layout.xml文件中定义闪屏页。

  <?xml version="1.0" encoding="utf-8"?>
  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:orientation="vertical" android:layout_width="fill_parent"
          android:layout_height="fill_parent">

          <ImageView android:id="@+id/splashscreen" android:layout_width="wrap_content"
                  android:layout_height="fill_parent"
                  android:src="@drawable/splash"
                  android:layout_gravity="center"/>

          <TextView android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:text="Hello World, splash"/>

  </LinearLayout>

而你的活动:

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;

public class Splash extends Activity {

    /** Duration of wait **/
    private final int SPLASH_DISPLAY_LENGTH = 1000;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.splashscreen);

        /* New Handler to start the Menu-Activity 
         * and close this Splash-Screen after some seconds.*/
        new Handler().postDelayed(new Runnable(){
            @Override
            public void run() {
                /* Create an Intent that will start the Menu-Activity. */
                Intent mainIntent = new Intent(Splash.this,Menu.class);
                Splash.this.startActivity(mainIntent);
                Splash.this.finish();
            }
        }, SPLASH_DISPLAY_LENGTH);
    }
}

就是这样了;)


3
@user2606414,请在 Stack Overflow 上提出你的问题,并粘贴完整的错误日志。 - DarkLeafyGreen
41
别忘了在清单文件中添加"闪屏界面"。 - Zar E Ahmer
8
@Peter,问题不在于如何在加载数据时显示启动画面。 - DarkLeafyGreen
29
这并不是一个适合作为启动界面的正确解决方案,它让用户等待才展示启动界面,然而启动界面的目的恰恰相反,应该在用户等待时展示。请参考@Abdullah的解决方案。 - efeyc
4
不要使用 SPLASH_DISPLAY_LENGTH 时间来阻塞应用程序,相反你应该采用以下方法:https://www.bignerdranch.com/blog/splash-screens-the-right-way/ - miguel.martin
显示剩余15条评论

62
  • 创建一个活动:启动页
  • 创建一个布局XML文件:splash.xml
  • 将UI组件放入splash.xml布局中,使其看起来符合你的要求
  • 你的Splash.java文件可能如下所示:

public class Splash extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.splash);

        int secondsDelayed = 1;
        new Handler().postDelayed(new Runnable() {
                public void run() {
                        startActivity(new Intent(Splash.this, ActivityB.class));
                        finish();
                }
        }, secondsDelayed * 1000);
    }
}
  • ActivityB.class更改为您想在闪屏屏幕后启动的任何活动

  • 检查您的清单文件,它应该像这样

  •         <activity
                android:name=".HomeScreen"
                android:label="@string/app_name">     
            </activity>
    
            <activity
                android:name=".Splash"
                android:label="@string/title_activity_splash_screen">     
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
    

    32
    这不是启动画面的目的。它会额外延迟1秒钟。启动画面应该是加载应用程序第一个屏幕时显示的图像。这个链接可能有帮助。 https://dev59.com/h3I-5IYBdhLWcg3wMFMf#7057332 - efeyc
    3
    @efeyc: 你100%正确,然而,应用程序启动时看起来非常漂亮,你认为呢? - McLan
    2
    @Suda.nese 绝对不是。用户不想看图片,用户想要使用应用程序而不会有不必要的延迟。 - Tim
    1
    @TimCastelijns 这取决于正在开发的应用程序以及启动画面的外观..当然,它旨在实用,但谁说不能用于其他用途!! - McLan
    7
    同意 @Suda.nese。如果应用程序要求包括启动画面,则就加上启动画面!当然,这可能不是用户所期望的,但如果客户想要一个启动画面,那就给他们吧! - james
    请查看我的最佳且简单的解决方案: https://medium.com/@vatani.ahmad/android-optimal-splash-screen-without-extra-activity-or-fragment-b60fea45a0cc - Ahmad Vatani

    30

    以上回答非常好,但我想再补充一些内容。我是Android新手,在开发过程中遇到了这些问题。希望这可以帮助像我一样的人。

    1. 启动画面是我的应用程序的入口点,因此请在AndroidManifest.xml中添加以下行。

        <activity
            android:name=".SplashActivity"
            android:theme="@android:style/Theme.DeviceDefault.Light.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    
  • 启动画面应该只在应用程序生命周期中显示一次,我使用一个布尔变量来记录启动画面的状态,并仅在第一次显示它。

  • public class SplashActivity extends Activity {
        private static boolean splashLoaded = false;
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            if (!splashLoaded) {
                setContentView(R.layout.activity_splash);
                int secondsDelayed = 1;
                new Handler().postDelayed(new Runnable() {
                    public void run() {
                        startActivity(new Intent(SplashActivity.this, MainActivity.class));
                        finish();
                    }
                }, secondsDelayed * 500);
    
                splashLoaded = true;
            }
            else {
                Intent goToMainActivity = new Intent(SplashActivity.this, MainActivity.class);
                goToMainActivity.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
                startActivity(goToMainActivity);
                finish();
            }
        }
    }
    

    愉快编码!


    11
    您可以在AndroidManifest.xml中添加android:noHistory="true"来防止用户使用返回按钮回到闪屏界面。 - Rachel

    23

    Abdullah的回答很好,但我想在我的回答中添加更多细节。

    实现闪屏界面

    正确实现闪屏界面与你想象中有些不同。你看到的闪屏界面必须立即准备好,即使在你的闪屏活动中填充布局文件之前也是如此。

    因此,你将不会使用布局文件。相反,将闪屏界面的背景指定为活动的主题背景。为此,请先在res/drawable中创建一个XML可绘制对象。

    background_splash.xml

    <?xml version="1.0" encoding="utf-8"?>
    <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
        <!-- Background Color -->
        <item
            android:drawable="@color/gray"/>
    
        <!-- Logo -->
        <item>
            <bitmap
                android:gravity="center"
                android:src="@mipmap/ic_launcher"/>
        </item>
    
    </layer-list>
    

    这只是一个带有标志和中央背景颜色的图层列表。

    现在打开styles.xml并添加此样式。

    <style name="SplashTheme" parent="Theme.AppCompat.NoActionBar">
            <item name="android:windowBackground">@drawable/background_splash</item>
    </style>
    

    这个主题将没有操作栏,并且具有我们上面创建的背景。

    在清单文件中,您需要将SplashTheme设置为您想要用作启动屏幕的活动。

    <activity
    android:name=".SplashActivity"
    android:theme="@style/SplashTheme">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
    
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    

    然后在您的活动代码中,使用意图将用户导航到闪屏后的特定屏幕。

    public class SplashActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            Intent intent = new Intent(this, MainActivity.class);
            startActivity(intent);
            finish();
        }
    }
    

    这就是正确的做法。我使用了这些参考资料来回答问题:

    1. https://material.google.com/patterns/launch-screens.html
    2. https://www.bignerdranch.com/blog/splash-screens-the-right-way/感谢这些人把我引导到了正确的方向。我想帮助其他人,因为被接受的答案并不是一个推荐的启动画面做法。

    4
    我在 YouTube 上看到了相关的教程。但我认为位图大小会是个问题,因为你不能使用 layer-list 来调整它的大小。 - RoCkDevstack
    您可以使用23+ API的宽度和高度属性调整项目大小,但最好为每个屏幕分辨率上传不同尺寸的图像(例如hdpi、xxhdpi)。 - Zeeshan Shabbir
    “实现启动画面”这一部分非常有用,谢谢! - acmpo6ou
    不再使用<bitmap>标签,这可能会引发ResourceNotFound异常;而是直接在<item>中使用android:drawable代替android:src - Zain
    可以将动画GIF添加到windowBackground中吗?或者在相关的layer-list中呢? - C.F.G
    对于那些感兴趣的人:根据这篇帖子,Android版本大于12的情况下,无法再使用全屏图像了:https://stackoverflow.com/a/74386961/1317559 - undefined

    13
    1. 创建一个名为SplashScreen.javaActivity

    public class SplashScreen extends Activity {
    protected boolean _active = true;
    protected int _splashTime = 3000; // time to display the splash screen in ms
    
    
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.splashscreen);
    
        Thread splashTread = new Thread() {
            @Override
            public void run() {
                try {
                    int waited = 0;
                    while (_active && (waited < _splashTime)) {
                        sleep(100);
                        if (_active) {
                            waited += 100;
                        }
                    }
                } catch (Exception e) {
    
                } finally {
    
                    startActivity(new Intent(SplashScreen.this,
                            MainActivity.class));
                    finish();
                }
            };
                 };
        splashTread.start();
    }
     }
    
  • splashscreen.xml将会是这样的

  • <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
      android:layout_width="600px" android:layout_height="1024px"
      android:background="#FF0000">
    </RelativeLayout> 
    

    13

    默认情况下,闪屏并不能使您的应用程序看起来更加专业。如果您不知道如何编写一个专业设计的闪屏,则其实际上如何专业化的程序是很值得考虑的。

    唯一需要有闪屏的原因(借口)就是因为您正在进行大量计算或者正在等待GPS / WiFi启动,因为您的应用程序在启动之前依赖于它们。如果没有这些计算结果或对GPS / WiFi等的访问权限,您的应用程序就无法使用,因此您认为需要一个闪屏,并且必须阻止其他正在运行的程序(包括后台)的视图。

    这样的闪屏应该看起来像您的全屏应用程序,以给人初始化的印象,然后在完成漫长的计算后,可以填写最后的细节(调整图像)。这种情况发生的可能性非常小,或者说这是程序设计的唯一方式是极其罕见的

    最好的方法是允许用户(和其他操作系统)在等待期间做其他事情,而不是将您的程序设计成依赖于需要一段时间的工作(等待的持续时间不确定)。

    您的手机上已经有显示GPS / WiFi正在启动的图标了。闪屏占用的时间或空间可以用来加载预先计算或实际进行计算。有关您所造成的问题以及必须考虑的问题,请参见下面的第一个链接。

    如果您绝对必须等待这些计算或GPS / WiFi,最好只需让应用程序启动,并弹出一条消息,说明需要等待计算(文字上的“初始化”消息就可以)。 GPS / WiFi的等待是可以预料到的(如果它们没有在另一个程序中启用),因此宣布它们的等待时间是不必要的。

    请记住,当闪屏启动时,您的程序已经在运行,您所做的只是延迟使用您的程序并占用CPU / GPU来执行大多数人认为不必要的操作。

    我们最好每次启动程序时都想要看到你的启动画面,否则我们就感觉它写得不太专业。将启动画面设置为全屏,并复制实际程序屏幕的内容(这样我们认为程序已经初始化了,实际上并没有),可能能实现你的目标(使你的程序看起来更专业),但我不会把赌注压在这个上面。
    为什么不这么做:http://cyrilmottier.com/2012/05/03/splash-screens-are-evil-dont-use-them/ 如何做:https://encrypted.google.com/search?q=Android+splash+screen+source 因此,有很好的理由不这么做,但是如果你确信自己的情况不属于那些例子,那么可以按照上述方法进行。一定要确信它真的能让你的应用程序看起来更专业,否则你就打败了唯一给出的这个做法的原因。
    这就像一个YouTube频道每个视频都以漫长的图形介绍(和结束语)开始,或者觉得需要讲笑话或解释过去一周发生了什么(当它不是喜剧或生活方式频道)。只要播放节目!(只要运行程序)。

    12

    以上所有答案都非常好。但是存在内存泄漏的问题。

    在Android社区中,这个问题通常被称为"Leaking an Activity"。那么这到底是什么意思呢?

    当发生配置更改时(如方向更改),Android会销毁Activity并重新创建它。通常,垃圾回收器只会清除旧Activity实例的分配内存,然后我们就可以了。

    "Leaking an Activity"是指垃圾回收器无法清除旧Activity实例的分配内存,因为它被一个超出Activity实例寿命的对象引用(strong reference)着。每个Android应用程序都有一定数量的内存分配给它。当垃圾回收器无法释放未使用的内存时,应用程序的性能将逐渐降低,并最终崩溃并显示OutOfMemory错误信息。

    如何确定应用程序是否存在内存泄漏?最快的方法是在Android Studio中打开内存选项卡,并在更改方向时注意分配的内存量。如果分配的内存保持增加而不减少,则表示存在内存泄漏。

    1.用户更改方向时出现内存泄漏。 enter image description here

    首先,您需要在布局资源splashscreen.xml文件中定义启动画面。

    启动画面活动的示例代码。

    public class Splash extends Activity {
     // 1. Create a static nested class that extends Runnable to start the main Activity
        private static class StartMainActivityRunnable implements Runnable {
            // 2. Make sure we keep the source Activity as a WeakReference (more on that later)
            private WeakReference mActivity;
    
            private StartMainActivityRunnable(Activity activity) {
             mActivity = new WeakReference(activity);
            }
    
            @Override
            public void run() {
             // 3. Check that the reference is valid and execute the code
                if (mActivity.get() != null) {
                 Activity activity = mActivity.get();
                 Intent mainIntent = new Intent(activity, MainActivity.class);
                 activity.startActivity(mainIntent);
                 activity.finish();
                }
            }
        }
    
        /** Duration of wait **/
        private final int SPLASH_DISPLAY_LENGTH = 1000;
    
        // 4. Declare the Handler as a member variable
        private Handler mHandler = new Handler();
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(icicle);
            setContentView(R.layout.splashscreen);
    
            // 5. Pass a new instance of StartMainActivityRunnable with reference to 'this'.
            mHandler.postDelayed(new StartMainActivityRunnable(this), SPLASH_DISPLAY_LENGTH);
        }
    
        // 6. Override onDestroy()
        @Override
        public void onDestroy() {
         // 7. Remove any delayed Runnable(s) and prevent them from executing.
         mHandler.removeCallbacksAndMessages(null);
    
         // 8. Eagerly clear mHandler allocated memory
         mHandler = null;
        }
    }
    

    更多信息请查阅此链接


    4

    以下是完整的代码

    SplashActivity.java

    public class SplashActivity extends AppCompatActivity {
    
    private final int SPLASH_DISPLAY_DURATION = 1000;
    
    @Override
    public void onCreate(Bundle bundle) {
        super.onCreate(bundle);
    
    
        new Handler().postDelayed(new Runnable(){
            @Override
            public void run() {
    
                Intent mainIntent = new Intent(SplashActivity.this,MainActivity.class);
                SplashActivity.this.startActivity(mainIntent);
                SplashActivity.this.finish();
            }
        }, SPLASH_DISPLAY_DURATION);
    }}
    

    在可绘制对象中创建这个 bg_splash.xml 文件。
    <?xml version="1.0" encoding="utf-8"?><layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    
    <item
        android:drawable="@color/app_color"/>
    
    <item>
        <bitmap
            android:gravity="center"
            android:src="@drawable/ic_in_app_logo_big"/>
    </item></layer-list>
    

    styles.xml 中创建一个自定义主题。
    <style name="SplashTheme" parent="Theme.AppCompat.NoActionBar">
        <item name="android:windowBackground">@drawable/bg_splash</item>
    </style>
    

    最后,在 AndroidManifest.xml 中为您的活动指定主题。

    <activity
            android:name=".activities.SplashActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait"
            android:theme="@style/SplashTheme">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
    
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    

    干杯。


    我该如何添加一个XML文件而不是drawable - viper
    我的意思是,你需要按照上述描述,在drawable目录中创建bg_splash.xml。 - awsleiman

    4

    闪屏界面不应该从布局文件中加载,否则在加载时可能会有一些延迟。

    最好的方法是为您的SplashScreenActivity创建一个Theme,并将android:windowBackground设置为可绘制资源。

    https://www.bignerdranch.com/blog/splash-screens-the-right-way/

    简而言之:

    在清单文件中声明SplashScreenActivity:

    <activity
            android:name=".activities.SplashScreenActivity"
            android:theme="@style/SplashTheme"
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    

    在SplashScreenActivity.java文件中:

    @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        Intent intent = new Intent(this, MainActivity_.class);
        startActivity(intent);
        finish();
    
    }
    

    接下来创建您主题的背景窗口资源:

    <style name="SplashTheme" parent="Theme.Bumpfie.Base">
        <item name="android:windowBackground">@drawable/splash</item>
    </style>
    

    可绘制文件 splash.xml:

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

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接