用于图标的 Mipmap 可绘制对象

Posted

技术标签:

【中文标题】用于图标的 Mipmap 可绘制对象【英文标题】:Mipmap drawables for icons 【发布时间】:2014-07-19 02:30:39 【问题描述】:

android 4.3 (Jelly Bean) 开始,我们现在可以使用 res/mipmap 文件夹来存储“mipmap”图像。

例如,Android 版 Chrome 将其图标存储在这些文件夹中,而不是更普通的 res/drawable 文件夹中。

这些 mipmap 图像与其他熟悉的可绘制图像有何不同?

我看到在我的清单中,我们使用了@mipmap/ 限定符,而不是@drawable/,考虑到资源文件夹名称,这很有意义:

<activity
    android:name=".MipmapDemp"
    android:icon="@mipmap/ic_launcher" />

参考资料:

Android 4.3 APIs 文档有以下内容:

使用 mipmap 作为位图或 drawable 的源是一个简单的 提供高质量图像和各种图像比例的方法,可以是 如果您希望图像在 动画。

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

我没有看到任何可以帮助我理解的内容。


XML Bitmap resources 有一个 android:mipMap 属性:

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

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


这个问题是在 Google 网上论坛 (The purpose of resource name "mipmap"?!) 上提出的,Romain Guy 回复道:

提供更大分辨率的图像很有用 通常被计算(例如,在 mdpi 设备上,Launcher 可能 希望较大的 hdpi 图标显示较大的应用程序快捷方式。)

我觉得这几乎是有道理的,但并不完全。

我仍然倾向于 Randy Sugianto 的后续行动:

这样做有什么好处?有没有指导如何使用 mipmaps,可能是为了更好的启动器图标?


当然,Wikipedia has a page for "Mipmap",它指的是 1983 年发明的一种较旧的技术,我与当前的 Android 实现不太相关。


这些天我们是否应该将所有应用程序图标存储在res/mipmap 文件夹中,这些mipmap 图像的指南是什么?


更新 #1

这是一篇试图解释它的博客文章。

Mipmapping for drawables in Android 4.3

但该博客文章中使用的图片显示了一个文件,其中包含许多徽标。这不是我在 Chrome 的 mipmap 文件夹中看到的。

Chrome 的mipmap-hdpi 文件夹包含三个图像。一个是单独的 Chrome 徽标。

奇怪的是,它是 72x72,而不是我希望看到的 48x48。

也许这就是全部 - 我们只需要在 mipmap 文件夹中保留更大的图标?


更新 #2

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

Getting Your Apps Ready for Nexus 6 and Nexus 9

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

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


更新 #3

请注意,Android Studio 在mipmap... 文件夹中创建ic_launcher.png 图标,而不是在Eclipse 用来创建它们的drawable... 文件夹中。


【问题讨论】:

【参考方案1】:

mipmap 有两种不同的用途:

    用于构建特定密度的 APK 时的启动器图标。一些开发人员为每个密度构建单独的 APK,以减小 APK 的大小。然而,一些启动器(随某些设备提供,或可在 Play 商店中获得)使用比标准 48dp 更大的图标尺寸。启动器使用 getDrawableForDensity 并根据需要缩小而不是放大,因此图标质量很高。例如,在 hdpi 平板电脑上,启动器可能会加载 xhdpi 图标。通过将启动器图标放在 mipmap-xhdpi 目录中,在为 hdpi 设备构建 APK 时,它不会像 drawable-xhdpi 目录那样被剥离。如果您正在为所有设备构建一个 APK,那么这并不重要,因为启动器可以访问所需密度的可绘制资源。

    来自 4.3 的实际 mipmap API。这个我没用过,也不熟悉。 Android 开源项目启动器不使用它,我不知道有任何其他启动器在使用它。

【讨论】:

如果我理解正确的话,您建议使用一个构建脚本来去除除 mipmap 资源之外的所有资源的不正确密度文件夹? 我建议只为所有密度构建一个 APK 而不必担心。但是是的,有时将 mipmap 目录用于启动器图标的原因是构建脚本(aapt --preferred-configurations)剥离了可绘制的 density 目录而不是 mipmap-density 目录。这几乎看起来像是在利用一个错误,但您在 Romain Guy 和 Diane Hackborn 在plus.google.com/105051985738280261832/posts/QTA9McYan1L 的帖子中的引述表明它是设计使然。 所以我删除 mipmap、将图标放入可绘制对象和构建单个 APK 的典型过程非常完美。听起来 mipmap 对于我们大多数开发人员来说是非典型的,但它是强加于我们所有人的。 在文档中它说:“mipmap:不同启动器图标密度的可绘制文件。” developer.android.com/guide/topics/resources/…【参考方案2】:

谷歌似乎已经更新了他们的文档,因为所有这些答案,所以希望这会在未来对其他人有所帮助:) 我自己在创建一个新的(新的)项目时遇到了这个问题。

TL;DR:drawables 可以作为 dp 特定资源优化的一部分被剥离。 Mipmap 不会被剥离。

不同设备上的不同主屏幕启动器应用以不同的分辨率显示应用启动器图标。当应用程序资源优化技术为未使用的屏幕密度删除资源时,启动器图标可能看起来很模糊,因为启动器应用程序必须放大较低分辨率的图标才能显示。为避免这些显示问题,应用程序应使用 mipmap/ 资源文件夹作为启动器图标。无论密度剥离如何,Android 系统都会保留这些资源,并确保启动器应用可以选择具有最佳分辨率的图标进行显示。

(来自http://developer.android.com/tools/projects/index.html#mipmap)

【讨论】:

这与Android Studio在导入图片资源时的默认放置一致。启动器图标进入 mipmap;其他人进入drawable。 文档似乎又变了,developer.android.com/tools/projects/index.html 中似乎不存在 mipmap(尽管 Android 文档的其他部分仍在尝试引用它)。【参考方案3】:

这些 mipmap 图像与其他熟悉的可绘制图像有何不同?

这是我试图解释差异的两分钱。在 Android 中处理图像时,您需要处理两种情况:

    您想为您的设备密度加载图像,并且您将“按原样”使用它,不改变其实际大小。在这种情况下,您应该使用 drawables,Android 将为您提供最合适的图像。

    您想为您的设备密度加载一张图片,但该图片将被放大或缩小。例如,当您想显示一个更大的启动器图标,或者您有一个动画,这会增加图像的大小时,这是需要的。在这种情况下,为确保最佳图像质量,您应该将图像放入 mipmap 文件夹。 Android 会做的是,它会尝试从更高密度的桶中获取图像,而不是按比例放大。这将提高图像的清晰度(质量)。

因此,决定将图像放入何处的经验法则是:

启动器图标总是进入 mipmap 文件夹。 通常放大(或极度缩小)且其质量对应用至关重要的图像也会放入 mipmap 文件夹。 所有其他图像都是通常的drawables

【讨论】:

那么操作栏的图标或浮动按钮的图标进入mipmap? 不,它们是通常的可绘制对象。 您好,那么对于第二点,如果android会切换到更高的分辨率而不是增加启动器图标的大小,我们如何增加启动器的大小?谢谢。【参考方案4】:

Android 4.3 中的 mipmap 实现正是 1983 年在 Wikipedia 文章中解释的技术 :)

mipmap 集的每个位图图像都是缩小的副本 主要纹理,但细节程度有所降低。虽然 当视图足以渲染时,仍会使用主纹理 完整的细节,渲染器将切换到合适的 mipmap 图像 (...) 当从远处或以小尺寸查看纹理时。

虽然这被描述为一种用于 3D 图形的技术(因为它提到“从远处观看”),但它同样适用于 2D(翻译为“绘制是一个较小的空间”,即“缩小”)。

对于一个具体的 Android 示例,假设您有一个具有特定背景可绘制对象的视图(特别是 BitmapDrawable)。您现在使用动画将其缩放为原始大小的 0.15。通常,这需要缩小每一帧的背景位图。然而,这种“极端”缩小可能会产生视觉伪影。

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

这有点理论,因为它实际上是由渲染器完成的。根据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,&c)。

【讨论】:

这并不能真正解释与同样包含 mipmap 图像的 drawable 文件夹的区别。 事实上,这个答案是完全错误的。 唯一的 区别在于文件是否被剥离 - 它与是否使用 mipmapping 无关(在这两种情况下都是如此)。该文件夹的名称有点糟糕;他们可能应该称它为drawable-nostrip 或其他名称。 对 mipmap 的解释很好,但 Kazuaki 引用 Google 文档条目的答案似乎暗示这实际上不是原因。【参考方案5】:

我在另一个线程中提到的一件事值得指出——如果您正在为不同的密度构建不同版本的应用程序,您应该了解“mipmap”资源目录。这与“可绘制”资源完全相同,只是它在创建不同的 apk 目标时不参与密度剥离。

https://plus.google.com/105051985738280261832/posts/QTA9McYan1L

【讨论】:

...确实如此,正如凯文在接受的答案中提到的那样。这似乎是其背后的主要原因。 @RichardLeMesurier 是的,只是为了简单明了【参考方案6】:

因为我一直在寻找一个明确的答案来确定通知图标的正确类型,所以我想在主题中添加这个明确的声明。来自http://developer.android.com/tools/help/image-asset-studio.html#saving

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

【讨论】:

【参考方案7】:

在 Android 中处理图像时,您需要处理两种情况:

    您想要为您的设备密度加载图像,并且您将“按原样”使用它,而不更改其实际大小。在这种情况下,您 应该与drawables一起使用,Android会给你最合适的 图片。 您想要为您的设备密度加载图像,但该图像将被放大或缩小。例如,当您 想要显示一个更大的启动器图标,或者你有一个动画,它 增加图像的大小。在这种情况下,为确保最佳图像质量, 您应该将图像放入 mipmap 文件夹。 Android会做的是, 它将尝试从更高密度的桶中拾取图像 扩大规模。

所以

因此,决定将图像放入何处的经验法则是 是:

    启动器图标总是进入 mipmap 文件夹。

    通常放大(或极度缩小)并且其质量对应用程序至关重要的图像进入 mipmap 文件夹,如下所示 好吧。

    所有其他图像都是通常的可绘制对象。

来自this 文章的引用。

【讨论】:

【参考方案8】:

为不同密度构建单独的 apk 时,其他密度的可绘制文件夹会被剥离。这将使图标在使用更高密度的启动器图标的设备中显得模糊。 由于 mipmap 文件夹不会被剥离,因此最好使用它们来包含启动器图标。

【讨论】:

【参考方案9】:

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

【讨论】:

【参考方案10】:
res/
mipmap-mdpi/ic_launcher.png (48x48 pixels)
mipmap-hdpi/ic_launcher.png (72x72)
mipmap-xhdpi/ic_launcher.png (96x96)
mipmap-xxhdpi/ic_launcher.png (144x144)
mipmap-xxxhdpi/ic_launcher.png (192x192)

启动器应用图标的 MipMap

http://android-developers.blogspot.co.uk/2014/10/getting-your-apps-ready-for-nexus-6-and.html

https://androidbycode.wordpress.com/2015/02/14/goodbye-launcher-drawables-hello-mipmaps/

【讨论】:

感谢第二篇博文!它很好地阐明了drawable-XXXmipmap-XXX 文件夹的用法之间的区别: 启动器图标与其他资源不同,因为用户启动器中可能会显示更高分辨率的图标。如果该更高分辨率的图像已从您的 drawables 文件夹中删除,则较低密度的图标将以编程方式被放大。这可能会导致不美观的模糊图标。 至少在 Android 8.1 的 Nexus P6 上,drawables 文件夹中的启动图标没有放大。实际上根本找不到,应用程序在打开时崩溃。【参考方案11】:

如果您为 HDPI 等目标屏幕分辨率构建 APK,Android 资产打包工具 AAPT 可以剥离您不需要的其他分辨率的可绘制对象。但如果它在 mipmap 文件夹中,那么这些资产将无论目标分辨率如何,都留在 APK 中。

【讨论】:

【参考方案12】:

我对mipmap的理解大致是这样的:

当需要绘制图像时,鉴于我们有不同的屏幕尺寸和分辨率,必须进行一些缩放。

如果您的图像适合低端手机,当您将其缩放到 10 英寸平板电脑的大小时,您必须“发明”实际不存在的像素。这是通过一些插值完成的算法。必须发明的像素数量越多,处理时间越长,质量开始下降。使用更复杂的算法获得最佳质量,需要更长时间(例如,周围像素的平均值与复制最近的像素)。

为了减少必须发明的像素数量,您可以使用 mipmap 为同一图像提供不同的尺寸/分辨率,系统将选择最接近必须渲染的分辨率的图像并从那里进行缩放.这应该会减少发明像素的数量,从而节省用于计算这些像素以提供高质量图像的资源。

我在一篇文章中读到了这一点,该文章解释了缩放图像时 libgdx 中的性能问题:

http://www.badlogicgames.com/wordpress/?p=1403

【讨论】:

以上是关于用于图标的 Mipmap 可绘制对象的主要内容,如果未能解决你的问题,请参考以下文章

Android mipmap 图标作为状态(通知)栏图标

Android的drawable,mipmap的图标大小

Android 项目中软件图标适配和mipmap文件夹的规则

通知中未显示图标:改为显示白色方块并使用 mipmap 启动器显示它

flutter 打包图标尺寸

android studio selector 怎么引用mipmap