So behandeln Sie die Klick-Klicks mit dem XML onClick in Fragments

Pre-Honeycomb (Android 3), jede Aktivität wurde registriert, um Button-Klicks über das onClick Tag in einem Layout-XML zu behandeln:

 android:onClick="myClickMethod" 

Innerhalb dieser Methode können Sie view.getId() und eine switch-Anweisung verwenden, um die Schaltflächenlogik view.getId() .

Mit der Einführung von Honeycomb breche ich diese Aktivitäten in Fragmente, die in vielen verschiedenen Aktivitäten wiederverwendet werden können. Die meisten der Verhalten der Tasten ist Aktivität unabhängig, und ich möchte, dass der Code in der Fragments-Datei wohnen, ohne die alte (vor 1.6) Methode der Registrierung der OnClickListener für jede Schaltfläche zu verwenden.

 final Button button = (Button) findViewById(R.id.button_id); button.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { // Perform action on click } }); 

Das Problem ist, dass, wenn mein Layout ist aufgeblasen ist es immer noch die Hosting-Aktivität, die die Schaltfläche Klicks, nicht die einzelnen Fragmente erhalten. Gibt es auch einen guten Ansatz

  • Registrieren Sie das Fragment, um die Klick-Klicks zu erhalten?
  • Übergeben Sie die Klickereignisse aus der Aktivität in das Fragment, zu dem sie gehören?

  • Android Data Binding auf einzelne Ansichten Add to LinearLayout programmgesteuert?
  • Gibt es eine Möglichkeit, den vollständigen Paketnamen in xml mit benutzerdefinierten Ansichten (Android) zu vermeiden?
  • Wie kann man eine Many-To-Many-Beziehung in XML oder einem anderen einfachen Dateiformat darstellen?
  • Wie funktioniert der Android XmlPullParser mit Schwachstellen?
  • Android View align unten (programmgesteuert) ohne XML
  • Wie erstelle ich die Verzögerung von 1 Sekunde, bevor du das Alpha von View gesetzt hast?
  • RadioGroup checkedButton-Eigenschaft
  • Selector mit android: drawable = "@ color / transparent" Attribut
  • 17 Solutions collect form web for “So behandeln Sie die Klick-Klicks mit dem XML onClick in Fragments”

    Du könntest das einfach machen:

    Aktivität:

     Fragment someFragment; ...onCreate etc instantiating your fragments public void myClickMethod(View v) { someFragment.myClickMethod(v); } 

    Fragment:

     public void myClickMethod(View v) { switch(v.getId()) { // Just like you were doing } } 

    Als Antwort auf @Ameen, die weniger Kopplung wollten, sind Fragmente wiederverwendbar

    Schnittstelle:

     public interface XmlClickable { void myClickMethod(View v); } 

    Aktivität:

     XmlClickable someFragment; ...onCreate, etc. instantiating your fragments casting to your interface. public void myClickMethod(View v) { someFragment.myClickMethod(v); } 

    Fragment:

     public class SomeFragment implements XmlClickable { ...onCreateView, etc. @Override public void myClickMethod(View v) { switch(v.getId()){ // Just like you were doing } } 

    Ich bevorzuge die folgende Lösung für die Bearbeitung von onClick-Events. Das funktioniert auch für Aktivität und Fragmente.

     public class StartFragment extends Fragment implements OnClickListener{ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment_start, container, false); Button b = (Button) v.findViewById(R.id.StartButton); b.setOnClickListener(this); return v; } @Override public void onClick(View v) { switch (v.getId()) { case R.id.StartButton: ... break; } } } 

    Das Problem, das ich denke, ist, dass die Aussicht immer noch die Aktivität ist, nicht das Fragment. Die Fragmente haben keine eigenständige eigene Sicht und sind der Ansicht der übergeordneten Aktivitäten beigefügt. Das ist, warum die Veranstaltung endet in der Aktivität, nicht das Fragment. Es ist unglücklich, aber ich denke, du brauchst einen Code, um diese Arbeit zu machen.

    Was ich bei Conversions gemacht habe, fügt einfach einen Klick-Listener hinzu, der den alten Event-Handler anruft.

    zum Beispiel:

     final Button loginButton = (Button) view.findViewById(R.id.loginButton); loginButton.setOnClickListener(new OnClickListener() { @Override public void onClick(final View v) { onLoginClicked(v); } }); 

    Ich habe vor kurzem dieses Problem gelöst, ohne eine Methode zum Kontext hinzufügen oder OnClickListener implementieren zu müssen. Ich bin mir nicht sicher, ob es eine "gültige" Lösung ist, aber es funktioniert.

    Basierend auf: https://developer.android.com/tools/data-binding/guide.html#binding_events

    Es kann mit Datenbindungen gemacht werden: Füge einfach deine Fragmentinstanz als Variable hinzu, dann kannst du jede Methode mit onClick verknüpfen.

     <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" tools:context="com.example.testapp.fragments.CustomFragment"> <data> <variable name="fragment" type="com.example.testapp.fragments.CustomFragment"/> </data> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_place_black_24dp" android:onClick="@{fragment.buttonClicked}"/> </LinearLayout> </layout> 

    Und das Fragment, das Code verknüpft, wäre …

     public class CustomFragment extends Fragment { ... @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment View view = inflater.inflate(R.layout.fragment_person_profile, container, false); FragmentCustomBinding binding = DataBindingUtil.bind(view); binding.setFragment(this); return view; } ... } 

    ButterKnife ist wohl die beste Lösung für das Problem der Störung. Es verwendet Annotationsprozessoren, um den sogenannten "old method" boilerplate code zu erzeugen.

    Aber die onClick-Methode kann immer noch mit einer benutzerdefinierten Inflator verwendet werden.

    Wie benutzt man

     @Override public View onCreateView(LayoutInflater inflater, ViewGroup cnt, Bundle state) { inflater = FragmentInflatorFactory.inflatorFor(inflater, this); return inflater.inflate(R.layout.fragment_main, cnt, false); } 

    Implementierung

     public class FragmentInflatorFactory implements LayoutInflater.Factory { private static final int[] sWantedAttrs = { android.R.attr.onClick }; private static final Method sOnCreateViewMethod; static { // We could duplicate its functionallity.. or just ignore its a protected method. try { Method method = LayoutInflater.class.getDeclaredMethod( "onCreateView", String.class, AttributeSet.class); method.setAccessible(true); sOnCreateViewMethod = method; } catch (NoSuchMethodException e) { // Public API: Should not happen. throw new RuntimeException(e); } } private final LayoutInflater mInflator; private final Object mFragment; public FragmentInflatorFactory(LayoutInflater delegate, Object fragment) { if (delegate == null || fragment == null) { throw new NullPointerException(); } mInflator = delegate; mFragment = fragment; } public static LayoutInflater inflatorFor(LayoutInflater original, Object fragment) { LayoutInflater inflator = original.cloneInContext(original.getContext()); FragmentInflatorFactory factory = new FragmentInflatorFactory(inflator, fragment); inflator.setFactory(factory); return inflator; } @Override public View onCreateView(String name, Context context, AttributeSet attrs) { if ("fragment".equals(name)) { // Let the Activity ("private factory") handle it return null; } View view = null; if (name.indexOf('.') == -1) { try { view = (View) sOnCreateViewMethod.invoke(mInflator, name, attrs); } catch (IllegalAccessException e) { throw new AssertionError(e); } catch (InvocationTargetException e) { if (e.getCause() instanceof ClassNotFoundException) { return null; } throw new RuntimeException(e); } } else { try { view = mInflator.createView(name, null, attrs); } catch (ClassNotFoundException e) { return null; } } TypedArray a = context.obtainStyledAttributes(attrs, sWantedAttrs); String methodName = a.getString(0); a.recycle(); if (methodName != null) { view.setOnClickListener(new FragmentClickListener(mFragment, methodName)); } return view; } private static class FragmentClickListener implements OnClickListener { private final Object mFragment; private final String mMethodName; private Method mMethod; public FragmentClickListener(Object fragment, String methodName) { mFragment = fragment; mMethodName = methodName; } @Override public void onClick(View v) { if (mMethod == null) { Class<?> clazz = mFragment.getClass(); try { mMethod = clazz.getMethod(mMethodName, View.class); } catch (NoSuchMethodException e) { throw new IllegalStateException( "Cannot find public method " + mMethodName + "(View) on " + clazz + " for onClick"); } } try { mMethod.invoke(mFragment, v); } catch (InvocationTargetException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new AssertionError(e); } } } } 

    Das ist ein anderer Weg:

    1. Erstellen Sie ein BaseFragment wie folgt:

     public abstract class BaseFragment extends Fragment implements OnClickListener 

    2.Verwendung

     public class FragmentA extends BaseFragment 

    Anstatt von

     public class FragmentA extends Fragment 

    3.In Ihrer Tätigkeit:

     public class MainActivity extends ActionBarActivity implements OnClickListener 

    und

     BaseFragment fragment = new FragmentA; public void onClick(View v){ fragment.onClick(v); } 

    Ich hoffe es hilft.

    Ich würde lieber für die onClick in Code gehen, als das onClick Attribut in XML zu verwenden, wenn onClick mit Fragmenten arbeite.

    Dies wird noch einfacher, wenn Sie Ihre Aktivitäten auf Fragmente migrieren. Sie können einfach den Klick-Handler (vorher auf android:onClick in XML) direkt aus jedem case Block android:onClick .

     findViewById(R.id.button_login).setOnClickListener(clickListener); ... OnClickListener clickListener = new OnClickListener() { @Override public void onClick(final View v) { switch(v.getId()) { case R.id.button_login: // Which is supposed to be called automatically in your // activity, which has now changed to a fragment. onLoginClick(v); break; case R.id.button_logout: ... } } } 

    Wenn es darum geht, Klicks in Fragmenten zu behandeln, sieht das mir einfacher aus als android:onClick .

    Sie können einen Rückruf als Attribut Ihres XML-Layouts definieren. Der Artikel Custom XML Attribute Für Ihre Custom Android Widgets wird Ihnen zeigen, wie es für ein benutzerdefiniertes Widget zu tun. Credit geht an Kevin Dion 🙂

    Ich untersuche, ob ich der Basis-Fragment-Klasse stilvolle Attribute hinzufügen kann.

    Die Grundidee besteht darin, die gleiche Funktionalität zu haben, die View bei der Bearbeitung des OnClick-Rückrufs implementiert.

    In meinem Anwendungsfall habe ich 50 ungerade ImageViews, die ich brauchte, um in eine einzelne onClick-Methode zu haken. Meine Lösung ist, die Ansichten innerhalb des Fragments zu übergehen und den gleichen Onclick-Listener auf jedem zu setzen:

      final View.OnClickListener imageOnClickListener = new View.OnClickListener() { @Override public void onClick(View v) { chosenImage = ((ImageButton)v).getDrawable(); } }; ViewGroup root = (ViewGroup) getView().findViewById(R.id.imagesParentView); int childViewCount = root.getChildCount(); for (int i=0; i < childViewCount; i++){ View image = root.getChildAt(i); if (image instanceof ImageButton) { ((ImageButton)image).setOnClickListener(imageOnClickListener); } } 

    Hinzufügen zu Blundells Antwort,
    Wenn du mehr Fragmente hast, mit vielen OnClicks:

    Aktivität:

     Fragment someFragment1 = (Fragment)getFragmentManager().findFragmentByTag("someFragment1 "); Fragment someFragment2 = (Fragment)getFragmentManager().findFragmentByTag("someFragment2 "); Fragment someFragment3 = (Fragment)getFragmentManager().findFragmentByTag("someFragment3 "); ...onCreate etc instantiating your fragments public void myClickMethod(View v){ if (someFragment1.isVisible()) { someFragment1.myClickMethod(v); }else if(someFragment2.isVisible()){ someFragment2.myClickMethod(v); }else if(someFragment3.isVisible()){ someFragment3.myClickMethod(v); } } 

    In deinem Fragment:

      public void myClickMethod(View v){ switch(v.getid()){ // Just like you were doing } } 

    Wenn du dich in XML mit android registrierst: Onclick = "", wird der Rückruf an die respektierte Aktivität gegeben, unter deren Kontext dein Fragment gehört (getActivity ()). Wenn diese Methode nicht in der Aktivität gefunden wird, dann wird das System eine Ausnahme auslösen.

    Vielleicht möchten Sie die Verwendung von EventBus für entkoppelte Ereignisse in Erwägung ziehen. Sie können ganz einfach Ereignisse hören. Sie können auch sicherstellen, dass die Veranstaltung auf dem ui-Thread empfangen wird (anstatt runOnUiThread .. für sich selbst für jedes Event-Abonnement)

    https://github.com/greenrobot/EventBus

    Von Github:

    Android optimierte Event-Bus, der die Kommunikation zwischen Aktivitäten, Fragmente, Threads, Services, etc. vereinfacht. Weniger Code, bessere Qualität

    Als ich Antworten sehe, sind sie irgendwie alt. In letzter Zeit stellt Google DataBinding vor, die viel einfacher zu handhaben ist. Klicken Sie auf oder klicken Sie in Ihrem xml.

    Hier ist ein gutes Beispiel, mit dem man sehen kann, wie man damit umgeht:

     <?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="handlers" type="com.example.Handlers"/> <variable name="user" type="com.example.User"/> </data> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user.firstName}" android:onClick="@{user.isFriend ? handlers.onClickFriend : handlers.onClickEnemy}"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user.lastName}" android:onClick="@{user.isFriend ? handlers.onClickFriend : handlers.onClickEnemy}"/> </LinearLayout> </layout> 

    Es gibt auch sehr nettes Tutorial über DataBinding, das du hier finden kannst.

    Ich möchte Adjorn Linkz's Antwort hinzufügen.

    Wenn Sie mehrere Handler benötigen, können Sie einfach Lambda Referenzen verwenden

     void onViewCreated(View view, Bundle savedInstanceState) { view.setOnClickListener(this::handler); } void handler(View v) { ... } 

    Der Trick hier ist, dass die Signatur der handler Methode mit View.OnClickListener.onClick Signatur View.OnClickListener.onClick . Auf diese Weise brauchen Sie die View.OnClickListener Schnittstelle nicht.

    Außerdem brauchen Sie keine switch-Anweisungen.

    Leider ist diese Methode nur auf Schnittstellen beschränkt, die eine einzige Methode oder eine Lambda erfordern.

    Das hat für mich gearbeitet: (Android studio)

      @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.update_credential, container, false); Button bt_login = (Button) rootView.findViewById(R.id.btnSend); bt_login.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { System.out.println("Hi its me"); }// end onClick }); return rootView; }// end onCreateView 

    Beste Lösung IMHO:

    Im Fragment:

     protected void addClick(int id) { try { getView().findViewById(id).setOnClickListener(this); } catch (Exception e) { e.printStackTrace(); } } public void onClick(View v) { if (v.getId()==R.id.myButton) { onMyButtonClick(v); } } 

    Dann in Fragments onViewStateRestored:

     addClick(R.id.myButton); 

    Ihre Aktivität empfängt den Rückruf, wie es verwendet werden muss:

     mViewPagerCloth.setOnClickListener((YourActivityName)getActivity()); 

    Wenn Sie möchten, dass Ihr Fragment einen Rückruf erhält, dann machen Sie dies:

     mViewPagerCloth.setOnClickListener(this); 

    Und implementiere onClickListener Schnittstelle auf Fragment

    Das Android ist ein Google Android Fan-Website, Alles über Android Phones, Android Wear, Android Dev und Android Spiele Apps und so weiter.