9

NinePatchDrawableのサポートが必要です:

私のアプリはネットワークからテーマをダウンロードできます。9パッチPNGを除いて、ほとんどすべてが正常に機能します。

final Bitmap bubble = getFromTheme("bubble");
if (bubble == null) return null;

final byte[] chunk = bubble.getNinePatchChunk();
if (!NinePatch.isNinePatchChunk(chunk)) return null;

NinePatchDrawable d = new NinePatchDrawable(getResources(), bubble, chunk, new Rect(), null);
v.setBackgroundDrawable(d);

d = null;
System.gc();

getFromTheme()は、SDカードからビットマップをロードします。9パッチPNGはすでにコンパイルされています。つまり、必要なチャンクが含まれています。

ビットマップをNinePatchDrawableオブジェクトに変換する方法は機能しているようです。これは、画像を描画したときと同じようにストレッチできるためです。

動作しないのはパディングだけです。私はすでにパディングを次のようなビューに設定しようとしました:

final Rect rect = new Rect();   // or just use the new Rect() set
d.getPadding(rect);             // in the constructor
v.setPadding(rect.left, rect.top, rect.right, rect.bottom);

d.getPadding(rect)は、チャンクから取得したパディングで変数rectを埋める必要がありますね。しかし、そうではありません。

結果:TextView(v)は、9パッチ画像のコンテンツ領域にテキストを表示しません。パディングは、各座標で0に設定されます。

読んでくれてありがとう。

4

4 に答える 4

17

最後に、私はそれをしました。Androidはチャンクデータを正しく解釈していませんでした。バグがあるかもしれません。したがって、パディングデータを取得するには、チャンクを自分で逆シリアル化する必要があります。

どうぞ:

package com.dragonwork.example;

import android.graphics.Rect;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;

class NinePatchChunk {

    public static final int NO_COLOR = 0x00000001;
    public static final int TRANSPARENT_COLOR = 0x00000000;

    public final Rect mPaddings = new Rect();

    public int mDivX[];
    public int mDivY[];
    public int mColor[];

    private static void readIntArray(final int[] data, final ByteBuffer buffer) {
        for (int i = 0, n = data.length; i < n; ++i)
            data[i] = buffer.getInt();
    }

    private static void checkDivCount(final int length) {
        if (length == 0 || (length & 0x01) != 0)
            throw new RuntimeException("invalid nine-patch: " + length);
    }

    public static NinePatchChunk deserialize(final byte[] data) {
        final ByteBuffer byteBuffer =
            ByteBuffer.wrap(data).order(ByteOrder.nativeOrder());

        if (byteBuffer.get() == 0) return null; // is not serialized

        final NinePatchChunk chunk = new NinePatchChunk();
        chunk.mDivX = new int[byteBuffer.get()];
        chunk.mDivY = new int[byteBuffer.get()];
        chunk.mColor = new int[byteBuffer.get()];

        checkDivCount(chunk.mDivX.length);
        checkDivCount(chunk.mDivY.length);

        // skip 8 bytes
        byteBuffer.getInt();
        byteBuffer.getInt();

        chunk.mPaddings.left = byteBuffer.getInt();
        chunk.mPaddings.right = byteBuffer.getInt();
        chunk.mPaddings.top = byteBuffer.getInt();
        chunk.mPaddings.bottom = byteBuffer.getInt();

        // skip 4 bytes
        byteBuffer.getInt();

        readIntArray(chunk.mDivX, byteBuffer);
        readIntArray(chunk.mDivY, byteBuffer);
        readIntArray(chunk.mColor, byteBuffer);

        return chunk;
    }
}

上記のクラスを次のように使用します。

final byte[] chunk = bitmap.getNinePatchChunk();
if (NinePatch.isNinePatchChunk(chunk)) {
    textView.setBackgroundDrawable(new NinePatchDrawable(getResources(),
          bitmap, chunk, NinePatchChunk.deserialize(chunk).mPaddings, null));
}

そしてそれは完璧に動作します!

于 2012-06-18T16:23:10.313 に答える
4

実際にはそれよりも少し複雑ですが、要約すると非常に単純です。

パディングrectは。によって返されBitmapFactory.decodeStream(InputStream, Rect, Options)ます。decodeByteArray()パディングrectを返すことができるバージョンはありません。

9パッチAPI全体は少しばかげています:

  • decodeByteArray()を呼び出しますnativeDecodeByteArray()。これはおそらくより効率的ですnativeDecodeStream()ByteArrayInputStream、明らかに開発者は、メモリから9パッチをデコードすることを期待していませんでした。
  • パディングrectは9つのパッチでのみNinePatch使用されるため、の代わりにその一部である方が理にかなっていますBitmapFactory。残念ながら、NinePatch.javaこれはビットマップと9パッチチャンクを描画メソッドに渡すラッパーにすぎません(そして、の呼び出しのため、ほとんどのNinePatch.draw()呼び出しはスレッドセーフではありませんmRect.set(location))。
  • NinePatchDrawableNinePatchは、とパディングrectを取得する方法を提供していません。これによりNinePatch、アプリケーションコードでは多少役に立たなくなります(自分でパディングを実行したい場合を除く)。NinePatchDrawable.getNinePatch()またははありませんNinePatch.getBitmap()

このコメントはそれをかなりうまくまとめています:

うーん。契約では、decodeStreamパッドrectはすでに割り当てられていますが、ビットマップに9パッチチャンクがない場合、パッドは無視されます。これを変更して、rectを遅延割り当て/割り当てることができれば、新しい Rectsを作成して床にドロップするだけのGCチャーンを回避できます。

私の修正はかなり簡単です:

public final class NinePatchWrapper {
  private final Bitmap mBitmap;
  private final Rect mPadding;
  /**
  * The caller must ensure that that bitmap and padding are not modified after
  * this method returns. We could copy them, but Bitmap.createBitmap(Bitmap)
  * does not copy the nine-patch chunk on some Android versions.
  */
  public NinePatchWrapper(Bitmap bitmap, Rect padding) {
    mBitmap = bitmap;
    mPadding = padding;
  }
  public NinePatchDrawable newDrawable(Resources resources) {
    return new NinePatchDrawable(mBitmap, mBitmap.getNinePatchChunk(), mPadding, null);
  }
}

...

public NinePatchWrapper decodeNinePatch(byte[] byteArray, int density) {
  Rect padding = new Rect();
  ByteArrayInputStream stream = new ByteArrayInputStream(byteArray);
  Bitmap bitmap = BitmapFactory.decodeStream(stream, padding, null);
  bitmap.setDensity(density);
  return new NinePatchWrapper(bitmap, padding);
}

大幅に簡略化されているため、テストされていません。特に、9パッチチャンクが有効であることを確認することをお勧めします。

于 2013-04-05T18:24:24.260 に答える
1

Paddingこのように9パッチの一部として含まれていない例を見たことがありません。

ここに画像の説明を入力してください

これを行うには、最初にNinePatchを作成してから、そこからDrawableを作成する必要があります。

NinePatch ninePatch = new NinePatch(bitmap, chunk, srcName);
NinePatchDrawable d = new NinePatchDrawable(res, ninePatch);

ただし、空の長方形を使用してDrawableを作成しているようです。

NinePatchDrawable d = new NinePatchDrawable(getResources(), bubble, chunk, new Rect(), null);

プログラムでパディングを指定する場合は、次のことを試してください。

Rect paddingRectangle = new Rect(left, top, right, bottom);
NinePatchDrawable d = new NinePatchDrawable(getResources(), bubble, chunk, paddingRectangle, null);
于 2012-06-18T14:34:04.223 に答える
1

パーティーに少し遅れましたが、これが私がそれを解決した方法です:

私は提供するデコーダーメソッドを使用しNinePatchDrawableます、それはパディングを正しく読み取ります:

     var myDrawable = NinePatchDrawable.createFromStream(sr, null);
于 2015-10-22T14:21:57.153 に答える