2012-06-05 10 views
21

Mam niestandardowy widok z 2 liniowymi układami: pierwszy to nagłówek widoku, a drugi to widok szczegółów.Jak mogę programowo uruchamiać zdarzenia Onclick w systemie Android?

W widoku niestandardowym, OnClickListener z nagłówka Linearlayout jest już zdefiniowany: po uruchomieniu zwija/rozwija drugi linelayout.

Co chcę zrobić, to dodać więcej funkcjonalności do zdarzenia OnClickListener mojego nagłówka (tj. Zwinąć/rozwinąć drugi układ i pokazać toast).

Nie mogę zmodyfikować kodu źródłowego widoku niestandardowego. Próbowałem ustawić nowy OnClickListener, ale ukrywa początkowe zdarzenie (zwiń/rozwiń).

Jak mam to wdrożyć?

Kod źródłowy widoku niestandardowego:

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

co chcę zrobić, to dodać trochę kodu do już zdefiniowane zdarzenie OnClickListener w mojej działalności. Coś takiego:

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

Proszę podać kod ....... odpowiedzi –

+0

Zobacz @ waqaslam użytkownika. – Halil

Odpowiedz

9

Prostym rozwiązaniem byłoby, aby uzyskać oryginalne OnClickListener a następnie zwolnić go w nowym:

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

Niestety View nie posiada getOnClickListner(), ale myślę, że można użyć reflection je zdobyć. Jest przechowywany w fieldmOnClickListener (source).

W ten sposób można uzyskać OnClickListener zdefiniowany dla układu:

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

naprawdę nie przeszkadza, aby obsłużyć wszystkie wyjątki poprawnie, ale to wystarczy, aby dostać się pomysł. Może to wyglądać nieładnie, ale w rzeczywistości to tylko 5 linii nowego kodu, aby rozwiązać problem.

+0

Wielkie dzięki Vladimir :) działa mi dobrze. Po prostu chcę zadać ci pytanie: czy odbicie jest ekspansywne pod względem pamięci i/lub procesora? – Zakaria

+2

no problem =) cóż, pobieranie pól i wywoływanie metod za pomocą odbicia jest droższe niż robienie tego "normalnie", ale w tym przypadku różnica jest tak niewielka, że ​​nie wpłynie na nic. Jest jednak pewne zastrzeżenie - ponieważ dostęp do pola jest możliwy po nazwie, jeśli zmieni się jego nazwa (co prawdopodobnie nie nastąpi), ten kod przestanie działać - nie będzie awarii, ale zostanie zgłoszony wyjątek 'NoSuchFieldException', a' preDefinedListener 'kończy się na' null', co powoduje, że zestaw słuchaczy jest ustawiony jako nienaruszony. – Vladimir

72

Można programowo podnieść kliknij zdarzenie na celu nazwać to OnClickListener jak poniżej:

view.performClick(); 

Teraz, jeśli nazywają to na drugi układ pod pierwszy układ na OnClickListener to mam nadzieję, że powinien zrobić magię

+1

Kiedy to zrobię. To daje mi 06-05 10: 29: 59.470: E/AndroidRuntime (7518): java.lang.StackOverflowError – Zakaria

+0

możesz opublikować swój pełny wyjątek logcat – waqaslam

+0

czy nazywasz 'myCustomView.performClick()'? Jeśli, więc musisz wywołać jako 'myCustomView.getChildAt (0) .performClick()' – waqaslam

0

Jeśli nie możesz zmodyfikować kodu CustomView, to masz poniżej opcję.

  • Rozszerzenie niestandardowego widoku.
  • Zastąpić metodę onClick() i powiązać ją jako odbiornik z pierwszym układem.
  • Wewnątrz onClick() najpierw wywołaj super.onClick(), a następnie dodaj swoją dodatkową funkcjonalność poniżej.

W ten sposób zachowujesz istniejący kod i dodajesz dodatkowe funkcje.

+1

Zdarzenie OnClickListener jest zdefiniowane jako Anonimowy odbiornik. Jak mogę to zmienić? – Zakaria

5

Ponieważ SDK 15 można po prostu wywołać metodę:

view.callOnClick() 
Powiązane problemy