2012-06-05 14 views
21

Ho una vista personalizzata con 2 layout di lineat: la prima è l'intestazione della vista e la seconda è la vista dettagli.come posso attivare l'evento Onclick a livello di programmazione in Android?

Nella vista personalizzata, OnClickListener dell'intestazione Linearlayout è già definito: quando si attiva, collassa/espande la seconda linearlayout.

Quello che voglio fare è aggiungere ulteriori funzionalità all'evento OnClickListener della mia intestazione (es .: collasso/espandi il secondo layout e mostri un Toast).

Non riesco a modificare il codice sorgente della visualizzazione personalizzata. Ho provato a impostare un nuovo OnClickListener ma nasconde l'evento iniziale (comprimi/espandi).

Come devo implementarlo?

Il codice sorgente di My Custom Vista:

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

quello che voglio fare è aggiungere del codice al già definito evento OnClickListener nella mia attività. Qualcosa del genere:

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

Si prega di fornire il codice ....... risposta –

+0

vedere @ di waqaslam. – Halil

risposta

9

soluzione semplice sarebbe quella di ottenere OnClickListener originale e poi il fuoco in uno nuovo:

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

Purtroppo, View non hai getOnClickListner(), ma credo che è possibile utilizzare reflection per ottenerlo. È memorizzato nello fieldmOnClickListener (source).

In questo modo è possibile ottenere OnClickListener definito per il layout:

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

Non ci ha dato fastidio per gestire correttamente tutte le eccezioni, ma è sufficiente per ottenere l'idea. Potrebbe sembrare disordinato, ma in realtà sono solo 5 righe di nuovo codice per risolvere il tuo problema.

+0

Grazie mille Vladimir :) funziona per me bene. Voglio solo farti una domanda: Reflection è espansivo in termini di memoria e/o processore ?? – Zakaria

+2

no problem =) beh, ottenere i campi e invocare i metodi tramite reflection è più costoso che farlo "normalmente", ma in questo caso la differenza è così piccola che non influenzerà nulla. Tuttavia, poiché il campo è accessibile per nome, se il suo nome cambia (il che probabilmente non accadrà) questo codice smetterà di funzionare - non si bloccherà, ma verrà generato 'NoSuchFieldException' e' preDefinedListener 'finirà con' null', che lascia intatto il listener impostato per il layout. – Vladimir

72

di programmazione è possibile alzare clicca evento su una vista da chiamare è OnClickListener come di seguito:

view.performClick(); 

Ora, se si chiama questo sul tuo secondo layout sotto primo layout del OnClickListener quindi spero che dovrebbe fare la magia

+1

Quando lo faccio. Mi dà un 06-05 10: 29: 59.470: E/AndroidRuntime (7518): java.lang.StackOverflowError – Zakaria

+0

puoi pubblicare l'eccezione logcat completa – waqaslam

+0

stai chiamando 'myCustomView.performClick()'? Se, quindi, è necessario chiamare 'myCustomView.getChildAt (0) .performClick()' – waqaslam

0

Se non è possibile modificare il codice di CustomView, allora avete l'opzione di seguito.

  • Estendere CustomView.
  • Sostituire il metodo onClick() e associarlo come Listener al primo layout.
  • All'interno di onClick() prima chiamata super.onClick() quindi aggiungere le funzionalità aggiuntive di seguito.

In questo modo si mantiene il codice esistente e si aggiungono funzionalità aggiuntive.

+1

l'evento OnClickListener è definito come listener anonimo. Come posso ignorarlo ?? – Zakaria

5

Dal SDK 15 si può semplicemente chiamare il metodo:

view.callOnClick() 
Problemi correlati