返回

Android纯文本渐变启动页:自定义Splash Screen

Android

Android 原生启动页:打造纯文本渐变效果

开发 App 时,启动页(Splash Screen)是给用户的第一印象。很多时候,我们会看到带应用图标的启动页。但是,如果你想玩点不一样的,比如纯文本、带动画效果的启动页呢?这篇文章就来帮你搞定它!别担心,虽然原帖的问题关闭了,但是问题可以分析解决.

一、问题拆解:不走寻常路

一般启动页都是显示个图标或者图片。 这次的需求比较特别:

  1. 不要图标,只要文字。
  2. 文字最好能逐个显示(类似打字机效果)。
  3. 文字颜色还要是渐变的。
  4. 用原生 Android 代码实现 (因为提问者用的 Flutter,想用原生方式定制启动页)。

二、原因分析:为什么不能直接用?

Android 12 (API 级别 31) 之后,系统引入了全新的 SplashScreen API。 这套 API 简化了启动页的实现,但同时也带来了一些限制:

  • 默认行为:新 API 倾向于使用应用图标,直接设置纯文本可能不那么直观。
  • 自定义限制:虽然可以自定义,但要实现逐字显示、渐变等效果,需要更多底层操作。

直接用现成的方案,可能满足不了这么个性化的需求。所以,我们得自己动手,丰衣足食。

三、解决方案:步步为营,逐个击破

1. 基础启动页:先让它显示出来

不管怎样,先搞个能显示的启动页。

原理:

  • 利用 SplashScreen API(兼容旧版本)。
  • 创建一个专门的 Theme 给启动页用。
  • AndroidManifest.xml 中指定这个 Theme。

步骤:

  1. 创建 Theme:res/values/styles.xml (或 themes.xml) 中添加:

    <style name="AppTheme.Starting" parent="Theme.SplashScreen">
        <item name="windowSplashScreenBackground">@color/white</item>  </style>
    

    如果你的项目已经针对夜间模式配置了深色背景,那新建一个文件res/values-night/styles.xml,并将其中windowSplashScreenBackground设置为深色背景色.

  2. AndroidManifest.xml: 找到你的启动 Activity(通常是 MainActivity),修改它的 android:theme

    <activity
        android:name=".MainActivity"
        android:theme="@style/AppTheme.Starting">
    
    </activity>
    
  3. MainActivity.kt (或 .java):onCreate 方法的最前面,调用 installSplashScreen()

    import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
    
    class MainActivity : AppCompatActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            installSplashScreen()
            super.onCreate(savedInstanceState)
            // ... 其他代码 ...
        }
    }
    

    或者,如果你是Java:

    import androidx.core.splashscreen.SplashScreen;
    
    public class MainActivity extends AppCompatActivity {
       @Override
        protected void onCreate(Bundle savedInstanceState) {
              SplashScreen.installSplashScreen(this);
              super.onCreate(savedInstanceState);
               // ... 其他代码 ...
    
       }
    }
    

    这样设置主题会使Android 12 及以上版本的启动页使用纯白色填充.
    在之前的版本上,我们接下来设置.

    这一步确保了在 App 内容加载前,能看到一个基本的启动页(现在是纯色背景)。

2. 去掉图标,换成文本

接下来,干掉图标,换上我们想要的文本。

原理:

  • 自定义 windowSplashScreenAnimatedIcon:虽然名字里有 "Icon",但我们可以用 TextView 把它替换掉。
  • 自定义postSplashScreenTheme,应用原本的主题.

步骤:
继续编辑res/values/styles.xml:

```xml
<style name="AppTheme.Starting" parent="Theme.SplashScreen">
    <item name="windowSplashScreenBackground">@color/white</item>
    <item name="windowSplashScreenAnimatedIcon">@drawable/splash_screen_text</item>
    <item name="postSplashScreenTheme">@style/Theme.YourOriginalTheme</item>
  
</style>

 ```

注意替换Theme.YourOriginalTheme为你应用原本的主题。

创建文本 Drawable:

  1. 新建 res/drawable/splash_screen_text.xml

    <?xml version="1.0" encoding="utf-8"?>
    <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
        <item>
            <shape android:shape="rectangle">
                <solid android:color="@android:color/transparent" />
            </shape>
        </item>
        <item android:gravity="center">
            <TextView
                xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Mathoria"
                android:textSize="48sp"
                android:textStyle="bold"
                android:textColor="@android:color/black"/>
    
        </item>
    </layer-list>
    

    这里,我们用一个透明背景的 layer-list 包裹 TextView,实现居中显示文本。

旧版本兼容:

如果你需要兼容比 Android 12 更老的设备,需要额外进行设置

新建 res/layout/activity_splash.xml

 <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  tools:context=".SplashActivity"
  android:background="@android:color/white">

  <TextView
      android:id="@+id/tv_splash"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="Mathoria"
      android:textSize="48sp"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="parent" />

 </androidx.constraintlayout.widget.ConstraintLayout>

新建 SplashActivity.kt:

 class SplashActivity : AppCompatActivity() {
   override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
       startActivity(Intent(this@SplashActivity,MainActivity::class.java))
       finish()
   }
 }

修改 AndroidManifest.xml,启动 Activity 改为SplashActivity:

<activity
  android:name=".SplashActivity"
    android:theme="@style/AppTheme.Starting">
   <intent-filter>
      <action android:name="android.intent.action.MAIN" />

       <category android:name="android.intent.category.LAUNCHER" />
   </intent-filter>
</activity>
<activity
   android:name=".MainActivity"
    android:exported="true">

</activity>

现在旧版本也可看到文本启动页

3. 渐变色:给文字上色

静态文本有点单调,来给它加个渐变色。

原理:

  • 使用 Shader(着色器)来实现渐变效果。
  • TextViewpaint 上应用 Shader

步骤:

  1. 修改之前的 res/drawable/splash_screen_text.xml: 去掉android:textColor属性, 因为我们要在代码里实现.

    
    <TextView
       xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="Mathoria"
       android:textSize="48sp"
        android:textStyle="bold"
        />
    

代码实现渐变:

需要的话,为旧版本修改res/layout/activity_splash.xml,做相同处理。

我们需要重写一个 TextView:

  1. 新建 GradientTextView.kt

    import android.content.Context
    import android.graphics.LinearGradient
    import android.graphics.Shader
    import android.util.AttributeSet
    import androidx.appcompat.widget.AppCompatTextView
    
    class GradientTextView @JvmOverloads constructor(
        context: Context,
        attrs: AttributeSet? = null,
        defStyleAttr: Int = 0
    ) : AppCompatTextView(context, attrs, defStyleAttr) {
    
        override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
            super.onLayout(changed, left, top, right, bottom)
    
            if (changed) {
                paint.shader = LinearGradient(
                    0f,
                    0f,
                    width.toFloat(),
                    height.toFloat(),
                    intArrayOf(
                        context.getColor(R.color.pink), // 你的粉色
                        context.getColor(R.color.blue)   // 你的蓝色
                    ),
                    null,
                    Shader.TileMode.CLAMP
                )
            }
        }
    }
    
    

    别忘了在res/values/colors.xml里添加你需要的颜色定义:

     <color name="pink">#FFC0CB</color>
     <color name="blue">#0000FF</color>
    
  2. 替换 TextView: 把上面所有的TextView, 替换为 GradientTextView

    • res/drawable/splash_screen_text.xml:
      <com.yourpackage.GradientTextView  </com.yourpackage.GradientTextView>
      
    • 如果你创建了activity_splash.xml
      <com.yourpackage.GradientTextView
       </com.yourpackage.GradientTextView>
    
    

    (记得把 com.yourpackage 换成你自己的包名)。

这样,文本就有了从粉色到蓝色的渐变效果。

4. 逐字显示:让文字动起来

最后,来实现逐字显示的动画效果。

原理:

  • 使用 HandlerRunnable 来定时更新 TextView 的内容。
  • 每次更新只显示文本的一部分,模拟打字机效果。

步骤:
对于 Android 12+, 因为我们修改了windowSplashScreenAnimatedIcon属性,SplashScreen API 不再处理动画, 我们可以在 MainActivity中实现:

  1. 修改 MainActivity.kt:

     override fun onCreate(savedInstanceState: Bundle?) {
    
         val splashScreen = installSplashScreen()
         super.onCreate(savedInstanceState)
         setContentView(R.layout.activity_main) //设置布局文件,其中包含一个GradientTextView.
         val textView = findViewById<GradientTextView>(R.id.tv_splash)
          splashScreen.setKeepOnScreenCondition{true}//保持启动页显示.
    
          val text = "Mathoria"
        var index = 0
        val handler = Handler(Looper.getMainLooper())
         val runnable = object : Runnable {
            override fun run() {
                 if (index <= text.length) {
                     textView.text = text.substring(0, index)
                     index++
                    handler.postDelayed(this, 100) // 每 100 毫秒更新一次
               }
                else{
                      splashScreen.setKeepOnScreenCondition{false}// 隐藏启动画面.
                }
            }
          }
           handler.post(runnable)
        // ... 其他代码 ...
    
    }
    

注意设置setContentView(R.layout.activity_main),和 GradientTextView 的 id。
对于旧版安卓,我们修改SplashActivity

  1. 修改 SplashActivity.kt
     class SplashActivity : AppCompatActivity() {
       override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
     setContentView(R.layout.activity_splash)
         val textView = findViewById<GradientTextView>(R.id.tv_splash)
           val text = "Mathoria"
      var index = 0
      val handler = Handler(Looper.getMainLooper())

       val runnable = object : Runnable {
          override fun run() {
             if (index <= text.length) {
               textView.text = text.substring(0, index)
                index++
             handler.postDelayed(this, 100) // 每 100 毫秒更新一次
              }else
          {
           startActivity(Intent(this@SplashActivity,MainActivity::class.java))
               finish()
           }
         }
    }
      handler.post(runnable)

  }
 }

现在,启动 App 时,就能看到文本逐字显示,并带有渐变效果的启动页了。

四、一点补充

如果你不想要动画效果,只是想要静态显示文本。你可以省掉很多自定义的东西:

  1. 直接创建 res/drawable/splash_screen_text.xml: 使用<TextView>,通过 android:textColor来处理颜色。
  2. 新版本, 通过 Theme 的windowSplashScreenAnimatedIcon引用这个 Drawable,并正确设置 postSplashScreenTheme
  3. 旧版本, 使用上文中旧版本的方案, 通过一个 SplashActivity的布局文件,直接放置 TextView, 然后启动你的MainActivity.

通过上面的几个步骤,你就完成了目标,做到了纯文本,带渐变,还带动画的启动页。