android diseño - Cómo manejar los clics de botón usando el XML onClick dentro de fragmentos




con desde (15)

Antes de Honeycomb (Android 3), cada actividad se registró para manejar los clics de los botones a través de la etiqueta onClick en el XML de un diseño:

android:onClick="myClickMethod"

Dentro de ese método, puede usar view.getId() y una instrucción switch para hacer la lógica del botón.

Con la introducción de Honeycomb, estoy dividiendo estas actividades en fragmentos que se pueden reutilizar en muchas actividades diferentes. La mayor parte del comportamiento de los botones es independiente de la actividad, y me gustaría que el código residiera dentro del archivo de Fragmentos sin usar el método antiguo (pre 1.6) de registrar el OnClickListener para cada botón.

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

El problema es que cuando se inflan mis diseños, sigue siendo la Actividad de hospedaje la que recibe los clics del botón, no los Fragmentos individuales. ¿Hay un buen enfoque para cualquiera

  • Registrar el fragmento para recibir los clics del botón?
  • ¿Pasar los eventos de clic de la Actividad al fragmento al que pertenecen?

Answers

Como veo respuestas son de alguna manera viejas. Recientemente, Google introdujo DataBinding que es mucho más fácil de manejar onClick o asignando en su xml.

Aquí hay un buen ejemplo que puedes ver cómo manejar esto:

<?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>

También hay un tutorial muy bueno sobre DataBinding que puedes encontrar Here .


Mejor solución en mi humilde opinión:

en el fragmento:

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

luego en Fragment's onViewStateRestored:

addClick(R.id.myButton);

El problema que creo es que la vista sigue siendo la actividad, no el fragmento. Los fragmentos no tienen una vista independiente propia y se adjuntan a la vista de actividades principal. Es por eso que el evento termina en la Actividad, no en el fragmento. Es desafortunado, pero creo que necesitarás un código para hacer que esto funcione.

Lo que he estado haciendo durante las conversiones es simplemente agregar un detector de clics que llama al antiguo controlador de eventos.

por ejemplo:

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

Esto ha estado funcionando para mí: (estudio de Android)

 @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

Usted podría hacer esto:

Actividad:

Fragment someFragment;    

//...onCreate etc instantiating your fragments

public void myClickMethod(View v) {
    someFragment.myClickMethod(v);
}

Fragmento:

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

En respuesta a @Ameen que quería menos acoplamiento para que los Fragmentos sean reutilizables

Interfaz:

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

Actividad:

XmlClickable someFragment;    

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

Fragmento:

public class SomeFragment implements XmlClickable {

//...onCreateView, etc.

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

Si se registra en xml con android: Onclick = "", se devolverá la llamada a la Actividad respetada en cuyo contexto pertenece su fragmento (getActivity ()). Si tal método no se encuentra en la Actividad, entonces el sistema lanzará una excepción.


Prefiero optar por el manejo de clics en el código que usar el atributo onClick en XML cuando se trabaja con fragmentos.

Esto se vuelve aún más fácil al migrar sus actividades a fragmentos. Solo puede llamar al controlador de clic (previamente establecido en android:onClick en XML) directamente desde cada bloque de case .

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:
              ...
        }
    }
}

Cuando se trata de manejar clics en fragmentos, me parece más simple que android:onClick .


Su actividad está recibiendo la devolución de llamada como debe haber utilizado:

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

Si desea que su fragmento reciba una devolución de llamada, haga esto:

mViewPagerCloth.setOnClickListener(this);

e implementar la interfaz onClickListener en Fragmento


Agregando a la respuesta de Blundell,
Si tienes más fragmentos, con un montón de onClicks:

Actividad:

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

} 

En tu fragmento:

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

Recientemente resolví este problema sin tener que agregar un método al contexto Actividad o tener que implementar OnClickListener. No estoy seguro si es una solución "válida" tampoco, pero funciona.

Basado en: https://developer.android.com/tools/data-binding/guide.html#binding_events

Se puede hacer con enlaces de datos: simplemente agregue su instancia de fragmento como una variable, luego puede vincular cualquier método con onClick.

<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>

Y el código de vinculación de fragmentos sería ...

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

    ...

}

En mi caso de uso, tengo 50 Visiones de imagen impares que necesitaba para conectar en un solo método onClick. Mi solución es recorrer las vistas dentro del fragmento y establecer el mismo oyente onclick en cada uno:

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

Puede definir una devolución de llamada como un atributo de su diseño XML. El artículo Atributos XML personalizados para sus widgets de Android personalizados le mostrará cómo hacerlo para un widget personalizado. El crédito es para Kevin Dion :)

Estoy investigando si puedo agregar atributos de estilo a la clase de Fragmento base.

La idea básica es tener la misma funcionalidad que implementa View cuando se trata con la devolución de llamada onClick.


Prefiero usar la siguiente solución para manejar eventos onClick. Esto funciona también para Actividad y Fragmentos.

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

Es posible que desee considerar el uso de EventBus para eventos desacoplados. Puede escuchar eventos con mucha facilidad. También puede asegurarse de que el evento se reciba en el subproceso de la interfaz de usuario (en lugar de llamar a runOnUiThread para usted por cada suscripción de evento)

https://github.com/greenrobot/EventBus

desde Github:

Bus de eventos optimizado para Android que simplifica la comunicación entre Actividades, Fragmentos, Subprocesos, Servicios, etc. Menos código, mejor calidad


Bastante seguro de que lo mejor es configurar un servidor proxy y luego usar algo como wireshark para monitorear el tráfico que va y viene. No soy un experto en esto, pero en los viejos tiempos antes de cambiar los enrutadores eran muy baratos, era muy fácil porque todos los paquetes se transmitían a todas las computadoras en la misma subred. Tal vez si pudiera conseguir un concentrador / enrutador que tenga la capacidad de desactivar el cambio, podría usar este método en lugar de un proxy.

En estos días, la mayoría de las comunicaciones se realiza mediante http y para eso tiene excelentes herramientas como Charles (mac) y Fiddler (windows) que hacen exactamente lo que quiere, excepto http. Es posible que al menos puedan darle ideas sobre cómo hacer lo mismo con Wireshark





android xml button android-fragments