2012-10-16 9 views
38

Vorrei fare un dialog fragment che chiede "Sei sicuro?" con una risposta "si/no".Più semplice frammento di dialogo sì/no

Ho guardato allo the documentation ed è veramente prolisso, andando dappertutto, spiegando come creare finestre di dialogo avanzate, ma nessun codice intatto su come creare una semplice finestra di dialogo "ciao mondo". La maggior parte delle esercitazioni utilizza il deprecato sistema di finestre di dialogo. Il official blog sembra essere inutilmente complicato e difficile da capire.

Quindi, qual è il modo più semplice per creare e visualizzare un dialogo di avviso veramente semplice? Punti bonus se sta utilizzando la libreria di supporto.

+0

Prova anche questo http://stackoverflow.com/a/38500468/3496570 – Nepster

risposta

76

Un DialogFragment è in realtà solo un frammento che racchiude una finestra di dialogo. Puoi inserire qualsiasi tipo di finestra di dialogo creando e restituendo la finestra di dialogo nel metodo onCreateDialog() di DialogFragment.

Ecco un esempio DialogFragment:

class MyDialogFragment extends DialogFragment{ 
    Context mContext; 
    public MyDialogFragment() { 
     mContext = getActivity(); 
    } 
    @Override 
    public Dialog onCreateDialog(Bundle savedInstanceState) { 
     AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(mContext); 
     alertDialogBuilder.setTitle("Really?"); 
     alertDialogBuilder.setMessage("Are you sure?"); 
     //null should be your on click listener 
     alertDialogBuilder.setPositiveButton("OK", null); 
     alertDialogBuilder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { 

      @Override 
      public void onClick(DialogInterface dialog, int which) { 
       dialog.dismiss(); 
      } 
     }); 


     return alertDialogBuilder.create(); 
    } 
} 

per creare la finestra chiamata:

new MyDialogFragment().show(getFragmentManager(), "MyDialog"); 

E per chiudere la finestra da qualche parte:

((MyDialogFragment)getFragmentManager().findFragmentByTag("MyDialog")).getDialog().dismiss(); 

Tutto questo codice funzionerà perfettamente con la libreria di supporto, semplicemente cambiando le importazioni per utilizzare le classi della libreria di supporto.

+0

Grazie, ma sembra causare l'errore 'Impossibile istanziare il frammento: assicurati che il nome della classe esista, sia pubblico e abbia un costruttore vuoto pubblico 'se esco e reinserisco l'applicazione mentre la finestra di dialogo è aperta. Aggiunto un costruttore vuoto, ma poi ha ottenuto un puntatore nullo su mContext. – Muz

+8

@muz Il sistema Android richiede una classe 'Fragment' per avere un costruttore con ** nessun parametro ** per istanziare il frammento quando è necessario. In un 'Fragment' hai un riferimento all'attività in cui questo frammento viene usato con il metodo' getActivity() '(usalo invece di' mContext'). Anche il frammento deve essere dichiarato nel proprio file java o come una ** classe statica interna in un'altra classe. Altrimenti Android non sarà in grado di trovare il tuo frammento per istanziarlo. – Luksprog

+0

@Luksprog Oh, ok, grazie. La parte 'getActivity()' l'ha riparata. – Muz

12

Quindi, qual è il modo più semplice per creare e visualizzare una finestra di dialogo Alert di base? Punti bonus se sta utilizzando la libreria di supporto.

È sufficiente creare un DialogFragment (SDK o libreria di supporto) e sovrascrivere il metodo onCreateDialog per restituire un AlertDialog con il testo e pulsanti desiderata impostata su di esso:

public static class SimpleDialog extends DialogFragment { 

    @Override 
    public Dialog onCreateDialog(Bundle savedInstanceState) { 
     return new AlertDialog.Builder(getActivity()) 
       .setMessage("Are you sure?").setPositiveButton("Ok", null) 
       .setNegativeButton("No way", null).create(); 
    } 

} 

di fare qualcosa quando l'utente si usa del pulsante dovrai fornire un'istanza di DialogInterface.OnClickListener anziché i riferimenti null dal mio codice.

2

a causa di attività/Frammento del ciclo di vita@athor & approccio @lugsprog può fallire, modo più elegante è quello di ottenere ** contesto attività dal metodo onAttach e conservarla riferimento debole ** (& cercare di evitare costruttore non predefinito in DialogFragment!, Per passare alcun argomento per argomenti uso di dialogo) in questo modo:

public class NotReadyDialogFragment extends DialogFragment { 

    public static String DIALOG_ARGUMENTS = "not_ready_dialog_fragment_arguments"; 

    private WeakReference<Context> _contextRef; 

    public NotReadyDialogFragment() { 
    } 

    @Override 
    public Dialog onCreateDialog(Bundle savedInstanceState) { 

     /** example pulling of arguments */ 
     Bundle bundle = getArguments(); 
     if (bundle!=null) { 
      bundle.get(DIALOG_ARGUMENTS); 
     } 

     // 
     // Caution !!! 
     // check we can use contex - by call to isAttached 
     // or by checking stored weak reference value itself is not null 
     // or stored in context -> example allowCreateDialog() 
     // - then for example you could throw illegal state exception or return null 
     // 
     AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(_contextRef.get()); 
     alertDialogBuilder.setMessage("..."); 
     alertDialogBuilder.setNegativeButton("Przerwij", new DialogInterface.OnClickListener() { 

      @Override 
      public void onClick(DialogInterface dialog, int which) { 
       dialog.dismiss(); 
      } 
     }); 
     return alertDialogBuilder.create(); 
    } 

    @Override 
    public void onAttach(Activity activity) { 
     super.onAttach(activity); 
     _contextRef = new WeakReference<Context>(activity); 
    } 

    boolean allowCreateDialog() { 
     return _contextRef !== null 
       && _contextRef.get() != null; 
    } 

EDIT: & se si vuole dialogo respingere quindi:

  1. cercare di farlo
  2. controllo se è esiste
  3. controllare se sta visualizzando
  4. respingere

qualcosa di simile:

 NotReadyDialogFragment dialog = ((NotReadyDialogFragment) getActivity().getFragmentManager().findFragmentByTag("MyDialogTag")); 
    if (dialog != null) { 
     Dialog df = dialog.getDialog(); 
     if (df != null && df.isShowing()) { 
      df.dismiss(); 
     } 
    } 

EDIT2: & se la u vuole dialogo come non annullabile u dovrebbe cambiare onCreatweDialog dichiarazione di ritorno come questo set:

/** convert builder to dialog */ 
    AlertDialog alert = alertDialogBuilder.create(); 
    /** disable cancel outside touch */ 
    alert.setCanceledOnTouchOutside(false); 
    /** disable cancel on press back button */ 
    setCancelable(false); 

    return alert; 
+0

Quindi ho capito che chiamare 'getActivity()' nel costruttore può fallire, ma perché la soluzione suggerita da Luksprog fallirà? Chiamare 'getActivity()' in 'onCreateDialog()' è esattamente ciò che fa l'implementazione di default, archiviare il mio riferimento al contesto suona come l'opposto di ciò che voglio fare. – Thorbear

+0

@Thorbear getActivity() potrebbe restituire null quando il frammento non è collegato all'attività - è possibile utilizzarlo ma è necessario verificarlo - sam per esempio utilizzando getResources() in frammento mentre il frammento non è collegato – ceph3us

+0

Sì, e solitamente (sempre) il il frammento non è collegato quando viene chiamato il costruttore. Ma c'è qualche situazione in cui 'onCreateDialog()' verrà chiamato mentre il frammento non è collegato? Di nuovo, l'implementazione di default (la libreria di supporto) chiama 'getActivity()' in 'onCreateDialog()' senza verificare nulla, stai dicendo che dovrebbe? – Thorbear

2

Per quelle che codificano con Kotlin e Anko, ora è possibile creare dialoghi in 4 righe di codice:

alert("Order", "Do you want to order this item?") { 
    positiveButton("Yes") { processAnOrder() } 
    negativeButton("No") { } 
}.show() 
Problemi correlati