Mipmap可缩放图标的绘制

474
自Android 4.3(Jelly Bean)起,我们现在可以使用res/mipmap文件夹来存储“mipmap”图像。例如,Chrome for Android将其图标存储在这些文件夹中,而不是更常规的res/drawable文件夹。那么这些mipmap图像与其他熟悉的drawable图像有什么不同呢?我发现在我的清单中,我们使用@mipmap/限定符,而不是@drawable/,这在资源文件夹名称上是有意义的。
<activity
    android:name=".MipmapDemp"
    android:icon="@mipmap/ic_launcher" />

参考资料:

Android 4.3 APIs文档如下所述:

使用mipmap作为位图或可绘制对象的源是提供高质量图像和各种图像比例的简单方法,如果您希望在动画期间缩放图像,则这尤其有用。

Android 4.2(API级别17)在Bitmap类中添加了对mipmaps的支持-当您提供了mipmap源并启用setHasMipMap()时,Android会交换Bitmap中的mip图像。现在,在Android 4.3中,您也可以通过在位图资源文件中提供mipmap资产并设置android:mipMap属性,或者调用hasMipMap()来为BitmapDrawable对象启用mipmaps。

我没有看到任何有助于我理解的内容。


XML位图资源具有一个android:mipMap属性:

布尔值。启用或禁用mipmap提示。有关更多信息,请参见setHasMipMap()。默认值为false。

据我所见,这不适用于启动器图标。


这个问题在Google Groups上被提出(资源名称“mipmap”的目的是什么?!),Romain Guy回答道:

提供一个比通常计算得到的更大分辨率的图像是有用的(例如,在mdpi设备上,启动器可能希望显示大的应用程序快捷方式的更大的hdpi图标)。

我觉得这几乎解释清楚了,但还是有点模糊。

我还倾向于采用Randy Sugianto的跟进建议:

这有什么优势吗?是否有指南可以使用mipmaps,也许是为了更好的启动器图标?


当然,维基百科有一个"Mipmap"的页面,它指的是一种在1983年发明的旧技术,我无法与当前的Android实现联系起来。

最近我们应该把所有的应用程序图标存储在res/mipmap文件夹中吗?如果是,这些mipmap图片的指南是什么?


更新 #1

这是一篇博客文章,试图对此进行解释。

但是,该博客文章中使用的图像显示出看起来像是一个文件中有许多标志的情况。这不是我在Chrome的mipmap文件夹中看到的。

Chrome的mipmap-hdpi文件夹包含三个图像。其中一个是Chrome标志,单独存在。

Chrome mipmap-hdpi icon.png

奇怪的是,它是72x72而不是我期望看到的48x48。也许这就是问题所在 - 我们只需要将更大的图标放在mipmap文件夹中?

更新 #2

2014年10月23日的Android Developers博客文章再次确认使用mipmap文件夹作为应用程序图标的想法:

当谈到Nexus 6屏幕密度时,作者写道:

最好的做法是将您的应用程序图标放置在mipmap文件夹中(而不是drawable文件夹),因为它们可用于不同于设备当前密度的分辨率。例如,xxxhdpi应用程序图标可以用于xxhdpi设备的启动器。


更新 #3

请注意,Android Studio会在mipmap...文件夹中创建ic_launcher.png图标,而不是Eclipse曾经创建的drawable...文件夹。


12个回答

269

mipmaps 有两个不同的用途:

  1. 在构建密度特定的 APK 时用于启动器图标。一些开发人员为每个密度构建单独的 APK,以降低 APK 的大小。然而,一些启动器(随一些设备一起发货或可在 Play 商店中获得)使用比标准的 48dp 更大的图标尺寸。启动器使用 getDrawableForDensity 并根据需要进行缩小,而不是放大,因此图标具有高质量。例如,在 hdpi 平板电脑上,启动器可能会加载 xhdpi 图标。将启动器图标放在 mipmap-xhdpi 目录中,可以避免在为 hdpi 设备构建 APK 时像 drawable-xhdpi 目录那样被删除。如果你正在为所有设备构建单个 APK,则这并不重要,因为启动器可以访问所需密度的 drawable 资源。

  2. 实际的 mipmap API 来自 4.3 版本。我没有使用过它,也不熟悉它。它不被 Android 开放源代码项目的启动器使用,我也不知道其他任何启动器在使用它。


2
那么您是在建议一个构建脚本,用于删除除mipmap资源以外的所有不正确密度文件夹,如果我理解正确的话? - Richard Le Mesurier
20
我建议只需构建一个APK适用于所有密度,不必担心它。但是,mipmap目录有时用于启动器图标的原因是由于构建脚本(aapt --preferred-configurations)会删除drawable-{density}目录,但不会删除mipmap-{density}目录。这几乎像是利用缺陷,但你从Romain Guy和Diane Hackborn在https://plus.google.com/105051985738280261832/posts/QTA9McYan1L的帖子中引用的内容表明这是设计意图。 - Kevin TeslaCoil
3
我通常的流程是删除mipmap,将我的图标放置在drawables中,并构建一个单独的APK,这样做非常完美。听起来大多数开发者不使用mipmap,但它强制适用于我们所有人。 - Someone Somewhere
文档中写道:“mipmap:不同启动器图标密度的可绘制文件。” https://developer.android.com/guide/topics/resources/providing-resources - activity

80
似乎自所有这些答案以来,谷歌已经更新了他们的文档,所以希望这会帮助未来的某个人 :) 我自己也在创建一个新的(新的新的)项目时遇到了这个问题。
简而言之,作为dp特定资源优化的一部分,可绘制物可能会被剥离。但是mipmaps不会被剥离。
不同设备上的不同主屏幕启动器应用程序以各种分辨率显示应用程序启动器图标。当应用程序资源优化技术删除未使用的屏幕密度资源时,启动器图标可能看起来模糊,因为启动器应用程序必须放大低分辨率图标以供显示。为避免这些显示问题,应用程序应使用mipmap/资源文件夹作为启动器图标。Android系统保留这些资源,无论密度剥离如何,并确保启动器应用程序可以选择最佳分辨率的图标进行显示。(来自http://developer.android.com/tools/projects/index.html#mipmap)

2
这与Android Studio导入图像资源时的默认放置方式一致。启动器图标放置在mipmap中,其他图像放置在drawable中。 - Edward Brey
2
文档似乎又发生了变化,尽管 Android 的其他部分仍然试图引用它,但 mipmap 在 http://developer.android.com/tools/projects/index.html 中似乎不存在。 - SomeoneElse

29
这些mipmap图像和其他熟悉的可绘制图像有何不同?
以下是我尝试解释差异的建议。在Android中处理图像时,有两种情况:
1. 您希望为设备密度加载图像,并且您将“按原样”使用它,而不更改其实际大小。在这种情况下,应使用drawables进行工作,Android会提供最适合的图像。
2. 您希望为设备密度加载图像,但此图像将被放大或缩小。例如,当您想显示更大的启动器图标或者您有一个增加图像大小的动画时,就需要这样做。在这种情况下,为确保获得最佳图像质量,应该将图像放入mipmap文件夹中。Android会尝试从较高密度桶中选择图像,而不是对其进行缩放。这将提高图像的清晰度(质量)。
因此,决定将图像放入哪里的经验法则如下:
- 启动器图标始终放在mipmap文件夹中。 - 需要经常缩放(或极度缩小)且其质量对于应用程序至关重要的图像也应放在mipmap文件夹中。 - 所有其他图像都是常规drawables

所以,操作栏的图标或浮动按钮的图标放在mipmap文件夹中吗? - Juan De la Cruz
不,它们是普通的可绘制对象。 - sergej shafarenka
嗨,关于第二点,如果安卓系统会切换到更高的分辨率而不是增加启动器图标的大小,那我们该如何增加启动器的大小呢?谢谢。 - CodingChap

24

Android 4.3中mipmaps的实现技术正是维基百科文章中解释的1983年的技术。

每个mipmap集合中的位图图像都是主纹理的缩小副本,但在特定的降低细节级别上。虽然当视图足够以完整细节呈现主纹理时仍将使用主纹理,但当从远处或小尺寸查看纹理时,渲染器将切换到适当的mipmap图像(...)。

尽管这被描述为三维图形技术(因为它提到了“从远处观看”),但对于二维图形同样适用(翻译为“绘制在较小的空间中”,即“缩放”)。

以Android具体示例为例,想象一下您有一个带有某个背景可拉伸 drawable(特别是一个BitmapDrawable)的View,现在使用动画将其缩小到原始大小的0.15倍。通常,这需要为每个帧缩小背景位图。然而,这种“极端”缩小可能会产生视觉伪影。

不过,您可以提供一个mipmap,这意味着该图像已经预渲染为几个特定的比例尺度(比方说1.0、0.5和0.25)。每当动画“越过”0.5阈值时,它将切换到0.5图像并对其进行缩放,而不是继续缩小原始的1.0大小的图像,这应该会提供更好的效果。随着动画的继续,以此类推。

这有点理论化,因为实际上是由渲染器完成的。根据Bitmap类的源代码,这只是一个提示,渲染器可能遵循也可能不遵循它。

/**
 * Set a hint for the renderer responsible for drawing this bitmap
 * indicating that it should attempt to use mipmaps when this bitmap
 * is drawn scaled down.
 *
 * If you know that you are going to draw this bitmap at less than
 * 50% of its original size, you may be able to obtain a higher
 * quality by turning this property on.
 * 
 * Note that if the renderer respects this hint it might have to
 * allocate extra memory to hold the mipmap levels for this bitmap.
 *
 * This property is only a suggestion that can be ignored by the
 * renderer. It is not guaranteed to have any effect.
 *
 * @param hasMipMap indicates whether the renderer should attempt
 *                  to use mipmaps
 *
 * @see #hasMipMap()
 */
public final void setHasMipMap(boolean hasMipMap) {
    nativeSetHasMipMap(mNativeBitmap, hasMipMap);
}

虽然我不太确定为什么这对应用程序图标尤其合适。 尽管在平板电脑上的Android以及一些启动器(例如GEL)要求使用“更高密度”的图标来显示更大,但这应该使用常规机制(即drawable-xxxhdpi等)来完成。


这并没有真正解释与包含mipmapped图像的“drawable”文件夹的区别。 - Timmmm
2
事实上,这个答案是完全错误的。唯一的区别在于文件是否被剥离,与是否使用mipmapping无关(两种情况下都会使用)。这个文件夹的命名有点不好,他们可能应该称其为“drawable-nostrip”或其他名称。 - Timmmm
2
对mipmaps的解释很好,但Kazuaki的答案提到了一个Google文档条目,似乎暗示这并不是原因。 - Trilarion

11

是的,正如在被接受的答案中由Kevin提到的那样。这似乎是背后的主要原因。 - Richard Le Mesurier
@RichardLeMesurier 是的,只是为了简短明了。 - k4dima

4
自从我正在寻找一个阐述清晰的答案来确定通知图标的正确类型,我想在这个主题上添加这个清晰的陈述。它来自http://developer.android.com/tools/help/image-asset-studio.html#saving

注意:启动器图标文件位于与其他图标不同的位置。它们位于项目的 mipmap/ 文件夹中。所有其他图标文件位于 drawable/ 文件夹中


3

当在Android中处理图片时,有两种情况需要考虑: 1. 您想为设备密度加载一张图片,并且您将使用它“原样”,而不改变其实际大小。在这种情况下,您应该使用drawable并且Android会提供最适合的图像。 2. 您想要为设备密度加载一张图片,但是这张图片将被缩放。例如,当您想显示更大的启动器图标或者您有一个增加图像大小的动画时,就需要这样做。在这种情况下,为确保最佳图像质量,应将图像放入mipmap文件夹中。Android会尝试从较高密度桶中选择图像,而不是对其进行缩放。 因此,决定将图像放在哪里的经验法则如下: 1. 启动器图标始终放在mipmap文件夹中。 2. 经常缩放(或极端缩小)且其质量对于应用程序至关重要的图像也应放在mipmap文件夹中。 3. 所有其他图像都是普通的drawables。

引用自this文章。


2

当为不同密度构建单独的apk时,其他密度的drawable文件夹会被剥离。这将使在使用更高密度的启动器图标的设备上,图标看起来模糊。 由于mipmap文件夹不会被剥离,因此最好始终使用它们来包含启动器图标。


2

当我们为不同密度构建单独的APK时,对于特定密度的APK,其他密度的drawable文件夹被剥离了。这会导致在使用高密度启动器图标的设备上,图标看起来模糊。由于mipmap文件夹不会被剥离,因此最好使用它们来包含启动器图标。


1
如果您为目标屏幕分辨率(如HDPI)构建APK,则Android资产包装工具AAPT可以剥离您不需要的其他分辨率的可绘制对象。但是,如果它在mipmap文件夹中,则这些资源将留在APK中,而不管目标分辨率如何。

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