Mostrar diálogo desde fragmento?


Tengo algunos fragmentos que necesitan mostrar un diálogo regular. En estos diálogos, el usuario puede elegir una respuesta sí / no, y luego el fragmento debe comportarse en consecuencia.

Ahora, la clase Fragment no tiene un método onCreateDialog() para reemplazar, así que supongo que tengo que implementar los diálogos fuera, en el que contiene Activity. Está bien, pero entonces el Activity necesita informar la respuesta elegida de alguna manera al fragmento. Por supuesto, podría usar un patrón de devolución de llamada aquí, para que el fragmento se registre en el Activity con una clase de escucha, y la Actividad reportaría la respuesta a través de eso, o algo así.

Pero esto parece ser un gran lío para una tarea simple como mostrar un diálogo "simple" sí-no en un fragmento. También, de esta manera mi Fragment sería menos autónomo.

¿Hay alguna forma más limpia de hacer esto?

Editar:

La respuesta a esta pregunta realmente no explica en detalle cómo se debe usar DialogFragments para mostrar diálogos desde Fragmento. Así que AFAIK, el camino a seguir es:

  1. Muestra un Fragmento.
  2. Cuando sea necesario, crea una instancia de un DialogFragment.
  3. Establezca el fragmento original como el destino de este DialogFragment, con .setTargetFragment().
  4. Mostrar el DialogFragment con .show() del fragmento original.
  5. Cuando el usuario elige alguna opción en este DialogFragment, notifique al Fragmento original sobre esta selección (por ejemplo, el usuario hizo clic en 'sí'), puede obtener la referencia del original Fragmento con .getTarget().
  6. Descarte el DialogFragment.
Author: Shubham Soni, 2011-03-22

7 answers

Debe usar un DialogFragment en su lugar.

 37
Author: mgv,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-23 01:25:18

Debo dudar cautelosamente de la respuesta previamente aceptada de que usar un DialogFragment es la mejor opción. El propósito (principal) del DialogFragment parece ser mostrar fragmentos que son diálogos en sí mismos, no mostrar fragmentos que tienen diálogos para mostrar.

Creo que usar la actividad del fragmento para mediar entre el diálogo y el fragmento es la opción preferible.

 28
Author: Mark D,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-28 17:52:07

Aquí hay un ejemplo completo de un DialogFragment sí/no:

La clase:

public class SomeDialog extends DialogFragment {

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        return new AlertDialog.Builder(getActivity())
            .setTitle("Title")
            .setMessage("Sure you wanna do this!")
            .setNegativeButton(android.R.string.no, new OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    // do nothing (will close dialog)
                }
            })
            .setPositiveButton(android.R.string.yes,  new OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    // do something
                }
            })
            .create();
    }
}

Para iniciar el diálogo:

        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        // Create and show the dialog.
        SomeDialog newFragment = new SomeDialog ();
        newFragment.show(ft, "dialog");

También puede dejar que la clase implemente OnClickListener y lo use en lugar de los oyentes incrustados.

Devolución de llamada a la actividad

Si quieres implementar callback así es como se hace En su actividad:

YourActivity extends Activity implements OnFragmentClickListener

Y

@Override
public void onFragmentClick(int action, Object object) {
    switch(action) {
        case SOME_ACTION:
        //Do your action here
        break;
    }
}

La clase callback:

public interface OnFragmentClickListener {
    public void onFragmentClick(int action, Object object);
}

Luego, para realizar una devolución de llamada desde un fragmento, debe asegúrese de que el oyente esté adjunto de la siguiente manera:

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    try {
        mListener = (OnFragmentClickListener) activity;
    } catch (ClassCastException e) {
        throw new ClassCastException(activity.toString() + " must implement listeners!");
    }
}

Y una devolución de llamada se realiza así:

mListener.onFragmentClick(SOME_ACTION, null); // null or some important object as second parameter.
 22
Author: Warpzit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-03 06:40:39

Para mí, fue lo siguiente-

MyFragment:

public class MyFragment extends Fragment implements MyDialog.Callback
{
    ShowDialog activity_showDialog;

    @Override
    public void onAttach(Activity activity)
    {
        super.onAttach(activity);
        try
        {
            activity_showDialog = (ShowDialog)activity;
        }
        catch(ClassCastException e)
        {
            Log.e(this.getClass().getSimpleName(), "ShowDialog interface needs to be     implemented by Activity.", e);
            throw e;
        }
    }

    @Override
    public void onClick(View view) 
    {
        ...
        MyDialog dialog = new MyDialog();
        dialog.setTargetFragment(this, 1); //request code
        activity_showDialog.showDialog(dialog);
        ...
    }

    @Override
    public void accept()
    {
        //accept
    }

    @Override
    public void decline()
    {
        //decline
    }

    @Override
    public void cancel()
    {
        //cancel
    }

}

MiDialog:

public class MyDialog extends DialogFragment implements View.OnClickListener
{
    private EditText mEditText;
    private Button acceptButton;
    private Button rejectButton;
    private Button cancelButton;

    public static interface Callback
    {
        public void accept();
        public void decline();
        public void cancel();
    }

    public MyDialog()
    {
        // Empty constructor required for DialogFragment
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        View view = inflater.inflate(R.layout.dialogfragment, container);
        acceptButton = (Button) view.findViewById(R.id.dialogfragment_acceptbtn);
        rejectButton = (Button) view.findViewById(R.id.dialogfragment_rejectbtn);
        cancelButton = (Button) view.findViewById(R.id.dialogfragment_cancelbtn);
        acceptButton.setOnClickListener(this);
        rejectButton.setOnClickListener(this);
        cancelButton.setOnClickListener(this);
        getDialog().setTitle(R.string.dialog_title);
        return view;
    }

    @Override
    public void onClick(View v)
    {
        Callback callback = null;
        try
        {
            callback = (Callback) getTargetFragment();
        }
        catch (ClassCastException e)
        {
            Log.e(this.getClass().getSimpleName(), "Callback of this class must be implemented by target fragment!", e);
            throw e;
        }

        if (callback != null)
        {
            if (v == acceptButton)
            {   
                callback.accept();
                this.dismiss();
            }
            else if (v == rejectButton)
            {
                callback.decline();
                this.dismiss();
            }
            else if (v == cancelButton)
            {
                callback.cancel();
                this.dismiss();
            }
        }
    }
}

Actividad:

public class MyActivity extends ActionBarActivity implements ShowDialog
{
    ..

    @Override
    public void showDialog(DialogFragment dialogFragment)
    {
        FragmentManager fragmentManager = getSupportFragmentManager();
        dialogFragment.show(fragmentManager, "dialog");
    }
}

Disposición de DialogFragment:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/dialogfragment_textview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="10dp"
        android:text="@string/example"/>

    <Button
        android:id="@+id/dialogfragment_acceptbtn"
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:layout_centerHorizontal="true"
        android:layout_below="@+id/dialogfragment_textview"
        android:text="@string/accept"
        />

    <Button
        android:id="@+id/dialogfragment_rejectbtn"
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:layout_alignLeft="@+id/dialogfragment_acceptbtn"
        android:layout_below="@+id/dialogfragment_acceptbtn"
        android:text="@string/decline" />

     <Button
        android:id="@+id/dialogfragment_cancelbtn"
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:layout_marginBottom="20dp"
        android:layout_alignLeft="@+id/dialogfragment_rejectbtn"
        android:layout_below="@+id/dialogfragment_rejectbtn"
        android:text="@string/cancel" />

     <Button
        android:id="@+id/dialogfragment_heightfixhiddenbtn"
        android:layout_width="200dp"
        android:layout_height="20dp"
        android:layout_marginTop="10dp"
        android:layout_marginBottom="20dp"
        android:layout_alignLeft="@+id/dialogfragment_cancelbtn"
        android:layout_below="@+id/dialogfragment_cancelbtn"
        android:background="@android:color/transparent"
        android:enabled="false"
        android:text=" " />
</RelativeLayout>

Como muestra el nombre dialogfragment_heightfixhiddenbtn, simplemente no pude encontrar una manera de arreglar que la altura del botón inferior se cortara por la mitad a pesar de decir wrap_content, así que agregué un botón oculto para "cortar" por la mitad en su lugar. Perdón por el hackeo.

 10
Author: EpicPandaForce,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-15 09:59:56
 public void showAlert(){


     AlertDialog.Builder alertDialog = new AlertDialog.Builder(getActivity());
     LayoutInflater inflater = getActivity().getLayoutInflater();
     View alertDialogView = inflater.inflate(R.layout.test_dialog, null);
     alertDialog.setView(alertDialogView);

     TextView textDialog = (TextView) alertDialogView.findViewById(R.id.text_testDialogMsg);
     textDialog.setText(questionMissing);

     alertDialog.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
         public void onClick(DialogInterface dialog, int which) {
             dialog.cancel();
         }
     });
     alertDialog.show();

}

Dónde .test_dialog es de xml custom

 3
Author: Alex Zaraos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-08 22:40:33

Yo mismo soy un principiante y honestamente no pude encontrar una respuesta satisfactoria que pudiera entender o implementar.

Así que aquí hay un enlace externo que realmente me ayudó a lograr lo que quería. Es muy sencillo y fácil de seguir.

Http://www.helloandroid.com/tutorials/how-display-custom-dialog-your-android-application

ESTO ES LO QUE TRATÉ DE LOGRAR CON EL CÓDIGO:

Tengo una actividad principal que aloja un fragmento. Yo quería un cuadro de diálogo que aparecerá en la parte superior del diseño para solicitar la entrada del usuario y luego procesar la entrada en consecuencia. Ver una captura de pantalla

Esto es lo que se ve el onCreateView de mi fragmento

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

    View rootView = inflater.inflate(R.layout.fragment_home_activity, container, false);

    Button addTransactionBtn = rootView.findViewById(R.id.addTransactionBtn);

    addTransactionBtn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Dialog dialog = new Dialog(getActivity());
            dialog.setContentView(R.layout.dialog_trans);
            dialog.setTitle("Add an Expense");
            dialog.setCancelable(true);

            dialog.show();

        }
    });

Espero que te ayude

Hazme saber si hay alguna confusión. :)

 1
Author: Junaid Aziz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-22 12:54:15
    public static void OpenDialog (Activity activity, DialogFragment fragment){

    final FragmentManager fm = ((FragmentActivity)activity).getSupportFragmentManager();

    fragment.show(fm, "tag");
}
 0
Author: Elmar Fazlagic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-06 06:58:55