Android 启动屏

前言

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

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

方案一

做一个静态 activey 欢迎页,在开始加载主界面前,立即显示这个 activey 覆盖在主界面上,待主界面准备好之后,移除这个 activey,比如 react-native-splash-screenreact-native-bootsplash 就是采用的这种方案。

但这带来一个问题,就是这个欢迎页本身的绘制也需要时间,虽然非常快,但启动时显示的仍然是白色启动背景。如果 activey 欢迎页本身也是白色背景,视觉上是渐进的,倒也问题不大,但如果欢迎页背景为其他颜色,这个白色闪屏就非常明显了。消除白屏的其中一个方法是在 android/app/src/main/res/values/styles.xml 进行如下设置

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

经过上面的修改,没有启动白屏了,但会发现,点击 app 图标后,会有一下停顿感,然后显示欢迎屏。其实很好理解,这个停顿感其实就是正在显示透明的启动背景,等同于把白屏体验改为停顿感了,体验更差。更好的办法是修改启动背景的颜色,这样效果更好,比如 activey 欢迎页为黑色背景,则可修改启动背景为黑色来避免启动时的白色闪屏

<resources>
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
         .....
         <!--启动背景改为黑色-->
         <item name="android:windowBackground">#ff000000</item>
    </style>
</resources>

方案二

上面使用 activey 做启动屏的好处是,可以进行编程,实现较为复杂的甚至是带动画的界面,但正如上述,绘制 activey 本身也是需要时间的,所以点击 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:antialias="true"
            android:filter="true"
            android:gravity="center" 
            android:src="@drawable/splash_img"/>
    </item>
</layer-list>

启动背景作为开屏图有以下特点,若满足要求,推荐此方案:

  1. 劣势:这是一个类似于 Canvas 绘图逻辑的资源文件,支持的 绘图方式 较为有限,无法实现较为复杂的启动屏,通常就是直接插入图片。

  2. 上例中第一个 item 用来设置背景颜色,因为 android 有众多分辨率,若启动背景图较小,无法覆盖满整个屏幕,可设计启动图片的边缘为纯色,和所设置背景颜色自动衔接即可。

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

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

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

其他启动配置

上述两个方案中仅针对启动背景做了设置(比如设置为透明或指定颜色/资源),除此之外,还有一些其他的常用设置,下面也做个简单的介绍,某些配置项有版本限制,可根据以下规则进行配置:

  • 无 API 版本限制的在 android/app/src/main/res/values/styles.xml 中配置
  • 有 API 版本限制在 values-v(n) 文件夹下配置,比如最低 API Level 19,在 android/app/src/main/res/values-v19/styles.xml 中配置
  • 如 API Level 19 仍需要通用配置的话,需将配置从 /values/styles.xml 复制到 values-v19/styles.xml,换句话说,每个配置都是独立的,而不是继承。
<resources>
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">

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

           <!--
             API 27: 在 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>

推荐配置

可使用以下方案来尽可能兼容各版本 Android(值得注意的是,RN 在 0.64 之后 已不再支持 5.0 版本(API 21)以下了,目前或许还可运行,以后将不再维护,毕竟只有2%左右的占有率,无需花费太多精力),以下路径均在 android/app/src/main/res 目录下:

  1. /values/styles.xml:中仅设置启动背景就好了,状态栏/导航栏保持默认,兼容特低版本(低于 4.4)
<resources>
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        ...
        <item name="android:windowBackground">@drawable/splash</item>
    </style>
</resources>
  1. /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>
  1. /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>

测试方案一

上面的配置同时适用于方案一二,使用方案一测试一下,即使用 activey 作为启动页。修改上面配置中的资源文件
<item name="android:windowBackground">@drawable/splash</item> 为颜色值
<item name="android:windowBackground">@android:color/darker_gray</item>

新增一个 layout/splash.xml,代码如下

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

    <ImageView
        android:contentDescription="@android:string/unknownName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:antialias="true"
        android:filter="true"
        android:translationY="0dp"
        android:src="@drawable/splash_img" />
    
</LinearLayout>

MainActivity.java 中加载 xml

...
 @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // 这里仅为了测试显示效果,直接加载 layout/splash
    // 若实际使用, 应该在这之前, 在 ContentVIew 上层显示 layout/splash
    setContentView(R.layout.splash);
  }
...

最终效果图如下(红色横线是后期加上去的),启动屏显示的位置在红线之间,即可用区域内,LOGO 居正中。通常情况下,我们一般希望图片在垂直方向略微偏上,而不是完全上下居中,有两种方法:

  • 可根据图片高度修改上面的偏移数字,比如将 android:translationY="0dp" 改为 android:translationY="-40dp"
  • 直接设置垂直居顶 android:layout_gravity="top" 同时设置 android:translationY="136dp"
方案一效果图

测试方案二

取消上述 android:windowBackground 属性的修改,仍使用启动背景作为启动屏方案,新增启动背景 /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="#aaa"/></item>
    <item android:bottom="0dp">
        <bitmap
            android:antialias="true"
            android:filter="true"
            android:gravity="center" 
            android:src="@drawable/splash_img"/>
    </item>
</layer-list>

此时效果图如下,启动背景的显示区域在红线之间,在不同版本的或不同手机上显示效果不同。同理的,如希望图片在垂直方向上稍微偏上,也可使用下面两种方法

  • 修改上面 bitmap 所在的 item 属性,比如将 android:bottom="0dp" 修改为 android:bottom="30dp"
  • 修改 bitmap 垂直位置为 android:gravity="top|center_horizontal"item 偏移改为 android:top="136dp"
方案二效果图

启动图尺寸

上述例子是启动屏的常见形式,显示效果还可以,从设计的角度讲,只需把控启动图的尺寸即可取得不错的观感。当下 Android 最大 DPI 为 xxxhdpi (> 640DPI),所有 DPI 可参考 官方文档,由于上述 XML 代码已经设置了缩放图片时消除锯齿,平滑过渡,所以为了维护方便,一般情况下,只需提供最大尺寸图片,DPI 较低的手机会自动使用该图进行缩放,即只需添加 drawable-xxxhdpi/splash_img.png 一张图片即可,图片尺寸则可以按照以下规则进行设计。

上面演示的图片宽度为 384px,保存在 drawable-xxxhdpi 目录,那么图片在 640DPI 的手机上将显示为实际尺寸(384px),其他 DPI 手机上的显示宽度计算公式为 显示宽度 = 384 * 手机DPI / 640,上面演示所用模拟器的分辨率为 1440,DPI 为 560,所以实际显示尺寸为 384 * 560 / 640 = 336,经测量,符合预期。一般情况下,手机 DPI 和 分辨率相对固定(可 参考),按照上述公式可算得,384px 的启动图实际显示尺寸大概有如下关系

限定符 DPI 分辨率 图片显示尺寸 启动图宽占比
xxxhdpi 640~ 1440 384 0.27
xxhdpi 480~640 1080 288~384 0.27 ~ 0.36
xhdpi 320~480 720 192~288 0.27 ~ 0.4
hdpi 240~320 480 144 ~192 0.3 ~ 0.4
mdpi 160~240 320 96 ~144 0.3 ~ 0.45
ldpi 120~160 240 72 ~96 0.3 ~ 0.4

通常情况下,无需考虑后三个了,这么老的手机基本被淘汰了(可 参考),最终可得出大概结论,在 xxxhdpi 密度下的开屏 LOGO 如果为 384px,那么宽度占比约为 30%,可根据设计需要依此为依据进行调整,比如取 512px,那么宽度占比约为 512/384 * 30% = 40%

上下图启动屏

上述启动图较为简单,除上述启动图之外,还有两种较为常见的启动图形式:

  1. 仅有一张启动 LOGO 图,放在屏幕底部。
  2. 有两张启动图,上面一张较大的,底部一张稍小的。

二者与一张图正居中的主要区别在于会有图片放在屏幕底部,底部的图就不那么简单了,有兼容性问题,这里选用上下启动图进行测试以作说明。仍然按照上述思路,先使用 activey 作为启动页,经测试,这种方案没有问题,无需多说,layout/splash.xml 代码和效果图如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:layout_gravity="center"
        >
        <ImageView
            android:contentDescription="@android:string/unknownName"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:antialias="true"
            android:filter="true"
            android:translationY="-30dp" 
            android:src="@drawable/splash_top"/>

    </LinearLayout>

    <ImageView
        android:contentDescription="@android:string/unknownName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:antialias="true"
        android:filter="true"
        android:translationY="0dp"
        android:src="@drawable/splash_bottom" />
</LinearLayout>
上下图均在预期的红线之间

再试一下使用启动背景的方案,/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="#aaa"/></item>
    <item android:top="-30dp">
        <bitmap
            android:antialias="true"
            android:filter="true"
            android:gravity="center"
            android:src="@drawable/splash_top" />
    </item>
    <item android:top="0dp">
        <bitmap
            android:antialias="true"
            android:filter="true"
            android:gravity="bottom|center_horizontal"
            android:src="@drawable/splash_bottom" />
    </item>
</layer-list>
使用启动背景作为方案的效果图

可见效果图是符合逻辑的,但却不符合期望效果。在 Android4.4 以上的非全面屏手机上,下图会被导航栏覆盖,如果对下图显示的位置不那么在意,可以给 /drawable/splash.xml 下图所在的 item 修改为 android:bottom="48dp",因为通常情况下,导航栏的高度为 48dp,这样可以让下图也能显示出来,但这也会带来两个问题:

  1. Android4.4 以下和全面屏,下图也会向上移动 48dp,设计感可能会不如预期。
  2. 并非所有手机的导航栏高度都一定为 48dp,为了保险起见,可能还需要加大该数值。

若无法接受这种方案,还有一种解决方案是修改 styles.xml。因为只有在 Android4.4 以上才有此问题,所以保持 /values/styles.xml/values-v19/styles.xml 不变,只需修改 /values-v21/styles.xml 即可(如果设置了 values-v23 也要同时修改),可以从上面介绍的启动配置中选择的合适的进行设置,有三种常见的方案

<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:navigationBarColor">@android:color/transparent</item>
    </style>
</resources>

<resources>
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        ...
        <!--状态栏/导航栏不属于背景区域,由系统接管-->
        <item name="android:windowBackground">@drawable/splash</item>
        <item name="android:windowDrawsSystemBarBackgrounds">false</item>
    </style>
</resources>


<resources>
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        ...
        <!--导航栏不属于背景区域,由系统接管;状态栏不显示-->
        <item name="android:windowBackground">@drawable/splash</item>
        <item name="android:windowDrawsSystemBarBackgrounds">false</item>
        <item name="android:windowFullscreen">true</item>
    </style>
</resources>

三种配置的效果图如下:

  • 第一种方案对全面屏手机友好(本来就没有导航栏,还可以显示状态栏),但对于有导航栏的显示效果就会如下图所示;
  • 第二种头部的状态栏无法自定义设置,总是为黑边,通常不使用这一种,不好看;
  • 第三种是大部分APP选择的方式,可以兼顾全面屏和有导航栏的,缺点是在冷启动瞬间不显示状态栏,在 APP 加载成功后需通过代码动态显示状态栏。因为状态栏被隐藏,这样也无需设置 values-v23 了。
  • 上述也不是绝对的,比如启动背景为一张全屏的大背景图,此时使用第一种方案可能会更友好一点。
三种不同处理方式的效果图

细心的朋友应该看出来上述截图没有使用刘海屏手机,这是因为第三种方案对于刘海屏不友好,由于 android:windowDrawsSystemBarBackgrounds 的配置,状态栏会变成一个大黑边(参见上面的启动配置介绍),需要新增一个 /values-v27/styles.xml (Android 8.1 及以上) 用以适配全面屏,配置如下

<resources>
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        ...
        <!--导航栏不属于背景区域,由系统接管;状态栏不显示-->
        <item name="android:windowBackground">@drawable/splash</item>
        <item name="android:windowDrawsSystemBarBackgrounds">false</item>
        <item name="android:windowFullscreen">true</item>
        <!--在 v21 基础上新增刘海设置-->
        <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
    </style>
</resources>
添加刘海配置前后的截图

上述应该算作较为完美的处理启动屏的方案了,如果希望上图位置向上偏移,可参考上面只有一张居中图的说明。最后剩下一个小问题,隐藏的状态栏应该在 App 主界面加载完毕后显示出来才好,对于 RN 可以使用下面的方法,原生开发可参考 RN 的 实现

import { StatusBar } from 'react-native';

StatusBar.setHidden(false);
StatusBar.setTranslucent(false);
StatusBar.setBackgroundColor('#000');//transparent

由于启动图是使用 Window 窗口背景实现的,当主界面加载后,会自动覆盖背景图,无需继续处理也没什么影响。但可以考虑在加载完毕后,清除 Window 窗口背景,这样也许可释放一些图片占用的内存(未测试),由于属于能做则做,不做也行的范畴,就不多说了。

继续:

iOS 启动屏
React Native 启动屏

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容