2

I am using the below code to instantiate a 9patch image and set it as the background of a button. The following image shows the non-ideal result.

InputStream = MyClass.class.getResourceAsStream("/images/btn_default_normal.9.png");
Drawable d = NinePatchDrawable.createFromStream(in, null);
button.setBackgroundDrawable(d);

enter image description here

Tried the below code as well, which seems to result in an ANR caused by native android code. It's not really clear what happens, but the application exists without warning, the log says something about an ANR, and I see the following stacktrace quite a bit in the log.

InputStream = MyClass.class.getResourceAsStream("/images/btn_default_normal.9.png");
Bitmap bitmap = BitmapFactory.decodeStream(in);
byte[] chunk = bitmap.getNinePatchChunk();
NinePatchDrawable drawable = new NinePatchDrawable(bitmap, chunk, new Rect(), null);
button.setBackgroundDrawable(drawable);



 at android.graphics.NinePatch.validateNinePathChunk(Native Method)
at android.graphics.NinePatch.<init>
at android.graphics.drawable.NinePatchDrawable.<init>
ab11
  • 19,770
  • 42
  • 120
  • 207
  • In the second case, are you sure the decodeStream created a valid bitmap? You might like to try a canvas.drawBitmap(bitmap, 0, 0, null); to check? – Torid Feb 14 '12 at 22:16

3 Answers3

3

the createFromStream() method is part of the Drawable class (which NinePatchDrawable extends) So it is returning to you a plain Drawable object, rather than a nine patch. That is why your button turns out looking that way I suspect.

Where is the image that you are trying to make in to a nine-patch? It seems from your example that it may be included in with your application resources (perhaps in one of the drawable folders?) if this is the case is there a reason that using the ID of the drawable will not work for your situation? you should be able to do something like this:

button.setBackgroundResource(R.drawable.btn_default_normal);

If I am missing something(which I definitely could be.) and there is a reason you can't use the resource ID. From the docs it looks like your second block of code is closer to what you'll want.

But the constructor you're using is deprecated. Try using this one instead. which would look like this:

InputStream in = MyClass.class.getResourceAsStream("/images/btn_default_normal.9.png");
Bitmap bitmap = BitmapFactory.decodeStream(in);
byte[] chunk = bitmap.getNinePatchChunk();
NinePatchDrawable drawable = new NinePatchDrawable(getResources(), bitmap, chunk, new Rect(), null);
button.setBackgroundDrawable(drawable);

The only difference being the first paramter should be your Applications Resources object.

However, honestly I could've sworn I read somewhere at some point that the system was incapable of working with NinePatchDrawables dynamically as objects. Even though the NinePatchDrawable object exists, I was under the impression that it was not working / not intended to be part of the public APIs

EDIT:

Does the answer on this question help? Create a NinePatch/NinePatchDrawable in runtime

Also my answer at the bottom of that question reminds me exactly why I was under the impression that it was not working / not indeded for part of the public APIs the docs for the getNinePatchChunk say

Returns an optional array of private data, used by the UI system for some bitmaps. Not intended to be called by applications.

But it looks like they managed to get it working anyway.

Community
  • 1
  • 1
FoamyGuy
  • 46,603
  • 18
  • 125
  • 156
  • Alas I am attempting to inflate from a stream because the Applications Resources are unavailable (this takes place in a library which is distributed as a jar, etc). Any possibility of instantiating from a stream without resources? – ab11 Feb 14 '12 at 23:17
  • did switching to the constructor with the Resources parameter change anything? Also see my edit and try the solution posted in the link. – FoamyGuy Feb 15 '12 at 01:45
  • Hi, I did manage to get a reference to Resources and tried the constructor as you recommended. I get the same crash/anr. – ab11 Feb 16 '12 at 19:37
  • Did you try to solution from the answer in the other question that I linked? – FoamyGuy Feb 16 '12 at 20:26
1

I had many hours of fun with this and the 9patch PNG's produced by the draw9patch utility don't have their 9patch chunks added to them as it literally will just draw black lines on PNG's.

Anytime you call .getChunk() or whatever it is on a Bitmap or BitmapDrawable object you're just going to get null if you're trying to use 9patch PNG's that aren't part of your resources.

The 9patch chunks are added to these PNG's at compile time (usually by Eclipse) using aapt. This adds another step to me retrieving 9patch's over the network as they must first be converted using aapt.

aapt c -v -S C:\Users\Kevin\workspace\com.xyz.theme -C C:\Users\Kevin\Desktop\out

Kevin Parker
  • 16,975
  • 20
  • 76
  • 105
0

the code can help you https://gist.github.com/knight9999/86bec38071a9e0a781ee

 InputStream is = new FileInputStream(ninePath);
 Bitmap bitmap = BitmapFactory.decodeStream(is);
 NinePatchDrawable drawable = NinePatchBitmapFactory.createNinePatchDrawable(getContext().getResources(), bitmap);
 is.close();
 getWindow().setBackgroundDrawable(drawable);
Sir l33tname
  • 4,026
  • 6
  • 38
  • 49
lyy
  • 21
  • 3