在运行时创建NinePatch/NinePatchDrawable

jac*_*b11 38 networking android runtime nine-patch

我的Android应用程序要求通过从服务器端检索新的颜色和图像来定制图形上的部件.这些图像中的一些是九个补丁图像.

我找不到创建和显示这些九个补丁图像(已通过网络检索)的方法.

检索九个补丁图像并将其作为位图保存在应用程序中.要创建NinePatchDrawable,您需要相应的NinePatchNinePatch的chunk(byte[]).无法从资源中加载NinePatch,因为图像不存在/res/drawable/.此外,为了创建NinePatch,您需要NinePatch的大块.所以,这一切都深入到大块.
那么问题是,如何从现有的Bitmap(包含NinePatch信息)格式化/生成块?

我搜索了Android源代码和Web,我似乎无法找到任何这方面的例子.更糟糕的是,NinePatch资源的所有解码似乎都是本地完成的.

有没有人有这种问题的经验?

我的目标是API级别4,如果这很重要的话.

kan*_*ure 55

getNinePatchChunk工作得很好.它返回null因为你给Bitmap了一个"源"九个补丁.它需要一个"编译"的九个图像.

Android世界中有两种类型的九种文件格式("源"和"已编译").源版本是在任何地方添加1px透明边框的地方 - 当您将应用程序编译为.apk之后,aapt会将您的*.9.png文件转换为Android期望的二进制格式.这是png文件获取其"块"元数据的地方.(了解更多)

好的,现在开始营业了(你正在听DJ kanzure).

  1. 客户端代码,如下所示:

    InputStream stream = .. //whatever
    Bitmap bitmap = BitmapFactory.decodeStream(stream);
    byte[] chunk = bitmap.getNinePatchChunk();
    boolean result = NinePatch.isNinePatchChunk(chunk);
    NinePatchDrawable patchy = new NinePatchDrawable(bitmap, chunk, new Rect(), null);
    
    Run Code Online (Sandbox Code Playgroud)
  2. 在服务器端,您需要准备图像.您可以使用Android二进制资源编译器.这样就可以自动创建一个新的Android项目,将一些*.9.png文件编译成Android原生格式.如果你是手动做到这一点,你就基本上是做一个项目,并在一些*.9.png文件("源"文件)抛出,编译所有的东西都.apk文件格式,解压.apk文件,然后找到*. 9.png文件,这是您发送给客户的文件.

另外:我不知道是否BitmapFactory.decodeStream知道这些png文件中的npTc块,因此它可能会也可能不会正确处理图像流.存在Bitmap.getNinePatchChunk意味着可能BitmapFactory- 您可以在上游代码库中查找它.

如果它不知道npTc块并且你的图像被大大搞砸了,那么我的回答会有所改变.

您可以编写一个快速的Android应用程序来加载已编译的图像并吐出byte[]块,而不是将已编译的九个补丁图像发送到客户端.然后,将此字节数组与常规图像一起传输给客户端 - 没有透明边框,不是"源"九个图像,而不是"已编译"的九个图像.您可以直接使用块来创建对象.

另一种方法是使用对象序列化将九个图像(NinePatch)发送到您的客户端,例如使用JSON或内置序列化程序.

编辑如果你真的,真的需要构建自己的数据块的字节数组,我会通过看开始do_9patch,isNinePatchChunk,Res_png_9patchRes_png_9patch::serialize()在ResourceTypes.cpp.Dmitry Skiba还有一个自制的npTc大块阅读器.我无法发布链接,所以如果有人可以编辑我很酷的答案.

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

结构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


Bri*_*fey 23

如果你需要动态创建9Patches,请查看我的主旨:https://gist.github.com/4391807

你传递任何位图,然后给它类似于iOS的cap insets.


小智 6

无需使用Android二进制资源编译器来编写已编译的9patch png,只需在android-sdk中使用aapt即可,命令行如下:
aapt.exe c -v -S /path/to/project -C /path/to/destination


KNa*_*ito 5

我创建了一个工具来从(未编译的)NinePatch位图创建NinePatchDrawable.请参阅https://gist.github.com/knight9999/86bec38071a9e0a781ee.

该方法 NinePatchDrawable createNinePatchDrawable(Resources res, Bitmap bitmap) 可以帮助您.

例如,

    ImageView imageView = (ImageView) findViewById(R.id.imageview);
    Bitmap bitmap = loadBitmapAsset("my_nine_patch_image.9.png", this);
    NinePatchDrawable drawable = NinePatchBitmapFactory.createNinePatchDrawable(getResources(), bitmap);
    imageView.setBackground( drawable );
Run Code Online (Sandbox Code Playgroud)

哪里

public static final Bitmap loadBitmapAsset(String fileName,Context context) {
    final AssetManager assetManager = context.getAssets();
    BufferedInputStream bis = null;
    try {
        bis = new BufferedInputStream(assetManager.open(fileName));
        return BitmapFactory.decodeStream(bis);
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            bis.close();
        } catch (Exception e) {

        }
    }
    return null;
}
Run Code Online (Sandbox Code Playgroud)

在此示例中,my_nine_patch_image.9.png它位于assets目录下.


Foa*_*Guy 0

Bitmap 类提供了执行此操作的方法yourbitmap.getNinePatchChunk()。我从未使用过它,但似乎这就是您所寻找的。