2010-09-21 8 views
6

Intento implementar un efecto de desplazamiento (efecto cuando se presiona el botón) colocando un archivo PNG semi transparente sobre el fondo del botón y el ícono del botón. Desafortunadamente, el archivo de fondo del botón es un 9-PATCH-PNG que causa algunos problemas aquí: "traga" todo en la parte superior de la capa y no permite cubrir las áreas extensibles (la línea de luz fina alrededor) de los nueve parches-png . En otras palabras, las líneas negras del borde superior e izquierdo de 9 PATCH PNG causan no solo el estiramiento, sino también el comportamiento de relleno.¿Cómo cubrir un 9-PATCH-PNG por completo?

La eliminación de 9-Patch-Information no es una buena solución.

Aquí puede ver mi Botón. El fondo azul es un PATCH PNG de 9. La delgada línea de luz alrededor del botón no es deseada.

alt text

Esta capa-lista se asigna al atributo botón de "fondo":

<?xml version="1.0" encoding="utf-8"?> 
<layer-list 
    xmlns:android="http://schemas.android.com/apk/res/android"> 
    <item 
    android:drawable="@drawable/home_btn_bg_blue_without_padding" /> 
    <item> 
    <bitmap 
     android:src="@drawable/home_icon_test" 
     android:gravity="center" /> 
    </item> 
    <item 
    android:drawable="@drawable/layer_black_50" /> 
</layer-list> 

ajuste de las compensaciones de la capa a "-1" en cada frontera no es válida. ¿Ustedes sugerencias?

actualización

Probé siguientes, que estarán evite escalar, sugirió a partir here. Pero tampoco funcionó:

<!-- To avoid scaling, the following example uses a <bitmap> element with centered gravity: --> 
<item> 
    <bitmap android:src="@drawable/image" 
      android:gravity="center" /> 
</item> 

Mi versión (todavía faltan las zonas estirables de la 9-patch-png descubierto):

alt text

<?xml version="1.0" encoding="utf-8"?> 
<layer-list 
    xmlns:android="http://schemas.android.com/apk/res/android"> 
    <item 
    android:drawable="@drawable/home_btn_bg_blue_hover_without_padding" /> 
    <item> 
    <bitmap 
     android:src="@drawable/home_icon_test" 
     android:gravity="center" /> 
    </item> 
    <item> 
    <bitmap android:src="@drawable/layer_black_100" 
      android:height="100dp" 
      android:width="100dp"/></item> 
</layer-list> 

Actualización 2

¿Podría funcionar para mí? Making Overlaid image transparent on touch in Android?

+0

Déjame hacerlo bien. La primera imagen es el efecto deseado ¿no? –

+0

@Octavian: No, colocar "@ drawable/layer_black ..." en la parte superior es el efecto deseado – OneWorld

+0

El texto que agregó en la parte superior sobre su "Actualización 2" se muestra como la vista previa de la pregunta en la lista de preguntas , por lo que es menos probable que alguien tenga una idea aproximada de lo que está preguntando mientras navega por la lista de preguntas de Android, y, supongo, es menos probable que quiera hacer clic y responder. – MatrixFrog

Respuesta

4

[NeverMind] Los comentarios internos para LayerDrawable.getPadding afirman que se necesita el relleno del primer dibujo de la lista. Si este comentario dice la verdad, puede obtener el comportamiento que desea colocando una imagen arbitraria (quizás vacía) antes de su parche 9 en la lista.

Una lectura rápida del código, sin embargo, implica que realmente utiliza el suma de todos los rellenos de la partida, lo que significa que no hay manera de eliminar su problema usando el valor por defecto LayerDrawable. La declaración implica la solución: implementar una subclase de LayerDrawable que anula "getPadding" para devolver {0, 0, 0, 0}. Puede que tenga que inicializar su subclase en código en lugar de cargar un diseño XML, pero esto no es particularmente difícil. [/ NEVERMIND]

Actualización: La solución anterior no funciona, porque el problema no es el relleno en sí, es el hecho de que la aplicación por defecto establece los límites de cada imagen sea la suma de los rellenos de las imágenes precedentes. En otras palabras, impone el anidamiento, que es lo que la mayoría de la gente querrá. La solución adecuada sigue siendo anular LayerDrawable, pero reemplaza "onBoundsChange" en su lugar. A, de demostración completa probado sigue:

package com.beekeeper.ninepatchcover; 

import android.app.Activity; 
import android.graphics.*; 
import android.graphics.drawable.*; 
import android.os.Bundle; 
import android.view.Gravity; 
import android.widget.ImageButton; 

public class NinePatchCover extends Activity { 
    private Drawable mCover0; 
    private Drawable mCover1; 

    /** Called when the activity is first created. */ 
    @Override public void onCreate(final Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 
    final Drawable button = 
     getResources().getDrawable(android.R.drawable.btn_default); 
    final Bitmap iconBitmap = 
     BitmapFactory.decodeResource(getResources(), 
            android.R.drawable.ic_menu_mylocation); 
    final BitmapDrawable icon = new BitmapDrawable(iconBitmap); 
    icon.setGravity(Gravity.CENTER); 
    mCover0 = 
     getResources().getDrawable(android.R.drawable.title_bar); 
    mCover1 = 
     getResources().getDrawable(android.R.drawable.title_bar); 

    final LayerDrawable unsolved = 
     new LayerDrawable(new Drawable[]{button, icon, mCover0}); 
    final LayerDrawable solved = 
     new MyLayerDrawable(new Drawable[]{button, icon, mCover1,}, mCover1); 

    ((ImageButton)findViewById(R.id.uncovered)).setBackgroundDrawable(unsolved); 
    ((ImageButton)findViewById(R.id.covered)).setBackgroundDrawable(solved); 
    } 

    class MyLayerDrawable extends LayerDrawable { 
    Drawable mCover; 

    public MyLayerDrawable(final Drawable[] layers, final Drawable cover) { 
     super(layers); 
     mCover = cover; 
    } 

    @Override protected void onBoundsChange(final Rect bounds) { 
     super.onBoundsChange(bounds); 
     mCover.setBounds(bounds); 
    } 
    } 
} 

utilizando la siguiente distribución/main.xml

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:orientation="vertical" android:layout_width="fill_parent" 
android:layout_height="fill_parent" 
> 
<ImageButton android:id="@+id/uncovered" 
    android:layout_width="fill_parent" android:layout_height="wrap_content" /> 
<ImageButton android:id="@+id/covered" 
    android:layout_width="fill_parent" android:layout_height="wrap_content" /> 
</LinearLayout> 

Una captura de pantalla de ejemplo siguiente:

NinePatchCover screen shot

Actualización 2:

Según lo solicitado, así es cómo puede modificarlo para inicializar un Selecto r dentro del código.Sustituir la inicialización de "mCover1" con el siguiente código:

final StateListDrawable sld = new StateListDrawable(); 
sld.addState(new int[]{android.R.attr.state_pressed}, 
       new ColorDrawable(0xffff0000)); 
sld.addState(new int[]{android.R.attr.state_window_focused}, 
       new ColorDrawable(0xff00ff00)); 
sld.addState(new int[]{}, 
       getResources().getDrawable(android.R.drawable.title_bar)); 
mCover1 = sld; 

Esto mostrará verde en el caso normal en el que se centra la ventana, pero el botón no está presionado, rojo cuando se pulsa el botón, y el valor predeterminado dibujable (gris) cuando la ventana no está enfocada. (Intente arrastrar hacia abajo la barra de notificaciones de "ventana" para ver la ventana en su estado desenfocado.)

+0

Oh ok, suena interesante. ¿Podría proporcionar el código de un ejemplo? (vale 100 puntos) – OneWorld

+0

Listo. Probado, fallido, refinado y probado – beekeeper

+0

Entonces, el código que se proporciona ahora está destinado a funcionar? Im gon intentarlo mañana. – OneWorld

2

lo tengo funcionando muy bien:

res/layout/Main.xml

... 
<ImageButton 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:src="@drawable/button" 
    /> 
... 

res/estirable/button.xml

<layer-list 
    xmlns:android="http://schemas.android.com/apk/res/android"> 
    <item android:drawable="@drawable/frame" /> 
    <item> 
     <bitmap 
      android:src="@drawable/tomato" 
      android:gravity="center" 
      /> 
    </item> 
</layer-list> 

frame.9.png es mi parche de nueve parches. El tomate es un png básico con transparencia a su alrededor.

Este es el resultado: alt text

Extracción de la parte transparente alrededor del tomate (llenando de rosa): alt text

Editar 2: Esto hará que la cubierta de tomate completamente el patch-9-png :

<layer-list 
    xmlns:android="http://schemas.android.com/apk/res/android"> 
    <item> 
    <bitmap 
     android:src="@drawable/frame" 
     /> 
    </item> 
    <item> 
    <bitmap 
     android:src="@drawable/tomato" 
     /> 
    </item> 
</layer-list> 

Otra forma, con el uso de un ImageButton es que se puede usar el parche-9-PNG como fondo y el "contenido" como el src del botón.En ese caso, debe configurar el relleno en 0 para esa tecnología

+0

Does su Tomato-imagen cubre el nueve parche por completo? ¿Podría usar una imagen no transparente? – OneWorld

+0

Está en la parte superior del parche de nueve ... el parche de nueve es el rectángulo negro que lo rodea. No escalé/moví el tomate, simplemente se colocó encima ... – Matthieu

+0

Ok. Quiero saber cómo cubrir este parche de nueve, por lo que ya no es visible el rectángulo negro. – OneWorld

1

Creo que hay dos soluciones para este problema.

Solución 1:

Cuando dice "flotar efecto", ¿quiere decir mientras que el botón está siendo presionado hacia abajo? Si ese es el caso, entonces lo que quiere hacer uso usar un selector a.k.a. state list para el fondo de botón, donde el estado seleccionado es diferente de su imagen normal:

<?xml version="1.0" encoding="utf-8"?> 
<selector xmlns:android="http://schemas.android.com/apk/res/android"> 
    <item android:state_pressed="true" 
      android:drawable="@android:color/black" /> <!-- pressed --> 
    <item android:drawable="@drawable/home_btn_bg_blue_hover_without_padding" /> <!-- default --> 
</selector> 

A continuación, establezca el fondo de botón a la lista del estado XML estirable.

Solución 2:

Si bien no se ha publicado su prima de nueve remiendos PNG, sospecho que puede eliminar los derecho e inferior de las marcas que denotan la "caja de relleno", manteniendo las marcas izquierda y superior , que denota el "área estirable" como se documentó en el 2D Graphics Doc. Esto retendrá el comportamiento de estiramiento actual de la imagen, pero eliminará cualquier relleno que sea intrínseco a la imagen. A continuación, puede agregar o eliminar el relleno según lo desee a las vistas interiores para obtener la visualización deseada.

+0

@ Solution1: No es el caso. Ya uso un selector en combinación con una lista de capas, que es similar a la lista de estados. @ Solution2: Ok, no proporcioné el PATCH PNG crudo 9, pero puedo describir los bordes con bastante facilidad: LADO IZQUIERDO: el primer y último píxel vacío, el resto tiene la línea negra. SUPERIOR: primer y último píxel vacío, el resto la línea negra. LADO DERECHO y LADO INFERIOR: todo vacío.Los lados izquierdo y superior TAMBIÉN causan un comportamiento de relleno y eso es todo el problema de todo! No puedo desactivar el comportamiento de relleno y mantener el comportamiento de estiramiento al mismo tiempo! – OneWorld

2

Tengo una superposición completa para trabajar manipulando el parche de nueve. En lugar de dejar los lados inferior y derecho (contenido) vacíos, intente rellenarlos completamente con píxeles negros.

Cuestiones relacionadas