2012-06-05 21 views
21

Tengo una vista personalizada con 2 diseños lineat: el primero es el encabezado de la vista y el segundo es la vista de detalles.¿cómo puedo activar el evento Onclick programáticamente en android?

En la vista personalizada, la OnClickListener de la cabecera LinearLayout ya está definido: cuando se dispara, se colapsa/expandes el segundo LinearLayout.

Lo que quiero hacer es agregar más funcionalidades al evento OnClickListener de mi encabezado (es decir: contraer/expandir el segundo diseño y mostrar un Toast).

No puedo modificar el código fuente de la vista personalizada. Traté de establecer un nuevo OnClickListener pero oculta el evento inicial (colapso/expansión).

¿Cómo debo implementar esto?

El código fuente de mi vista personalizada:

public class ExpandoLayout extends ViewGroup 
{ 
    /* some declarations */ 
    private Linearlayout header; 
    private linearlayout footer; 

    /* some code */ 
    @override 
    protected void onFinishInflate() { 
    header= new LinearLayout(context); 
    header.setOnClickListener(new OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       toggleExpand(); 
      } 
     }); 
    } 
} 

lo que quiero hacer es añadir algo de código para el evento ya definido OnClickListener en mi actividad. Algo así:

public class myActivity extends Activity { 
private Linearlayout myCustomView; 
@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.rsdetail); 
    myCustomView= (MyCustomView) findViewById(R.id.expanded); 

    myCustomView.getChildAt(0).setOnClickListener(new OnClickListener() { 

     @Override 
     public void onClick(View v) { 
      if(v instanceof LinearLayout) 
      { 
       v.performClick(); 

       Toast.makeText(getActivity(), "ExpandoOnClickListener", 2000).show(); 
      } 
     } 
    }); 
} 
+1

Por favor indicar el código ....... respuesta –

+0

Ver @ de waqaslam. – Halil

Respuesta

9

Una solución sencilla sería la de obtener OnClickListener original y luego el fuego en uno nuevo:

final OnClickListener preDefinedListener = myCustomView.getChildAt(0).getOnClickListner(); 

myCustomView.getChildAt(0).setOnClickListener(new OnClickListener() { 
    @Override 
    public void onClick(View v) { 
     if(v instanceof LinearLayout) 
     { 
      preDefinedListener.onClick(v); // calls default (defined by MyCustomView) 

      Toast.makeText(getActivity(), "ExpandoOnClickListener", 2000).show(); 
     } 
    } 
}); 

Lamentablemente, View no tiene getOnClickListner(), pero supongo que puede utilizar reflection conseguirlo. Se almacena en el fieldmOnClickListener (source).

Así es como se puede obtener OnClickListener definido para su diseño:

OnClickListener tmpOnClickListener = null; 
try { 
    Class<View> cls = (Class<View>) Class.forName("android.view.View"); 
    Field fld = cls.getDeclaredField("mOnClickListener"); 
    fld.setAccessible(true); // because it is protected 

    tmpOnClickListener = (OnClickListener) fld.get(myCustomView.getChildAt(0)); 

    fld.setAccessible(false); // restore it's original property 
} catch (SecurityException e) { 
    e.printStackTrace(); 
} catch (NoSuchFieldException e) { 
    e.printStackTrace(); 
} catch (IllegalArgumentException e) { 
    e.printStackTrace(); 
} catch (IllegalAccessException e) { 
    e.printStackTrace(); 
} catch (ClassNotFoundException e) { 
    e.printStackTrace(); 
} 

final OnClickListener preDefinedListener = tmpOnClickListener; 

if (preDefinedListener != null) { 
    myCustomView.getChildAt(0).setOnClickListener(new OnClickListener() { 
     @Override 
     public void onClick(View paramView) { 
      preDefinedListener.onClick(paramView); 

      Toast.makeText(getActivity(), "ExpandoOnClickListener", Toast.LENGTH_LONG).show(); 
     } 
}); 

verdad, no me molestaría para manejar toda excepción correctamente, pero es suficiente para obtener la idea. Puede parecer desordenado, pero en realidad son solo 5 líneas de código nuevo para resolver su problema.

+0

Muchas gracias Vladimir :) me funciona bien. Solo quiero hacerte una pregunta: ¿la expansión es expansiva en términos de memoria y/o procesador? – Zakaria

+2

no hay problema =) bueno, obtener campos e invocar métodos a través de la reflexión es más caro que hacerlo "normalmente", pero en este caso la diferencia es tan pequeña que no afectará nada. Sin embargo, hay una advertencia: dado que se accede al campo por nombre, si su nombre cambia (lo que probablemente no ocurra), este código dejará de funcionar; no se bloqueará, pero se lanzará 'NoSuchFieldException', y' preDefinedListener 'terminará' null', lo que deja al oyente configurado para el diseño intacto. – Vladimir

72

Puede programación elevar haga clic en evento en una vista a llamar es OnClickListener de la siguiente manera:

view.performClick(); 

Ahora bien, si se llama a esto en su segunda disposición bajo el primer diseño de OnClickListener entonces espero que haga la magia

+1

Cuando hago esto. Me da un 06-05 10: 29: 59.470: E/AndroidRuntime (7518): java.lang.StackOverflowError – Zakaria

+0

puede publicar su excepción logcat completa – waqaslam

+0

¿está llamando 'myCustomView.performClick()'? Si, entonces necesita llamar como 'myCustomView.getChildAt (0) .performClick()' – waqaslam

0

Si no puede modificar el código de CustomView, entonces tiene la siguiente opción.

  • Extienda la vista personalizada.
  • Reemplace el método onClick() y vincule esto como un Oyente al primer diseño.
  • Dentro de onClick() primera llamada a super.onClick() luego agregue su funcionalidad adicional a continuación.

De esta manera usted mantiene el código existente y agrega funcionalidad adicional también.

+1

El evento OnClickListener se define como Escucha anónima. ¿Cómo puedo anularlo? – Zakaria

5

Desde SDK 15 sólo se puede llamar al método:

view.callOnClick() 
Cuestiones relacionadas