2014-11-13 3 views
10

Ich habe eine einfache Klasse:Hörer über Bundle in AlertDialogFragment übergeben - ist das möglich?

public class AlertDialogFragment extends DialogFragment { 

    private static final DialogInterface.OnClickListener DUMMY_ON_BUTTON_CLICKED_LISTENER = new DialogInterface.OnClickListener() { 
     @Override 
     public void onClick(DialogInterface dialog, int which) { 
      // do nothing 
     } 
    }; 

    public static final class Builder implements Parcelable { 

     public static final Creator<Builder> CREATOR = new Creator<Builder>() { 
      @Override 
      public Builder createFromParcel(Parcel source) { 
       return new Builder(source); 
      } 

      @Override 
      public Builder[] newArray(int size) { 
       return new Builder[size]; 
      } 
     }; 

     private Optional<Integer> title; 
     private Optional<Integer> message; 
     private Optional<Integer> positiveButtonText; 
     private Optional<Integer> negativeButtonText; 

     public Builder() { 
      title = Optional.absent(); 
      message = Optional.absent(); 
      positiveButtonText = Optional.absent(); 
      negativeButtonText = Optional.absent(); 
     } 

     public Builder(Parcel in) { 
      title = (Optional<Integer>) in.readSerializable(); 
      message = (Optional<Integer>) in.readSerializable(); 
      positiveButtonText = (Optional<Integer>) in.readSerializable(); 
      negativeButtonText = (Optional<Integer>) in.readSerializable(); 
     } 

     @Override 
     public void writeToParcel(Parcel out, int flags) { 
      out.writeSerializable(title); 
      out.writeSerializable(message); 
      out.writeSerializable(positiveButtonText); 
      out.writeSerializable(negativeButtonText); 
     } 

     @Override 
     public int describeContents() { 
      return 0; 
     } 

     public Builder withTitle(Integer title) { 
      this.title = Optional.fromNullable(title); 
      return this; 
     } 

     public Builder withMessage(Integer message) { 
      this.message = Optional.fromNullable(message); 
      return this; 
     } 

     public Builder withPositiveButton(int buttonText) { 
      this.positiveButtonText = Optional.fromNullable(buttonText); 
      return this; 
     } 

     public Builder withNegativeButton(int buttonText) { 
      this.negativeButtonText = Optional.fromNullable(buttonText); 
      return this; 
     } 

     private void set(AlertDialog.Builder dialogBuilder, final AlertDialogFragment alertDialogFragment) { 
      if (title.isPresent()) { 
       dialogBuilder.setTitle(title.get()); 
      } 
      if (message.isPresent()) { 
       dialogBuilder.setMessage(message.get()); 
      } 
      if (positiveButtonText.isPresent()) { 
       dialogBuilder.setPositiveButton(positiveButtonText.get(), new DialogInterface.OnClickListener() { 
        @Override 
        public void onClick(DialogInterface dialog, int which) { 
         alertDialogFragment.onPositiveButtonClickedListener.onClick(dialog, which); 
        } 
       }); 
      } 
      if (negativeButtonText.isPresent()) { 
       dialogBuilder.setNegativeButton(negativeButtonText.get(), new DialogInterface.OnClickListener() { 
        @Override 
        public void onClick(DialogInterface dialog, int which) { 
         alertDialogFragment.onNegativeButtonClickedListener.onClick(dialog, which); 
        } 
       }); 
      } 
     } 

     public AlertDialogFragment build() { 
      return AlertDialogFragment.newInstance(this); 
     } 
    } 


    private static final String KEY_BUILDER = "builder"; 

    private DialogInterface.OnClickListener onPositiveButtonClickedListener = DUMMY_ON_BUTTON_CLICKED_LISTENER; 
    private DialogInterface.OnClickListener onNegativeButtonClickedListener = DUMMY_ON_BUTTON_CLICKED_LISTENER; 


    private static AlertDialogFragment newInstance(Builder builder) { 
     Bundle args = new Bundle(); 
     args.putParcelable(KEY_BUILDER, builder); 
     AlertDialogFragment fragment = new AlertDialogFragment(); 
     fragment.setArguments(args); 
     return fragment; 
    } 

    public void setOnPositiveButtonClickedListener(DialogInterface.OnClickListener listener) { 
     this.onPositiveButtonClickedListener = listener != null ? listener : DUMMY_ON_BUTTON_CLICKED_LISTENER; 
    } 

    public void setOnNegativeButtonClickedListener(DialogInterface.OnClickListener listener) { 
     this.onNegativeButtonClickedListener = listener != null ? listener : DUMMY_ON_BUTTON_CLICKED_LISTENER; 
    } 

    @Override 
    public Dialog onCreateDialog(Bundle savedInstanceState) { 
     AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity()); 
     Builder builder = getArguments().getParcelable(KEY_BUILDER); 
     builder.set(alertDialogBuilder, this); 
     return alertDialogBuilder.create(); 
    } 


} 

Jetzt habe ich auf den Knopf klicken Zuhörer in SimpleDialogFragment direkt zu setzen, weil ich nicht die Zuhörer über Bundle (args) passieren kann. Aber ich will - so es wie Instanziieren ein AlertDialog aussehen:

AlertDialogFragment dialogFragment = new AlertDialogFragment.Builder() 
       .withTitle(R.string.no_internet_connection) 
       .withMessage(messageId) 
       .withPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { 
        @Override 
        public void onClick(DialogInterface dialog, int which) { 
         dialog.dismiss(); 
        } 
       }).build(); 
dialogFragment.show(getSupportFragmentManager(), FRAGMENT_TAG_NO_INTERNET_CONNECTION); 

Aber jetzt sollte ich Zuhörer auf diese Weise festgelegt:

AlertDialogFragment dialogFragment = new AlertDialogFragment.Builder() 
       .withTitle(R.string.no_internet_connection) 
       .withMessage(messageId) 
       .withPositiveButton(android.R.string.ok) 
       .build(); 
dialogFragment.setOnPositiveButtonClickListener(new DialogInterface.OnClickListener() { 
        @Override 
        public void onClick(DialogInterface dialog, int which) { 
         dialog.dismiss(); 
        } 
       }); 
dialogFragment.show(getSupportFragmentManager(), FRAGMENT_TAG_NO_INTERNET_CONNECTION); 

Vielleicht auf den Knopf klicken Zuhörer Einstellung direkt auf DialogFragment Instanz, anstatt sie über Bundle Argumente zu übergeben, ist nicht sicher, da die empfohlene Möglichkeit, Argumente an Fragment zu übergeben sie über Bundle Argumente übergeben.

Und ich weiß, dass die empfohlene Art und Weise mit Fragment s in Android zu kommunizieren ist Host-Aktivität zu verpflichtenCallback-Schnittstelle zu implementieren. Aber auf diese Weise ist es nicht klar, dass Aktivität diese Schnittstelle implementieren sollte, bis ClassCastException in Runtime geworfen wird. Und es macht auch starke Abhängigkeit - um es irgendwo außerhalb Aktivität zu verwenden Ich sollte die Callback Schnittstelle in Aktivität implementieren. So kann ich es nicht in Fragment verwenden s „unabhängig“ von HostAktivitäten: prepareAlertDialogFragment().show(getActivity().getSupportFragmentManager(), "tag");

Antwort

6

Von dem, was es klingt wie Sie einen Alert-Dialog haben wollen, dass es eigene Zuhörer haben kann, die auf Tastendruck-Ereignisse reagieren können (Art wie OnClickListener). Die Art, wie ich das erreicht habe, besteht darin, ein benutzerdefiniertes DialogFragment zusammen mit einem Listener zu erstellen, der Parcelable erweitert.

ConfirmOrCancelDialogFragment.java

Dies ist Sie Dialog-Implementierung. Es wird sehr ähnlich zu Fragmenten behandelt, außer der Art, wie es instanziiert wird, was durch einen statischen Methodenaufruf zu newInstance geschieht.

public class ConfirmOrCancelDialogFragment extends DialogFragment { 
    TextView tvDialogHeader, 
      tvDialogBody; 

    Button bConfirm, 
      bCancel; 

    private ConfirmOrCancelDialogListener mListener; 

    private String mTitle, 
      mBody, 
      mConfirmButton, 
      mCancelButton; 

    public ConfirmOrCancelDialogFragment() { 
    } 

    public static ConfirmOrCancelDialogFragment newInstance(String title, String body, ConfirmOrCancelDialogListener listener) { 
     ConfirmOrCancelDialogFragment fragment = new ConfirmOrCancelDialogFragment(); 
     Bundle args = new Bundle(); 
     args.putString("title", title); 
     args.putString("body", body); 
     args.putParcelable("listener", listener); 
     fragment.setArguments(args); 
     return fragment; 
    } 

    public static ConfirmOrCancelDialogFragment newInstance(String title, String body, String confirmButton, String cancelButton, ConfirmOrCancelDialogListener listener) { 
     ConfirmOrCancelDialogFragment fragment = new ConfirmOrCancelDialogFragment(); 
     Bundle args = new Bundle(); 
     args.putString("title", title); 
     args.putString("body", body); 
     args.putString("confirmButton", confirmButton); 
     args.putString("cancelButton", cancelButton); 
     args.putParcelable("listener", listener); 
     fragment.setArguments(args); 
     return fragment; 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
     View view = inflater.inflate(R.layout.dialog_confirm_or_cancel, container); 

     /* Initial Dialog Setup */ 
     getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE); // we are using a textview for the title 
     mListener = getArguments().getParcelable("listener"); 

     /* Link UI */ 
     tvDialogHeader = (TextView) view.findViewById(R.id.tvDialogHeader); 
     tvDialogBody = (TextView) view.findViewById(R.id.tvDialogBody); 
     bConfirm = (Button) view.findViewById(R.id.bConfirm); 
     bCancel = (Button) view.findViewById(R.id.bCancel); 

     /* Setup UI */ 
     mTitle = getArguments().getString("title", ""); 
     mBody = getArguments().getString("body", ""); 
     mConfirmButton = getArguments().getString("confirmButton", getResources().getString(R.string.yes_delete)); 
     mCancelButton = getArguments().getString("cancelButton", getResources().getString(R.string.no_do_not_delete)); 

     tvDialogHeader.setText(mTitle); 
     tvDialogBody.setText(mBody); 
     bConfirm.setText(mConfirmButton); 
     bCancel.setText(mCancelButton); 

     bConfirm.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       mListener.onConfirmButtonPressed(); 
       dismiss(); 
      } 
     }); 

     bCancel.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       mListener.onCancelButtonPressed(); 
       dismiss(); 
      } 
     }); 

     return view; 
    } 
} 

ConfirmOrCancelDialogListener.java

Dies ist Ihre Zuhörer Implementierung, Sie immer mehr dazu hinzufügen könnte, aber nur sicherstellen, dass es sich Parcel so kann es durch das Bündel in der newInstance Methode in ConfirmOrCancelDialogFragment gefunden geben werden .java

public interface ConfirmOrCancelDialogListener extends Parcelable { 
    void onConfirmButtonPressed(); 

    void onCancelButtonPressed(); 
} 

Anwendungsbeispiel:

Dies ist, wo die Dinge ein wenig chaotischer bekommen, als ich möchte. Da Ihr Listener Parcelable erweitert, müssen Sie auch diese Methoden überschreiben, die describeContents und writeToParcel sind. Zum Glück können sie meistens leer sein und alles funktioniert immer noch gut.

FragmentManager fm = getActivity().getSupportFragmentManager(); 
ConfirmOrCancelDialogFragment confirmOrCancelDialogFragment = ConfirmOrCancelDialogFragment.newInstance 
    (getString(R.string.header), getString(R.string.body), 
         new ConfirmOrCancelDialogListener() { 
          @Override 
          public void onConfirmButtonPressed() { 

          } 

          public void onCancelButtonPressed() { 
          } 

          @Override 
          public int describeContents() { 
           return 0; 
          } 

          @Override 
          public void writeToParcel(Parcel dest, int flags) { 
          } 
         } 
       ); 
confirmOrCancelDialogFragment.show(fm, "fragment_delete_confirmation"); 

diese Antwort nicht vollständig Frage der Weitergabe eines AlertDialogFragment in durch, aber ich glaube, wenn diese Frage so lange unbeantwortet geblieben ist, es lohnt ein Beispiel dafür, wie geben zu erreichen Aufgabe mit einem benutzerdefinierten Dialog, der scheint Ihnen ein wenig mehr Kontrolle über den Stil und die Funktionalität zu geben.

+0

benötigen Sie einen Parcelable.Creator? –

+0

Nein, Sie sollten keinen Parcelable.Creator brauchen. Der obige Code sollte für Copy-Pasta bereit sein. – CodyEngel

+0

Bitte beachten Sie, dass diese Methode Probleme verursachen kann. Aktivieren Sie in den Entwickleroptionen auf Ihren Geräten die Einstellung "Aktivitäten nicht beibehalten" und stellen Sie sicher, dass Sie beim Zurückkehren zu Ihrem Fragment, das diese Methode verwendet, nicht abstürzen. Normalerweise wird eine Ausnahme ausgelöst, weil der Listener nicht mehr im Speicher ist und es keinen Creator gibt, der ihn erneut instanziieren kann. – Kuffs

Verwandte Themen