Android 启动画面没有徽标失真

Android splash screen without logo distortion

是否可以创建一个带有徽标的启动画面,该徽标保持其宽高比,同时背景图像可以独立调整大小?我目前正在为不同的分辨率使用多个 .png 文件,它们在大多数设备上看起来都很棒。然而,有一些手机严重扭曲了我的标志(即三星 S8,移动竖屏 space)。

我可以处理启动画面背景的一些失真,但 skinny/squashed 徽标是不可接受的。有谁知道如何做到这一点?对于新布局,矢量可绘制徽标会比 .png 更好吗?

您是否考虑过保持 ImageView 的纵横比?这是一个相关问题,应该为您指明正确的方向:How to scale an Image in ImageView to keep the aspect ratio

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" 
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/bg"
    android:gravity="center">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/logo"/>

</RelativeLayout>

这会做到这一点


这是在 nexus 10

如果您的启动画面只有纵向图像,这里有一个解决方案,它是纵向全屏,居中但不裁剪 edit: 纵向横向:

splash_screen.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/layoutSplash"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="@color/splash_screen_background">

    <ImageView
        android:contentDescription="@string/splash_screen_description"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center_vertical"
        style="@style/SplashScreen" />

</LinearLayout>

values/styles.xml

<style name="SplashScreen">
    <item name="android:src">@drawable/splash</item>
    <item name="android:adjustViewBounds">true</item>
    <item name="android:scaleType">fitCenter</item>
</style>

values-port/styles.xml

<style name="SplashScreen">
    <item name="android:src">@drawable/splash</item>
    <item name="android:adjustViewBounds">true</item>
    <item name="android:scaleType">centerCrop</item>
</style>

根本不用layouts,用一个LayeredList,做背景。这是一个例子;

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

在 layout.xml 中渲染初始视图而不是作为主题背景(就像这里推荐的其他答案一样)需要更长的时间来加载。这是因为首先加载应用程序的主题,然后构建 Activity,最后展开布局。由于启动画面的目的是在应用程序加载时显示某些内容,因此启动画面本身的加载延迟约 0.5 秒会导致明显的延迟。将启动画面作为主题窗口背景加载效果更好(在点击启动器图标后几乎立即呈现),但有一些限制需要解决。您当前根据屏幕宽度定义多个徽标大小的方法是处理这种情况的正确方法。这是一个示例配置,它处理 pre 和 post Android v21:

之间的差异

values/themes.xml:

<style name="SplashThemeCommon" parent="Theme.AppCompat.NoActionBar">
    <item name="android:windowContentOverlay">@null</item>
    <item name="android:windowBackground">@drawable/splash_logo_theme</item>
</style>

<style name="SplashTheme" parent="SplashThemeCommon">
    <item name="android:windowFullscreen">true</item>
</style>

values-v21/themes.xml:

<style name="SplashTheme" parent="SplashThemeCommon">
    <item name="android:windowTranslucentStatus">true</item>
    <item name="android:windowTranslucentNavigation">true</item>
</style>

drawable/splash_logo_theme.xml

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

接下来您可以为不同的屏幕配置添加一份 "splash_logo.png"。您在这里有几个合理的选择。一种详尽的方法可能包括针对每种屏幕尺寸的不同徽标:

  • drawable-sw320dp-xxxhdpi/splash_logo.png
  • drawable-sw400dp-xxxhdpi/splash_logo.png
  • drawable-sw480dp-xxxhdpi/splash_logo.png
  • drawable-sw600dp-xxxhdpi/splash_logo.png
  • drawable-sw720dp-xxxhdpi/splash_logo.png
  • drawable-sw820dp-xxxhdpi/splash_logo.png

"swXXXdp"表示XXX是以dp为单位的最小屏幕尺寸(宽度或高度)。 820dp 将是一个巨大的平板电脑,320dp 将是一个古老的小型设备,而当今的大多数旗舰设备将属于 400dp 类别。 450dp 宽的设备将使用 400dp 图像。

为什么我要在这里定义xxxhdpi?因为如果你不指定,Android 将假定它是 mdpi 图像并尝试 upscale/resize 用于更高 dpi 的设备(当今大多数旗舰手机都是 xxhdpi)。这种放大将导致您的图像呈块状,并且比原始图像大。通过在此处指定 xxxhdpi,Android 将仅尝试缩小图像以确保图像永远不会出现块状;这是一个优化,因此我们不需要为 ldpi、mdpi、hdpi、xhdpi 等定义单独的图像。

虽然 APK 中有 6 张图片有点浪费。我们可以进一步优化此方法,以在应用程序中包含更少的图像并确保更小的 APK 大小。相反,我们只包含以下两张图片:

  • drawable-sw600dp-xxxhdpi/splash_logo.png
  • drawable-xxxhdpi/splash_logo.png

任何 600dp 和更大的设备(平板电脑)都有一个更大的图像副本以利用更大的屏幕空间,而所有其他手机使用位于容器中的较小副本,没有屏幕宽度限定符。这里的缺点是,由于每个容器覆盖了如此大的屏幕宽度范围,因此 4" 设备上的徽标将比 6" 设备上占据更大的屏幕部分。这是减少 APK 大小的妥协,只要图像从不被截断,即使在最小的设备上,大多数用户也不会注意到。

那么我们应该包括多大尺寸的 png?它们需要特定大小才能显示在主题中,因为与 layout.xml 不同,我们不能在 XML 中指定 width/height(仅添加了可绘制 width/height 支持在 API 23)。这意味着如果你包含一个非最佳的 png 大小,它会显得太小或两倍大;如果它太大,它实际上会被切断。获得合适尺寸的好计划是:

  • 创建一个 layout/test.xml 文件,只有默认的 LinearLayout 并且没有可见内容
  • 在 Android Studio 和 select 布局编辑器左下角的“设计”选项卡中打开它
  • 在布局编辑器的顶部栏中将主题更改为 SplashTheme
  • 将设备更改为"Pixel XL"
  • 将图片放在 drawable-sw400dp/splash_logo.png
  • 在 Photoshop 或 Gimp 等外部图像编辑器中打开图像,更改大小,保存,然后在 Android Studio 中检查布局(您可能需要关闭并重新打开编辑器才能更改为生效)。重复直到图像在布局中看起来正确大小
  • 按比例为其他屏幕宽度生成图像;例如,sw320dp 图像应为 320/400 或 400dp 图像大小的 67%,而 720dp 图像应为 720/400 或 400dp 图像大小的 180%。切记不要将 400dp 图像放大为更大的图像,因为这样会降低质量。相反,根据您的高质量原始副本生成所有图像
  • 将生成的图像放在上面指定的不同可绘制目录中
  • Select 布局编辑器中不同屏幕尺寸(包括平板电脑)的设备,并确保它们的徽标足够大,但不会被截断,适用于所有屏幕尺寸

您如何知道哪个设备屏幕分辨率属于哪个 swXXXdp 类别?这需要简单的计算。让我们看看 Pixel XL:

  • 屏幕尺寸为 1440x2560
  • 因此最小尺寸为 1440
  • 屏幕dpi为534
  • 以英寸为单位的屏幕宽度为 1440/534=2.69"
  • 打开网站:http://angrytools.com/android/pixelcalc/
  • 在英寸 ("in") 框中输入 2.69
  • 左边的绿色框之一将显示 dp,在本例中为 431
  • 对于 431 dp 宽的屏幕,Pixel XL 将使用 drawable-sw400dp/splash_logo.png 图像(如果您拥有所有 6 个图像类别),或者 drawable-xxxhdpi/splash_logo.png 图像(如果您只有两个图像类别)图片类别
  1. 在Androidresources/res文件夹中,新建文件夹“drawable-xxxhdpi”和“drawable- sw600dp"

  2. 在“drawable-sw600dp”文件夹中,添加分辨率为[=的'splash_logo.png' 20=]4096x4096 像素。这应该包括平板电脑。

  3. 在“drawable-xxxhdpi”文件夹中,添加另一个'splash_logo.png”分辨率为1440x2560像素。这应该涵盖智能手机。

这就是解决所有扭曲的方法!