2012-06-18 6 views
8

Creé un ImageButton con un selector para estados presionados y no comprimidos, y esto funciona bien.Creación de ImageButton de forma irregular con diferentes estados de clic

Pero el botón tiene una forma irregular y solo quiero que se pueda hacer clic donde la imagen rectangular subyacente no sea transparente.

Así que implementé un OnTouchListener que verifica las coordenadas del evento táctil con respecto a los valores de píxel del mapa de bits (como se describe en la primera respuesta aquí: link). Esto funciona, en términos de la lógica que decide si se presionó el botón, pero ahora la imagen del botón ya no cambia a la imagen presionada.

Aquí es lo que tengo:

selector de archivos xml:

<?xml version="1.0" encoding="utf-8"?> 
<selector xmlns:android="http://schemas.android.com/apk/res/android" > 
    <item android:state_pressed="true" android:drawable="@drawable/button_start_call_pressed" /> 
    <item android:drawable="@drawable/button_start_call_normal" /> 
</selector> 

ImageButton parcialmente transparente en el diseño:

<ImageButton 
    android:id="@+id/dashboardStartCallButton" 
    android:background="@null" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:src="@drawable/start_call_button_selector" 
    /> 

En la Actividad:

public void onCreate(Bundle savedInstance) { 
    super.onCreate(savedInstance); 
    ... 
    ImageButton startCallButton = (ImageButton) this.findViewById(R.id.dashboardStartCallButton); 
    startCallButton.setOnTouchListener(new OnTouchListener() { 
     @Override 
     public boolean onTouch(View v, MotionEvent event) { 
      return OnStartCallButtonTouch(v,event); 
     }   
    }); 
} 


public boolean OnStartCallButtonTouch(View v, MotionEvent event) 
{ 
    Bitmap TheBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.button_start_call_normal); 
    int eventPadTouch = event.getAction(); 
    int iX = (int) event.getX(); 
    int iY = (int) event.getY(); 
    switch (eventPadTouch) { 
     case MotionEvent.ACTION_DOWN: 
      if (iX>=0 & iY>=0 & iX<TheBitmap.getWidth() & iY<TheBitmap.getHeight()) {     
       if (TheBitmap.getPixel(iX,iY)!=0) { 
        onStartCallButtonClicked(v); 
        return false; 
       } 
      } 
    }   
    return true; 
} 
+0

¿por qué no 'return OnStartCallButtonTouch (v, event) || startCallButton.onTouch() '? –

Respuesta

10

creo que usted En realidad estás buscando este:

View.dispatchTouchEvent(...)

Necesita anular este método en el botón personalizado para devolver falsa si el punto no está en el área deseada. Le sugiero que vaya en ello como esto:

public static class MyButton extends ImageButton { 
    ... 
    @Override 
    public boolean dispatchTouchEvent(MotionEvent event) { 
     int iX = (int) event.getX(); 
     int iY = (int) event.getY(); 
     // TODO Or use a more sophisticated, pixel value-based condition 
     if (!(iX>=0 & iY>=0 & iX<TheBitmap.getWidth() & iY<TheBitmap.getHeight())) { 
      return false; 
     } 
     return super.dispatchTouchEvent(event) 
    } 
} 

Por qué no usar OnTouchListener: Debido a que es necesario llamar a través de View.onTouchEvent() (que se realiza en super.dispatchTouchEvent (evento)) para que Vista manejar estados dibujable (se hace en onTouchEvent() utilizando el método View.refreshDrawableState(), y también hay algo de lógica más bien compleja allí)

por qué no anular onTouchEvent(): Porque en View.dispatchTouchEvent() no es una condición de que si hay un OnTouchListener, entonces deje que el oyente maneje todo y devuelva verdadero. Por lo tanto, si más tarde configura un OnTouchListener para el botón por alguna razón, su condición basada en coordenadas en el EventoTouch() no se verificará, porque onTouchEvent() nunca se llamará. Al reemplazar dispatchTouchEvent() filtra los toques en la parte superior y deja la otra lógica en su lugar: puede agregar cualquier oyente al botón y funcionará como lo haría con el botón normal, pero solo cuando su condición sea verdadera.

+0

Oye, ¿cómo te va? Si la respuesta lo hizo por usted, por favor, considere aceptarlo. –

1

Creo que necesita modificar su detección de colisión para saber si el tacto está dentro de su botón o no. Use el siguiente enfoque.

public boolean OnStartCallButtonTouch(View v, MotionEvent event) 
{ 
    Bitmap TheBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.button_start_call_normal); 
    int eventPadTouch = event.getAction(); 
    int iX = (int) event.getX(); 
    int iY = (int) event.getY(); 

    int[] location = new int[2]; 
    v.getLocationOnScreen(location); 

    int viewX = location[0]; 
    int viewY = location[1]; 


    switch (eventPadTouch) { 
     case MotionEvent.ACTION_DOWN: 
      if (iX>=viewX & iY>=viewY & iX<=(viewX+TheBitmap.getWidth()) & iY<=(viewY+TheBitmap.getHeight())) {     
       if (TheBitmap.getPixel(iX,iY)!=0) { 
        onStartCallButtonClicked(v); 
        showPressedState(); 
        return false; 
       } 
      } 
      break; 
     case MotionEvent.ACTION_UP: 
     case MotionEvent.ACTION_CANCEL: 
      showNormalState(); 
      break; 
    }   
    return true; 
} 

private void showNormalState() { 
    // set your button background drawable to show normal state 
} 

private void showPressedState() { 
    // set your button background drawable to show pressed state 
} 
Cuestiones relacionadas