在运行时创建 NinePatch/NinePatchDrawable
我对我的 Android 应用程序有一个要求,即通过从服务器端检索新的颜色和图像,图形上的部分应该是可定制的。其中一些图像是九块图像。
我找不到创建和显示这些九个补丁图像(已通过网络检索)的方法。
九个补丁图像被检索并作为位图保存在应用程序中。为了创建 NinePatchDrawable,您需要相应的 < a href="http://developer.android.com/reference/android/graphics/NinePatch.html" rel="noreferrer">NinePatch 或块 (byte[]
)九补丁。 NinePatch 无法从资源加载,因为 /res/drawable/
中不存在图像。此外,为了创建 NinePatch,您需要 NinePatch 的块。因此,一切都深入到该块。
那么问题是,如何从现有位图(包含 NinePatch 信息)格式化/生成块?
我搜索了 Android 源代码和网络,但似乎找不到任何这样的示例。更糟糕的是,NinePatch 资源的所有解码似乎都是本地完成的。
有没有人有过此类问题的经验?
我的目标是 API 级别 4(如果这很重要的话)。
I have a requirement on my Android application that parts on the graphics should be customizable, by retrieving new colors and images from the server side. Some of these images are nine-patch images.
I can't find a way to create and display these nine-patch images (that have been retrieved over the network).
The nine-patch images are retrieved and kept in the application as Bitmaps. In order to create a NinePatchDrawable, you either need the corresponding NinePatch or the chunk (byte[]
) of the NinePatch. The NinePatch can NOT be loaded from the Resources, since the images doesn't exist in /res/drawable/
. Furthermore, in order to create the NinePatch, you need the chunk of the NinePatch. So, it all drills down to the chunk.
The question is then, how do one format/generate the chunk from an existing Bitmap (containing the NinePatch information)?
I've searched through the Android source code and the Web and I can't seem to find any examples of this. To make things worse, all decoding of a NinePatch resources seem to be done natively.
Have anyone had any experiences with this kind of issue?
I'm targeting API level 4, if that is of importance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
getNinePatchChunk
工作得很好。它返回 null,因为您为Bitmap
提供了“源”ninepatch。它需要一个“编译的”ninepatch 图像。Android 世界中有两种类型的 ninepatch 文件格式(“源”和“编译”)。源版本是在各处添加 1px 透明边框的地方 - 当您稍后将应用程序编译为 .apk 时,aapt 会将您的 *.9.png 文件转换为 Android 期望的二进制格式。这是 png 文件获取其“块”元数据的地方。 (了解更多)
好的,现在开始说正事。
客户端代码,如下所示:
服务器端,您需要准备图像。您可以使用 Android 二进制资源编译器。这可以自动消除创建新 Android 项目的一些痛苦,只是将一些 *.9.png 文件编译为 Android 本机格式。如果您要手动执行此操作,您实际上需要创建一个项目并放入一些 *.9.png 文件(“源”文件),将所有内容编译为 .apk 格式,解压缩 .apk 文件,然后找到 *.9.png 文件。 9.png 文件,这就是您发送给客户的文件。
另外:我不知道 BitmapFactory.decodeStream 是否知道这些 png 文件中的 npTc 块,因此它可能会或可能不会正确处理图像流。
Bitmap.getNinePatchChunk
的存在表明BitmapFactory
可能——您可以在上游代码库中查找它。如果它不知道 npTc 块并且您的图像被严重搞砸,那么我的答案会稍微改变。
您无需将编译后的 ninepatch 图像发送到客户端,而是编写一个快速 Android 应用程序来加载编译后的图像并吐出
byte[]
块。然后,您将此字节数组与常规图像一起传输到客户端 - 没有透明边框,不是“源”ninepatch 图像,也不是“编译的”ninepatch 图像。您可以直接使用块来创建对象。另一种替代方法是使用对象序列化将 ninepatch 图像 (
NinePatch
) 发送到客户端,例如使用 JSON 或内置序列化程序。编辑如果您真的非常需要构建自己的块字节数组,我会首先查看
do_9patch
、isNinePatchChunk
、Res_png_9patch ResourceTypes.cpp 中的
和Res_png_9patch::serialize()
。还有 Dmitry Skiba 自制的 npTc 块读取器。我无法发布链接,所以如果有人可以编辑我的答案那就太好了。do_9补丁:
https://android.googlesource.com/ platform/frameworks/base/+/gingerbread/tools/aapt/Images.cpp
isNinePatchChunk:http://netmite.com/android/mydroid/1.6/frameworks/base/core/jni/android/graphics/NinePatch.cpp
struct Res_png_9patch : https ://scm.sipfoundry.org/rep/sipX/main/sipXmediaLib/contrib/android/android_2_0_headers/frameworks/base/include/utils/ResourceTypes.h
Dmitry Skiba 东西:http://code.google.com/p/android4me/source/browse/ src/android/graphics/Bitmap.java
getNinePatchChunk
works just fine. It returned null because you were givingBitmap
a "source" ninepatch. It needs a "compiled" ninepatch image.There are two types of ninepatch file formats in the Android world ("source" and "compiled"). The source version is where you add the 1px transparency border everywhere-- when you compile your app into a .apk later, aapt will convert your *.9.png files to the binary format that Android expects. This is where the png file gets its "chunk" metadata. (read more)
Okay, now down to business.
Client code, something like this:
Server-side, you need to prepare your images. You can use the Android Binary Resource Compiler. This automates some of the pain away from creating a new Android project just to compile some *.9.png files into the Android native format. If you were to do this manually, you would essentially make a project and throw in some *.9.png files ("source" files), compile everything into the .apk format, unzip the .apk file, then find the *.9.png file, and that's the one you send to your clients.
Also: I don't know if
BitmapFactory.decodeStream
knows about the npTc chunk in these png files, so it may or may not be treating the image stream correctly. The existence ofBitmap.getNinePatchChunk
suggests thatBitmapFactory
might-- you could go look it up in the upstream codebase.In the event that it does not know about the npTc chunk and your images are being screwed up significantly, then my answer changes a little.
Instead of sending the compiled ninepatch images to the client, you write a quick Android app to load compiled images and spit out the
byte[]
chunk. Then, you transmit this byte array to your clients along with a regular image-- no transparent borders, not the "source" ninepatch image, not the "compiled" ninepatch image. You can directly use the chunk to create your object.Another alternative is to use object serialization to send ninepatch images (
NinePatch
) to your clients, such as with JSON or the built-in serializer.Edit If you really, really need to construct your own chunk byte array, I would start by looking at
do_9patch
,isNinePatchChunk
,Res_png_9patch
andRes_png_9patch::serialize()
in ResourceTypes.cpp. There's also a home-made npTc chunk reader from Dmitry Skiba. I can't post links, so if someone can edit my answer that would be cool.do_9patch:
https://android.googlesource.com/platform/frameworks/base/+/gingerbread/tools/aapt/Images.cpp
isNinePatchChunk: http://netmite.com/android/mydroid/1.6/frameworks/base/core/jni/android/graphics/NinePatch.cpp
struct Res_png_9patch: https://scm.sipfoundry.org/rep/sipX/main/sipXmediaLib/contrib/android/android_2_0_headers/frameworks/base/include/utils/ResourceTypes.h
Dmitry Skiba stuff: http://code.google.com/p/android4me/source/browse/src/android/graphics/Bitmap.java
如果您需要动态创建 9Patches,请查看我制作的要点: https://gist.github.com/4391807
你可以向它传递任何位图,然后给它提供类似于 iOS 的上限插入。
If you need to create 9Patches on the fly check out this gist I made: https://gist.github.com/4391807
You pass it any bitmap and then give it cap insets similar to iOS.
我创建了一个工具来从(未编译的)NinePatch 位图创建 NinePatchDrawable。
请参阅 https://gist.github.com/knight9999/86bec38071a9e0a781ee 。
方法
NinePatchDrawable createNinePatchDrawable(Resources res, Bitmap bitmap)
对你有帮助。
例如,
在
此示例案例中,
my_nine_patch_image.9.png
位于 asset 目录下。I create a tool to create NinePatchDrawable from (uncompiled) NinePatch bitmap.
See https://gist.github.com/knight9999/86bec38071a9e0a781ee .
The method
NinePatchDrawable createNinePatchDrawable(Resources res, Bitmap bitmap)
helps you.
For example,
where
In this sample case, the
my_nine_patch_image.9.png
is under the assets directory.无需使用Android Binary Resource Compiler来准备编译好的9patch png,只需在android-sdk中使用aapt即可,命令行如下:
aapt.exe c -v -S /path/to/project -C /path/to/destination
No need to use Android Binary Resource Compiler to prepare compiled 9patch pngs, just using aapt in android-sdk is ok, the command line is like this:
aapt.exe c -v -S /path/to/project -C /path/to/destination
所以您基本上想按需创建一个
NinePatchDrawable
,不是吗?我尝试了以下代码,也许它对您有用:我认为这应该有效。您只需更改第一行即可从网络获取 InputStream。根据文档,
getNinePatchChunk()
不适合由开发人员调用,并且将来可能会中断。So you basically want to create a
NinePatchDrawable
on demand, don't you? I tried the following code, maybe it works for you:I think this should work. You just have to change the first line to get the InputStream from the web.
getNinePatchChunk()
is not intended to be called from developers according to the documentation, and might break in the future.工作和测试 - 运行时 NINEPATCH 创建
这是我对 android Ninepatch Builder 的实现,您可以通过此类和下面的代码示例通过提供任何位图在运行时创建 NinePatch
。 现在我们可以使用 ninepatch 构建器来创建 NinePatch 或 NinePatchDrawable 或创建 NinePatch Chunk。
示例:
只需将 NinePatchBuilder 类代码复制粘贴到 java 文件中,并使用示例在应用程序运行时以任何分辨率动态创建 NinePatch。
WORKING AND TESTED - RUNTIME NINEPATCH CREATION
This is my implementation of android Ninepatch Builder, you can create NinePatches on Runtime through this class and code examples below by supplying any Bitmap
Now we can use ninepatch builder to create NinePatch or NinePatchDrawable or for creating NinePatch Chunk.
Example:
Just copy paste the NinePatchBuilder class code in a java file and use the examples to create NinePatch on the fly during your app runtime, with any resolution.
Bitmap 类提供了一个方法来执行此操作
yourbitmap.getNinePatchChunk()
。我从未使用过它,但似乎这就是您所寻找的。The Bitmap class provides a method to do this
yourbitmap.getNinePatchChunk()
. I've never used it but it seems like thats what your looking for.