2012-06-16 10 views
9

Necesito ayuda con NinePatchDrawable:NinePatchDrawable no recibe el relleno del trozo

Mi aplicación se puede descargar temas desde la red. Casi todas las cosas funcionan bien, excepto 9 PNG de parche.

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() carga el mapa de bits de la tarjeta SD. Los PNG de 9 parches ya están compilados, eso significa que incluyen el fragmento requerido.

La forma en que convierto el mapa de bits en un objeto NinePatchDrawable parece estar funcionando, porque la imagen es estirable y también la dibujé.

Lo único que no funciona es el relleno. Ya intentado fijar el relleno a la vista como esta:

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) debe llenar el rect variable con el acolchado consiguió del trozo, no? Pero no es así

Resultado: The TextView (v) no muestra el texto en el área de contenido de la imagen de 9 parches. Los rellenos se establecen en 0 en cada coordenada.

Gracias por leer.

Respuesta

16

Por último, lo hice. Android no estaba interpretando los datos del fragmento correctamente. Puede haber un error. Entonces usted debe deserializar el fragmento para obtener los datos de relleno.

Aquí vamos:

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; 
    } 
} 

Uso de la clase por encima de la siguiente manera:

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

y funcionará perfectamente!

+1

Resuelva un problema en b.android.com, también mencione el dispositivo utilizado y la versión de Android. – Reno

+0

Gracias. Lo acabo de hacer. – DragonWork

+0

¡Guau, muchas gracias! Funcionó perfectamente – ABentSpoon

0

nunca he visto un ejemplo donde el Padding no está incluido como parte de la 9-parche de este modo:

enter image description here

Para hacer esto, primero debe construir un NinePatch y luego crearle 're Disponibles de ella:

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

Sin embargo, usted parece ser la construcción de su Disponibles con un rectángulo vacío:

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

Si desea especificar programáticamente el relleno intente esto:

Rect paddingRectangle = new Rect(left, top, right, bottom); 
NinePatchDrawable d = new NinePatchDrawable(getResources(), bubble, chunk, paddingRectangle, null); 
+0

Pero mi pregunta es: ¿Cómo para obtener las variables a la izquierda, arriba, derecha e inferior de la imagen misma? – DragonWork

+2

El primer ejemplo de que muestran cómo rellenar correctamente un NinePatchDrawable para incluir el relleno en el trozo. Una vez que esto ha sido construida que puede hacer getPadding (rect) – Graeme

+0

El primer ejemplo debe hacerlo. Construye el NinePatch, luego el NinePatchDrawable de ese NinePatch. 'getPadding()' debería devolver los valores correctos. – kcoppock

4

En realidad es un poco más complicado que eso, pero lo que se reduce a es bastante simple:

El rect relleno es devuelto por BitmapFactory.decodeStream(InputStream, Rect, Options). No hay una versión de decodeByteArray() que pueda devolver el relleno.

Todo el API de nueve parche es un poco tonto:

  • decodeByteArray() llamadas nativeDecodeByteArray(), que presumiblemente es más eficiente que nativeDecodeStream() en un ByteArrayInputStream, pero es evidente que los desarrolladores no se espera que desee decodificar un nueve parche de memoria.
  • El relleno rect es solo utilizado por nueve parches, por lo que tiene más sentido para que sea parte de NinePatch en lugar de BitmapFactory. Lamentablemente, NinePatch.java no es mucho más que un contenedor que pasa el mapa de bits y trozo de nueve parche para métodos de dibujo (y la mayoría de los NinePatch.draw() llamadas no están hilo-seguro debido a la llamada a mRect.set(location)).
  • NinePatchDrawable no ofrece una forma de tomar un NinePatch y un relleno, lo que hace que NinePatch sea algo inútil en el código de la aplicación (a menos que desee hacer el relleno usted mismo). No hay NinePatchDrawable.getNinePatch() o NinePatch.getBitmap().

This comment lo resume bastante bien:

uf. El contrato decodeStream es que ya hemos asignado la rect almohadilla, pero si el mapa de bits no tenía un trozo ninepatch, continuación, se ignorará la almohadilla. Si pudiéramos cambiar esto a perezosamente alloc/asignar el rect, podríamos evitar la rotación de GC de hacer nuevos Rect s sólo para dejarlos caer en el suelo.

Mi solución es bastante simple:

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); 
} 

No probado, ya que está muy simplificado. En particular, es posible que desee comprobar que el fragmento de nueve parches sea válido.

0

Un poco tarde a la fiesta, pero aquí es cómo lo resolví:

utilizo el método decodificador que NinePatchDrawable proporciona, se lee el relleno correctamente:

 var myDrawable = NinePatchDrawable.createFromStream(sr, null); 
Cuestiones relacionadas