web-dev-qa-db-de.com

Jelly Bean DatePickerDialog --- gibt es eine Möglichkeit abzubrechen?

--- Hinweis an die Moderatoren: Heute (15. Juli) habe ich bemerkt, dass jemand stand schon vor diesem Problem hier . Aber ich bin mir nicht sicher, ob es angebracht ist, dieses Duplikat zu schließen, da ich denke, dass ich das Problem viel besser erklärt habe. Ich bin mir nicht sicher, ob ich die andere Frage bearbeiten und diesen Inhalt dort einfügen soll, aber es ist mir unangenehm, die Frage einer anderen Person zu sehr zu ändern. ---

Ich habe etwas komisch hier.

Ich denke nicht, dass das Problem davon abhängt, gegen welches SDK Sie bauen. Auf die Betriebssystemversion des Geräts kommt es an.

Problem Nr. 1: Inkonsistenz standardmäßig

DatePickerDialog wurde in Jelly Bean geändert (?) und bietet jetzt nur einen Done -Button. Frühere Versionen enthielten die Schaltfläche Abbrechen. Dies kann die Benutzererfahrung beeinträchtigen (Inkonsistenz, Muskelgedächtnis aus früheren Android Versionen).

Replizieren: Erstellen Sie ein Basisprojekt. Fügen Sie dies in onCreate ein:

DatePickerDialog picker = new DatePickerDialog(
        this,
        new OnDateSetListener() {
            @Override
            public void onDateSet(DatePicker v, int y, int m, int d) {
                Log.d("Picker", "Set!");
            }
        },
        2012, 6, 15);
picker.show();

Erwartet: Eine Schaltfläche Abbrechen wird im Dialogfeld angezeigt.

Current: Eine Schaltfläche Cancel wird nicht angezeigt.

Screenshots:4.0. (OK) und 4.1.1 (möglicherweise falsch?).

Problem Nr. 2: Falsches Entlassungsverhalten

Dialog ruft den Listener auf, den er tatsächlich aufrufen soll, und ruft dann alwaysOnDateSetListener Listener auf. Wenn Sie den Vorgang abbrechen, wird die festgelegte Methode weiterhin aufgerufen, und durch Festlegen wird die Methode zweimal aufgerufen.

Replicate: Verwenden Sie den Code 1, fügen Sie jedoch den folgenden Code hinzu (dies löst jedoch nur den Code 1) visuell/Benutzeroberfläche):

picker.setButton(DialogInterface.BUTTON_NEGATIVE, "Cancel", 
        new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                Log.d("Picker", "Cancel!");
            }
        });

Erwartet:

  • Das Drücken der ZURÜCK-Taste oder das Klicken außerhalb des Dialogfelds sollte nichts bewirken .
  • Drücken Sie "Abbrechen", um Picker Cancel! zu drucken.
  • Drücken von "Set" sollte Picker Set! drucken.

Current:

  • Durch Drücken der ZURÜCK-Taste oder Klicken außerhalb des Dialogfelds wird ein Auswahlsatz gedruckt! .
  • Wenn Sie auf "Abbrechen" klicken, wird Picker Cancel! und dann Picker Set! gedruckt.
  • Durch Drücken von "Einstellen" wird Picker Set! und dann Picker Set! gedruckt.

Protokollzeilen, die das Verhalten anzeigen:

07-15 12:00:13.415: D/Picker(21000): Set!

07-15 12:00:24.860: D/Picker(21000): Cancel!
07-15 12:00:24.876: D/Picker(21000): Set!

07-15 12:00:33.696: D/Picker(21000): Set!
07-15 12:00:33.719: D/Picker(21000): Set!

Sonstige Hinweise und Kommentare

  • Es spielt keine Rolle, es um ein DatePickerFragment zu wickeln. Ich habe das Problem für Sie vereinfacht, aber ich habe es getestet.
147
davidcesarino

Anmerkung: behoben ab Lollipop , Quelle hier . Automated Klasse zur Verwendung in Clients (kompatibel mit allen Android Versionen) ebenfalls aktualisiert.

TL; DR: 1-2-3 kinderleichte Schritte für eine globale Lösung:

  1. Download this Klasse.
  2. Implementieren Sie OnDateSetListener in Ihre Aktivität (oder ändern Sie die Klasse entsprechend Ihren Anforderungen).
  3. Löst den Dialog mit diesem Code aus (in diesem Beispiel verwende ich ihn in einem Fragment):

    Bundle b = new Bundle();
    b.putInt(DatePickerDialogFragment.YEAR, 2012);
    b.putInt(DatePickerDialogFragment.MONTH, 6);
    b.putInt(DatePickerDialogFragment.DATE, 17);
    DialogFragment picker = new DatePickerDialogFragment();
    picker.setArguments(b);
    picker.show(getActivity().getSupportFragmentManager(), "frag_date_picker");
    

Und das ist alles, was es braucht! Der Grund, warum ich meine Antwort immer noch als "akzeptiert" behalte, ist, dass ich meine Lösung immer noch bevorzuge, da sie einen sehr geringen Platzbedarf hat Der Client-Code behebt das grundlegende Problem (der Listener wird in der Framework-Klasse aufgerufen), funktioniert problemlos bei Konfigurationsänderungen und leitet die Codelogik an die Standardimplementierung in früheren Android Versionen weiter, die von diesem Fehler nicht betroffen sind ( siehe Klassenquelle).

Originalantwort (aus historischen und didaktischen Gründen aufbewahrt):

Fehlerquelle

OK, es scheint in der Tat ein Fehler zu sein und jemand anderes hat ihn bereits beseitigt. Problem 348 .

Ich habe festgestellt, dass das Problem möglicherweise in DatePickerDialog.Java Liegt. Wo es heißt:

private void tryNotifyDateSet() {
    if (mCallBack != null) {
        mDatePicker.clearFocus();
        mCallBack.onDateSet(mDatePicker, mDatePicker.getYear(),
                mDatePicker.getMonth(), mDatePicker.getDayOfMonth());
    }
}

@Override
protected void onStop() {
    tryNotifyDateSet();
    super.onStop();
}

Ich denke, es hätte sein können:

@Override
protected void onStop() {
    // instead of the full tryNotifyDateSet() call:
    if (mCallBack != null) mDatePicker.clearFocus();
    super.onStop();
}

Wenn mir jetzt jemand sagen kann, wie ich Android einen Patch/Bug-Report vorschlagen kann, würde ich das gerne tun. In der Zwischenzeit schlug ich dort eine mögliche (einfache) Korrektur als angehängte Version von DatePickerDialog.Java Vor.

Konzept zur Vermeidung des Fehlers

Setzen Sie den Listener im Konstruktor auf null und erstellen Sie später Ihre eigene Schaltfläche BUTTON_POSITIVE. Das war's, Details weiter unten.

Das Problem tritt auf, weil DatePickerDialog.Java, Wie Sie in der Quelle sehen können, eine globale Variable (mCallBack) aufruft, die den im Konstruktor übergebenen Listener speichert:

    /**
 * @param context The context the dialog is to run in.
 * @param callBack How the parent is notified that the date is set.
 * @param year The initial year of the dialog.
 * @param monthOfYear The initial month of the dialog.
 * @param dayOfMonth The initial day of the dialog.
 */
public DatePickerDialog(Context context,
        OnDateSetListener callBack,
        int year,
        int monthOfYear,
        int dayOfMonth) {
    this(context, 0, callBack, year, monthOfYear, dayOfMonth);
}

    /**
 * @param context The context the dialog is to run in.
 * @param theme the theme to apply to this dialog
 * @param callBack How the parent is notified that the date is set.
 * @param year The initial year of the dialog.
 * @param monthOfYear The initial month of the dialog.
 * @param dayOfMonth The initial day of the dialog.
 */
public DatePickerDialog(Context context,
        int theme,
        OnDateSetListener callBack,
        int year,
        int monthOfYear,
        int dayOfMonth) {
    super(context, theme);

    mCallBack = callBack;
    // ... rest of the constructor.
}

Der Trick besteht also darin, einen null -Listener bereitzustellen, der als Listener gespeichert wird, und dann Ihre eigenen Schaltflächen zu rollen (unten ist der Originalcode von # 1, aktualisiert):

    DatePickerDialog picker = new DatePickerDialog(
        this,
        null, // instead of a listener
        2012, 6, 15);
    picker.setCancelable(true);
    picker.setCanceledOnTouchOutside(true);
    picker.setButton(DialogInterface.BUTTON_POSITIVE, "OK",
        new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                Log.d("Picker", "Correct behavior!");
            }
        });
    picker.setButton(DialogInterface.BUTTON_NEGATIVE, "Cancel", 
        new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                Log.d("Picker", "Cancel!");
            }
        });
picker.show();

Jetzt wird es wegen der möglichen Korrektur funktionieren, die ich oben gepostet habe.

Und da DatePickerDialog.Java Nach einem null sucht, wann immer es mCallback liest ( seit den Tagen von API 3/1.5 scheint es --- kann Honeycomb natürlich nicht überprüfen), es wird die Ausnahme nicht auslösen. Angesichts der Tatsache, dass Lollipop das Problem behoben hat, werde ich es nicht untersuchen: benutze einfach die Standardimplementierung (abgedeckt in der Klasse, die ich bereitgestellt habe).

Anfangs hatte ich Angst, die Funktion clearFocus() nicht aufzurufen, aber ich habe sie hier getestet und die Protokollzeilen waren sauber. Also ist diese Linie, die ich vorgeschlagen habe, vielleicht doch nicht nötig, aber ich weiß es nicht.

Kompatibilität mit früheren API-Levels (bearbeitet)

Wie ich im Kommentar unten gezeigt habe, war das ein Konzept, und Sie können die Klasse, die ich verwende, von meinem Google Drive-Konto herunterladen . So wie ich es verwendet habe, wird die Standardsystemimplementierung für Versionen verwendet, die nicht vom Fehler betroffen sind.

Ich habe ein paar Annahmen getroffen (Schaltflächennamen usw.), die für meine Bedürfnisse geeignet sind, weil ich den Code für Boilerplates in Client-Klassen auf ein Minimum reduzieren wollte. Vollständiges Anwendungsbeispiel:

class YourActivity extends SherlockFragmentActivity implements OnDateSetListener

// ...

Bundle b = new Bundle();
b.putInt(DatePickerDialogFragment.YEAR, 2012);
b.putInt(DatePickerDialogFragment.MONTH, 6);
b.putInt(DatePickerDialogFragment.DATE, 17);
DialogFragment picker = new DatePickerDialogFragment();
picker.setArguments(b);
picker.show(getActivity().getSupportFragmentManager(), "fragment_date_picker");
115
davidcesarino

Ich werde mein eigenes Riff zu der von David Cesarino geposteten Lösung hinzufügen, falls Sie keine Fragmente verwenden, und einen einfachen Weg suchen, dies in allen Versionen (2.1 bis 4.1) zu beheben:

public class FixedDatePickerDialog extends DatePickerDialog {
  //I use a Calendar object to initialize it, but you can revert to Y,M,D easily
  public FixedDatePickerDialog(Calendar dateToShow, Context context, OnDateSetListener callBack) {
    super(context, null, dateToShow.get(YEAR), dateToShow.get(MONTH), dateToShow.get(DAY_OF_MONTH));
    initializePicker(callBack);
  }

  public FixedDatePickerDialog(Calendar dateToShow, Context context, int theme,
    OnDateSetListener callBack) {
    super(context, theme, null, dateToShow.get(YEAR), dateToShow.get(MONTH), dateToShow.get(DAY_OF_MONTH));
    initializePicker(callBack);
  }

  private void initializePicker(final OnDateSetListener callback) {
    try {
      //If you're only using Honeycomb+ then you can just call getDatePicker() instead of using reflection
      Field pickerField = DatePickerDialog.class.getDeclaredField("mDatePicker");
      pickerField.setAccessible(true);
      final DatePicker picker = (DatePicker) pickerField.get(this);
      this.setCancelable(true);
      this.setButton(DialogInterface.BUTTON_NEGATIVE, getContext().getText(Android.R.string.cancel), (OnClickListener) null);
      this.setButton(DialogInterface.BUTTON_POSITIVE, getContext().getText(Android.R.string.ok),
          new DialogInterface.OnClickListener() {
              @Override
              public void onClick(DialogInterface dialog, int which) {
                picker.clearFocus(); //Focus must be cleared so the value change listener is called
                callback.onDateSet(picker, picker.getYear(), picker.getMonth(), picker.getDayOfMonth());
              }
          });
    } catch (Exception e) { /* Reflection probably failed*/ }
  }
}
16
dmon

Bis der Fehler behoben ist, schlage ich vor, DatePickerDialog oder TimePickerDialog nicht zu verwenden. Verwenden Sie den benutzerdefinierten AlertDialog mit dem TimePicker/DatePicker-Widget.

Ändern Sie TimePickerDialog mit;

    final TimePicker timePicker = new TimePicker(this);
    timePicker.setIs24HourView(true);
    timePicker.setCurrentHour(20);
    timePicker.setCurrentMinute(15);

    new AlertDialog.Builder(this)
            .setTitle("Test")
            .setPositiveButton(Android.R.string.ok, new OnClickListener() {

                @Override
                public void onClick(DialogInterface dialog, int which) {
                    Log.d("Picker", timePicker.getCurrentHour() + ":"
                            + timePicker.getCurrentMinute());
                }
            })
            .setNegativeButton(Android.R.string.cancel,
                    new OnClickListener() {

                        @Override
                        public void onClick(DialogInterface dialog,
                                int which) {
                            Log.d("Picker", "Cancelled!");
                        }
                    }).setView(timePicker).show();

Ändern Sie DatePickerDialog mit;

    final DatePicker datePicker = new DatePicker(this);
    datePicker.init(2012, 10, 5, null);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
        datePicker.setCalendarViewShown(false);
    }

    new AlertDialog.Builder(this)
            .setTitle("Test")
            .setPositiveButton(Android.R.string.ok, new OnClickListener() {

                @Override
                public void onClick(DialogInterface dialog, int which) {
                    Log.d("Picker", datePicker.getYear() + " "
                            + (datePicker.getMonth() + 1) + " "
                            + datePicker.getDayOfMonth());
                }
            })
            .setNegativeButton(Android.R.string.cancel,
                    new OnClickListener() {

                        @Override
                        public void onClick(DialogInterface dialog,
                                int which) {
                            Log.d("Picker", "Cancelled!");
                        }
                    }).setView(datePicker).show();
8
cirit

Der für TimePicker basiert auf der Lösung von David Cesarino, "TL; DR: 1-2-3 absolut einfache Schritte für eine globale Lösung"

TimePickerDialog bietet keine Funktionen wie DatePickerDialog.getDatePicker. Also muss OnTimeSetListener Listener angegeben werden. Um die Ähnlichkeit mit der DatePicker-Problemumgehungslösung zu erhalten, habe ich das alte mListener-Konzept beibehalten. Sie können es bei Bedarf ändern.

Anrufen und Mithören ist dieselbe wie bei der ursprünglichen Lösung. Einfach mit einbeziehen

import Android.app.TimePickerDialog;
import Android.app.TimePickerDialog.OnTimeSetListener;

elternklasse erweitern,

... implements OnDateSetListener, OnTimeSetListener

Implementieren

 @Override
 public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
 ...
 }

beispiel anrufen

    Calendar cal = Calendar.getInstance();
    int hour = cal.get(Calendar.HOUR_OF_DAY);
    int minute = cal.get(Calendar.MINUTE);


    Bundle b = new Bundle();
    b.putInt(TimePickerDialogFragment.HOUR, hour);
    b.putInt(TimePickerDialogFragment.MINUTE, minute);

    DialogFragment picker = new TimePickerDialogFragment();
    picker.setArguments(b);
    picker.show(getSupportFragmentManager(), "frag_time_picker");

(Aktualisiert um abzubrechen)

public class TimePickerDialogFragment extends DialogFragment {

    public static final String HOUR = "Hour";
    public static final String MINUTE = "Minute";

    private boolean isCancelled = false; //Added to handle cancel
    private TimePickerDialog.OnTimeSetListener mListener;

    //Added to handle parent listener
    private TimePickerDialog.OnTimeSetListener mTimeSetListener = new TimePickerDialog.OnTimeSetListener() {
        public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
            if (!isCancelled)
            {
                mListener.onTimeSet(view,hourOfDay,minute);
            }
        }
    };
    //
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        this.mListener = (TimePickerDialog.OnTimeSetListener) activity;
    }

    @Override
    public void onDetach() {
        this.mListener = null;
        super.onDetach();
    }

    @TargetApi(11)
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        Bundle b = getArguments();
        int h = b.getInt(HOUR);
        int m = b.getInt(MINUTE);

        final TimePickerDialog picker = new TimePickerDialog(getActivity(), getConstructorListener(), h, m,DateFormat.is24HourFormat(getActivity()));

        //final TimePicker timePicker = new TimePicker(getBaseContext());
        if (hasJellyBeanAndAbove()) {
            picker.setButton(DialogInterface.BUTTON_POSITIVE,
                    getActivity().getString(Android.R.string.ok),
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            isCancelled = false; //Cancel flag, used in mTimeSetListener
                        }
                    });
            picker.setButton(DialogInterface.BUTTON_NEGATIVE,
                    getActivity().getString(Android.R.string.cancel),
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            isCancelled = true; //Cancel flag, used in mTimeSetListener
                        }
                    });
        }
        return picker;
    }
    private boolean hasJellyBeanAndAbove() {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
    }

    private TimePickerDialog.OnTimeSetListener getConstructorListener() {
        return hasJellyBeanAndAbove() ? mTimeSetListener : mListener; //instead of null, mTimeSetListener is returned.
    }
}
4
Tejasvi Hegde

Für den Fall, dass jemand eine schnelle Problemumgehung wünscht, hier ist der Code, den ich verwendet habe:

public void showCustomDatePicker () {

final DatePicker mDatePicker = (DatePicker) getLayoutInflater().
        inflate(R.layout.date_picker_view, null);
//Set an initial date for the picker
final Calendar c = Calendar.getInstance();
int year = c.get(Calendar.YEAR);
int month = c.get(Calendar.MONTH);
int day = c.get(Calendar.DAY_OF_MONTH);
//Set the date now
mDatePicker.updateDate(year, month, day);

//create the dialog
AlertDialog.Builder mBuilder = new Builder(this);
//set the title
mBuilder.setTitle(getString(R.string.date_picker_title))
    //set our date picker
    .setView(mDatePicker)
    //set the buttons 
.setPositiveButton(Android.R.string.ok, new OnClickListener() {

    @Override
    public void onClick(DialogInterface dialog, int which) {
        //whatever method you choose to handle the date changes
            //the important thing to know is how to retrieve the data from the picker
        handleOnDateSet(mDatePicker.getYear(), 
                mDatePicker.getMonth(), 
                mDatePicker.getDayOfMonth());
    }
})
.setNegativeButton(Android.R.string.cancel, new OnClickListener() {

    @Override
    public void onClick(DialogInterface dialog, int which) {
        dialog.dismiss();
    }
})
//create the dialog and show it.
.create().show();

}

Dabei ist layout.date_picker_view eine einfache Layoutressource mit einem DatePicker als einzigem Element:

<!xml version="1.0" encoding="utf-8">
<DatePicker xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:id="@+id/date_picker"
Android:layout_width="fill_parent"   
Android:spinnersShown="true" 
Android:calendarViewShown="false"
Android:layout_height="fill_parent"/>

Hier ist das vollständige Tutorial falls Sie interessiert sind.

3
daniel_c05

Laut Ankur Chaudharys brillantem Antwort zum ähnlichen Problem TimePickerDialog wird es, wenn wir in onDateSet nachsehen, ob die angegebene Ansicht isShown() ist oder nicht Lösen Sie das gesamte Problem mit minimalem Aufwand, ohne den Picker zu erweitern oder nach abscheulichen Markierungen im Code zu suchen oder sogar nach der Betriebssystemversion zu suchen.

public void onDateSet(DatePicker view, int year, int month, int day) {
    if (view.isShown()) {
        // read the date here :)
    }
}

und natürlich kann das Gleiche für onTimeSet gemäß Ankur's Antwort gemacht werden

3
AbdelHady

Meine einfache Lösung. Wenn Sie möchten, dass es erneut ausgelöst wird, führen Sie einfach "resetFired" aus (sagen Sie, wenn Sie den Dialog erneut öffnen).

private class FixedDatePickerDialogListener implements DatePickerDialog.OnDateSetListener{
    private boolean fired;

    public void resetFired(){
        fired = false;
    }

    public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
        if (fired) {
            Log.i("DatePicker", "Double fire occurred.");
            return;//ignore and return.
        } 
        //put your code here to handle onDateSet
        fired = true;//first time fired 
    }
}
3
Daniel Ryan

Die Art und Weise, wie ich mit dieser Situation umgegangen bin, bestand darin, ein Flag zu verwenden und die Methoden onCancel und onDismiss zu überschreiben.

onCancel wird nur aufgerufen, wenn der Benutzer außerhalb des Dialogfelds oder der Schaltfläche "Zurück" berührt. onDismiss wird immer aufgerufen

Das Setzen eines Flags in der onCancel-Methode kann dazu beitragen, die Absicht des Benutzers in der onDismiss-Methode zu filtern: Aktion abbrechen oder Aktion ausführen. Unten ein Code, der die Idee zeigt.

public class DatePickerDialogFragment extends DialogFragment implements DatePickerDialog.OnDateSetListener {

    private boolean cancelDialog = false;
    private int year;
    private int month;
    private int day;

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        DatePickerDialog dpd = new DatePickerDialog(getActivity(), this, year, month, day);
        return dpd;
    }

    public void setDatePickerDate(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }

    @Override
    public void onCancel(DialogInterface dialog) {
        super.onCancel(dialog);
        cancelDialog = true;
    }

    @Override
    public void onDismiss(DialogInterface dialog) {
        super.onDismiss(dialog);
        if (!cancelDialog) {
          #put the code you want to execute if the user clicks the done button
        }
    }

    @Override
    public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
        setDatePickerDate(year, monthOfYear, dayOfMonth);
    }
}
2
Alvaro

Es gibt eine sehr einfache Problemumgehung, wenn Ihre Anwendung die Aktionsleiste nicht verwendet. Beachten Sie im Übrigen, dass einige Apps auf diese Funktionalität angewiesen sind, da das Abbrechen aus der Datumsauswahl eine besondere Bedeutung hat (z. B. das Löschen des Datumsfelds in eine leere Zeichenfolge, die für einige Apps eine gültige und aussagekräftige Art der Eingabe darstellt) ) und die Verwendung von Booleschen Flags, um zu verhindern, dass das Datum zweimal auf OK gesetzt wird, hilft Ihnen in diesem Fall nicht.

Re. Für die eigentliche Korrektur müssen Sie weder neue Schaltflächen noch einen eigenen Dialog erstellen. Der Punkt ist, mit beiden, den älteren Versionen von Android, den fehlerhaften (4 .) und allen zukünftigen, kompatibel zu sein, obwohl letzteres natürlich nicht sicher ist. Beachten Sie, dass in Android 2., onStop () für Android.app.Dialog führt überhaupt nichts aus und in 4. * mActionBar.setShowHideAnimationEnabled (false), was nur wichtig ist, wenn Ihre App über eine Aktionsleiste verfügt. Das von Dialog geerbte onStop () in DatePickerDialog liefert nur mDatePicker.clearFocus () (ab dem neuesten Fix für Android - Quellen 4.3), was nicht unbedingt erforderlich zu sein scheint.

Daher sollte das Ersetzen von onStop () durch eine Methode, die nichts bewirkt, in vielen Fällen Ihre App reparieren und sicherstellen, dass dies auf absehbare Zeit so bleibt. Erweitern Sie daher einfach die DatePickerDialog-Klasse mit Ihrer eigenen und überschreiben Sie onStop () mit einer Dummy-Methode. Sie müssen auch einen oder zwei Konstruktoren gemäß Ihren Anforderungen bereitstellen. Beachten Sie auch, dass Sie nicht versucht sein sollten, diese Korrektur zu übertreiben, indem Sie z. Wenn Sie versuchen, etwas direkt mit der Aktivitätsleiste zu tun, wird Ihre Kompatibilität nur auf die neuesten Versionen von Android beschränkt. Beachten Sie auch, dass es schön wäre, den Super für DatePickers onStop () aufrufen zu können, da der Fehler nur im onStop () in DatePickerDialog selbst, nicht jedoch in der Superklasse von DatePickerDialog vorliegt. Dies würde jedoch erfordern, dass Sie super.super.onStop () aus Ihrer benutzerdefinierten Klasse aufrufen, was Java nicht zulässt, da dies gegen die Kapselungsphilosophie verstößt :) Unten ist meine kleine Klasse, die ich früher verwendet habe Verride DatePickerDialog. Ich hoffe, dieser Kommentar wäre für jemanden nützlich. Wojtek Jarosz

public class myDatePickerDialog extends DatePickerDialog {

public myDatePickerDialog(Context context, OnDateSetListener callBack, int year, int monthOfYear, int dayOfMonth) {
    super(context, callBack, year, monthOfYear, dayOfMonth);
}

@Override
protected void onStop() {
    // Replacing tryNotifyDateSet() with nothing - this is a workaround for Android bug https://Android-review.googlesource.com/#/c/61270/A

    // Would also like to clear focus, but we cannot get at the private members, so we do nothing.  It seems to do no harm...
    // mDatePicker.clearFocus();

    // Now we would like to call super on onStop(), but actually what we would mean is super.super, because
    // it is super.onStop() that we are trying NOT to run, because it is buggy.  However, doing such a thing
    // in Java is not allowed, as it goes against the philosophy of encapsulation (the Creators never thought
    // that we might have to patch parent classes from the bottom up :)
    // However, we do not lose much by doing nothing at all, because in Android 2.* onStop() in androd.app.Dialog //actually
    // does nothing and in 4.* it does:
    //      if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(false); 
    // which is not essential for us here because we use no action bar... QED
    // So we do nothing and we intend to keep this workaround forever because of users with older devices, who might
    // run Android 4.1 - 4.3 for some time to come, even if the bug is fixed in later versions of Android.
}   

}

1
Wojtek Jarosz

Meine Arbeitsversion mit ClearButton unter Verwendung von Lambda Expressions:

public class DatePickerFragment extends DialogFragment {
    private OnDateSelectListener dateSelectListener;
    private OnDateClearListener dateClearListener;

    public void setDateSelectListener(OnDateSelectListener dateSelectListener) {
        this.dateSelectListener = dateSelectListener;
    }

    public void setDateClearListener(OnDateClearListener dateClearListener) {
        this.dateClearListener = dateClearListener;
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        // Use the current date as the default date in the picker
        final Calendar c = Calendar.getInstance();
        int year = c.get(Calendar.YEAR);
        int month = c.get(Calendar.MONTH);
        int day = c.get(Calendar.DAY_OF_MONTH);

        // Create a new instance of DatePickerDialog and return it
        DatePickerDialog dialog = new DatePickerDialog(getActivity(), null, year, month, day);
        dialog.setCancelable(true);
        dialog.setCanceledOnTouchOutside(true);
        dialog.setTitle("Select Date");
        dialog.setButton(BUTTON_POSITIVE, ("Done"), (dialog1, which) -> {
            DatePicker dp = dialog.getDatePicker();
            dialog.dismiss();
            dateSelectListener.onDateSelect(dp.getYear(), dp.getMonth(), dp.getDayOfMonth());
        });
        dialog.setButton(BUTTON_NEUTRAL, ("Clear"), (dialog1, which) -> {
            dialog.dismiss();
            dateClearListener.onDateClear();
        });
        dialog.setButton(BUTTON_NEGATIVE, ("Cancel"), (dialog1, which) -> {
            if (which == DialogInterface.BUTTON_NEGATIVE) {
                dialog.cancel();
            }
        });
        dialog.getDatePicker().setCalendarViewShown(false);
        return dialog;
    }


    public interface OnDateClearListener {
        void onDateClear();
    }

    public interface OnDateSelectListener {
        void onDateSelect(int year, int monthOfYear, int dayOfMonth);
    }
}
0

Hier ist meine Workaround-Klasse für DatePickerDialog beim Abbrechen und beim Verlassen mit der Zurück-Taste. Kopieren und Verwenden im Stil von DatePickerDialog (Da der Listener statusbehaftet ist, müssen wir bei Verwendung eine neue Instanz erstellen. Andernfalls wird mehr Code benötigt, damit dies funktioniert.)

Verwenden:

new FixedDatePickerDialog(this,
            new FixedOnDateSetListener() {

                @Override
                public void onDateSet(DatePicker view, int year,
                        int monthOfYear, int dayOfMonth) {
                    if (isOkSelected()) {
                        // when DONE button is clicked
                    }
                }

            }, year, month, day).show();

Klasse:

public class FixedDatePickerDialog extends DatePickerDialog {
private final FixedOnDateSetListener fixedCallback;
public FixedDatePickerDialog(Context context,
        FixedOnDateSetListener callBack, int year, int monthOfYear,
        int dayOfMonth) {
    super(context, callBack, year, monthOfYear, dayOfMonth);
    fixedCallback = callBack;
    this.setButton(DialogInterface.BUTTON_NEGATIVE,
            context.getString(R.string.cancel), this);
    this.setButton(DialogInterface.BUTTON_POSITIVE,
            context.getString(R.string.done), this);
}

@Override
public void onClick(DialogInterface dialog, int which) {
    if (which == BUTTON_POSITIVE) {
        fixedCallback.setOkSelected(true);
    } else {
        fixedCallback.setOkSelected(false);
    }
    super.onClick(dialog, which);
}

public abstract static class FixedOnDateSetListener implements
        OnDateSetListener {
    private boolean okSelected = false;

    @Override
    abstract public void onDateSet(DatePicker view, int year,
            int monthOfYear, int dayOfMonth);

    public void setOkSelected(boolean okSelected) {
        this.okSelected = okSelected;
    }

    public boolean isOkSelected() {
        return okSelected;
    }
}

}

0
Loc Phan


Probieren Sie die folgenden Konzepte aus.

DatePickerDialog picker = new DatePickerDialog(
        this,
        new OnDateSetListener() {
            @Override
            public void onDateSet(DatePicker v, int y, int m, int d) {
                Log.d("Picker", "Set!");
            }
        },
        2012, 6, 15);
picker.show();


Die onDateSet () -Methode ruft zweimal auf (wenn Sie den Emulator einchecken. Sie ruft zweimal auf. Wenn Sie ein echtes Gerät verwenden, wird der Aufruf einmal korrekt ausgeführt. Wenn Sie den Emulator verwenden, verwenden Sie den counter.if you are Wenn Sie in einem realen Gerät arbeiten, ignorieren Sie die Zählervariable. Wenn Sie in einem realen Gerät arbeiten, funktioniert es für mich.)
wenn der Benutzer auf die Schaltfläche in DatePickerDialog klickt.
Dazu sollten Sie einen Zählerwert beibehalten und nichts tun, wenn die Motte das erste Mal aufruft, und die Operation ausführen, wenn die Methode das zweite Mal aufruft.
Lesen Sie die folgenden Codierungsausschnitte

   static int counter=0;       //Counter will be declared globally.

    DatePickerDialog picker = new DatePickerDialog(
            this,
            new OnDateSetListener() {
                @Override
                public void onDateSet(DatePicker v, int y, int m, int d) {

                   counter++;
                   if(counter==1) return;
                   counter=0;
                   //Do the operations here

                }
            },
            2012, 6, 15);
    picker.show();



Für das Abbrechen des Datepicker-Dilalogs funktioniert es für mich. Für den Emulator funktioniert es nicht

DialogInterface.OnClickListener dialogOnClickListener=new DialogInterface.OnClickListener()
        {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                // TODO Auto-generated method stub

                if(which==Dialog.BUTTON_NEGATIVE)
                {
                    Log.i(tagName, "dialog negative button clicked");
                    dialog.dismiss();
                }

            }

        };

        mDatePickerDialog.setButton(Dialog.BUTTON_NEGATIVE, "Cancel", dialogOnClickListener);


Es funktioniert für mich für ein echtes Gerät. Aber für den Emulator funktioniert es nicht richtig. Ich denke, es ist ein Android Emulator-Fehler.

0
SIVAKUMAR.J

Sie können onCancel () überschreiben und setOnDismissListener () verwenden, um negative Benutzeraktionen zu erkennen. Und mit einem DatePickerDialog.BUTTON_POSITIVE wissen Sie, dass der Benutzer ein neues Datum festlegen möchte.

 DatePickerDialog mDPD = new DatePickerDialog(
                      getActivity(), mOnDateSetListener, mYear, mMonth, mDay);
 mDPD.setOnCancelListener(new OnCancelListener() {
    @Override
    public void onCancel(DialogInterface dialog) {
        // do something onCancek
        setDate = false;
    }
 });

 mDPD.setOnDismissListener(new OnDismissListener() {
    @Override
    public void onDismiss(DialogInterface arg0) {
        // do something onDismiss
        setDate = false;
    }
});

mDPD.setButton(DatePickerDialog.BUTTON_POSITIVE, "Finish", new DatePickerDialog.OnClickListener() {

    @Override
    public void onClick(DialogInterface dialog, int which) {
        // user set new date
        setDate = true;
    }
});

dann auf setDate prüfen:

public void onDateSet(DatePicker view, int year, int month, int day) {
    if(setDate){
        //do something with new date
    }
}
0
Markus Rubey

Ich mochte die obige Antwort von David Cesarino, wollte aber etwas, das den kaputten Dialog nicht ersetzen kann und das in jedem Dialog funktioniert, in dem Abbrechen/falsches Abbrechen-Verhalten vorliegen könnte. Hier sind abgeleitete Klassen für DatePickerDialog/TimePickerDialog, die als Drop-In-Ersetzungen funktionieren sollten. Dies sind keine benutzerdefinierten Ansichten. Es wird das Systemdialogfeld verwendet, das Verhalten der Abbrechen-/Zurück-Schaltfläche wird jedoch so geändert, dass es wie erwartet funktioniert.

Dies sollte auf API Level 3 und höher funktionieren. Also im Grunde jede Version von Android (Ich habe es auf Jellybean und Lollipop speziell getestet).

DatePickerDialog:

package snappy_company_name_here;

import Android.content.Context;
import Android.content.DialogInterface;
import Android.widget.DatePicker;

/**
 * This is a modified version of DatePickerDialog that correctly handles cancellation behavior since it's broken on jellybean and
 * KitKat date pickers.
 *
 * Here is the bug: http://code.google.com/p/Android/issues/detail?id=34833
 * Here is an SO post with a bunch of details: http://stackoverflow.com/questions/11444238/jelly-bean-datepickerdialog-is-there-a-way-to-cancel
 *
 * @author stuckj, created on 5/5/15.
 */
public class DatePickerDialog extends Android.app.DatePickerDialog implements DialogInterface.OnClickListener
{
    final CallbackHelper callbackHelper;

    // NOTE: Must be static since we're using it in a super constructor call. Which is annoying, but necessary
    private static class CallbackHelper implements OnDateSetListener
    {
        private final OnDateSetListener callBack;
        private boolean dialogButtonPressHandled = false; // To prevent setting the date when the dialog is dismissed...

        // NOTE: Must be static since we're using it in a super constructor call. Which is annoying, but necessary
        public CallbackHelper(final OnDateSetListener callBack)
        {
            this.callBack = callBack;
        }

        @Override
        public void onDateSet(final DatePicker view, final int year, final int monthOfYear, final int dayOfMonth)
        {
            if (!dialogButtonPressHandled && (callBack != null))
            {
                callBack.onDateSet(view, year, monthOfYear, dayOfMonth);
            }
        }
    }

    /**
     * Sets the positive and negative buttons to use the dialog callbacks we define.
     */
    private void setButtons(final Context context)
    {
        setButton(DialogInterface.BUTTON_NEGATIVE, context.getString(Android.R.string.cancel), this);
        setButton(DialogInterface.BUTTON_POSITIVE, context.getString(Android.R.string.ok), this);
    }

    @Override
    public void onClick(final DialogInterface dialog, final int which)
    {
        // ONLY call the super method in the positive case...
        if (which == DialogInterface.BUTTON_POSITIVE)
        {
            super.onClick(dialog, which);
        }

        callbackHelper.dialogButtonPressHandled = true;
    }

    @Override
    public void onBackPressed()
    {
        getButton(DialogInterface.BUTTON_NEGATIVE).performClick();
    }

    // Need this so we can both pass callbackHelper to the super class and save it off as a variable.
    private DatePickerDialog(final Context context,
                             final OnDateSetListener callBack,
                             final int year,
                             final int monthOfYear,
                             final int dayOfMonth,
                             final CallbackHelper callbackHelper)
    {
        super(context, callbackHelper, year, monthOfYear, dayOfMonth);
        this.callbackHelper = callbackHelper;
        setButtons(context);
    }

    /**
     * @param context The context the dialog is to run in.
     * @param callBack How the parent is notified that the date is set.
     * @param year The initial year of the dialog.
     * @param monthOfYear The initial month of the dialog.
     * @param dayOfMonth The initial day of the dialog.
     */
    public DatePickerDialog(final Context context,
                            final OnDateSetListener callBack,
                            final int year,
                            final int monthOfYear,
                            final int dayOfMonth)
    {
        this(context, callBack, year, monthOfYear, dayOfMonth, new CallbackHelper(callBack));
    }

    // Need this so we can both pass callbackHelper to the super class and save it off as a variable.
    private DatePickerDialog(final Context context, final int theme, final OnDateSetListener listener, final int year,
                             final int monthOfYear, final int dayOfMonth, final CallbackHelper callbackHelper)
    {
        super(context, theme, callbackHelper, year, monthOfYear, dayOfMonth);
        this.callbackHelper = callbackHelper;
        setButtons(context);
    }

    /**
     * @param context The context the dialog is to run in.
     * @param theme the theme to apply to this dialog
     * @param listener How the parent is notified that the date is set.
     * @param year The initial year of the dialog.
     * @param monthOfYear The initial month of the dialog.
     * @param dayOfMonth The initial day of the dialog.
     */
    public DatePickerDialog(final Context context, final int theme, final OnDateSetListener listener, final int year,
                            final int monthOfYear, final int dayOfMonth)
    {
        this(context, theme, listener, year, monthOfYear, dayOfMonth, new CallbackHelper(listener));
    }
}

TimePickerDialog:

package snappy_company_name_here;

import Android.content.Context;
import Android.content.DialogInterface;
import Android.widget.TimePicker;

/**
 * This is a modified version of TimePickerDialog that correctly handles cancellation behavior since it's broken on jellybean and
 * KitKat date pickers.
 *
 * Here is the bug: http://code.google.com/p/Android/issues/detail?id=34833
 * Here is an SO post with a bunch of details: http://stackoverflow.com/questions/11444238/jelly-bean-datepickerdialog-is-there-a-way-to-cancel
 *
 * @author stuckj, created on 5/5/15.
 */
public class TimePickerDialog extends Android.app.TimePickerDialog implements DialogInterface.OnClickListener
{
    final CallbackHelper callbackHelper;

    // NOTE: Must be static since we're using it in a super constructor call. Which is annoying, but necessary
    private static class CallbackHelper implements OnTimeSetListener
    {
        private final OnTimeSetListener callBack;
        private boolean dialogButtonPressHandled = false; // To prevent setting the date when the dialog is dismissed...

        // NOTE: Must be static since we're using it in a super constructor call. Which is annoying, but necessary
        public CallbackHelper(final OnTimeSetListener callBack)
        {
            this.callBack = callBack;
        }

        @Override
        public void onTimeSet(final TimePicker view, final int hourOfDay, final int minute)
        {
            if (!dialogButtonPressHandled && (callBack != null))
            {
                callBack.onTimeSet(view, hourOfDay, minute);
            }
        }
    }

    /**
     * Sets the positive and negative buttons to use the dialog callbacks we define.
     */
    private void setButtons(final Context context)
    {
        setButton(DialogInterface.BUTTON_NEGATIVE, context.getString(Android.R.string.cancel), this);
        setButton(DialogInterface.BUTTON_POSITIVE, context.getString(Android.R.string.ok), this);
    }

    @Override
    public void onClick(final DialogInterface dialog, final int which)
    {
        // ONLY call the super method in the positive case...
        if (which == DialogInterface.BUTTON_POSITIVE)
        {
            super.onClick(dialog, which);
        }

        callbackHelper.dialogButtonPressHandled = true;
    }

    @Override
    public void onBackPressed()
    {
        getButton(DialogInterface.BUTTON_NEGATIVE).performClick();
    }

    // Need this so we can both pass callbackHelper to the super class and save it off as a variable.
    private  TimePickerDialog(final Context context,
                              final OnTimeSetListener callBack,
                              final int hourOfDay, final int minute, final boolean is24HourView, final CallbackHelper callbackHelper)
    {
        super(context, callbackHelper, hourOfDay, minute, is24HourView);
        this.callbackHelper = callbackHelper;
        setButtons(context);
    }

    /**
     * @param context Parent.
     * @param callBack How parent is notified.
     * @param hourOfDay The initial hour.
     * @param minute The initial minute.
     * @param is24HourView Whether this is a 24 hour view, or AM/PM.
     */
    public TimePickerDialog(final Context context,
                            final OnTimeSetListener callBack,
                            final int hourOfDay, final int minute, final boolean is24HourView)
    {
        this(context, callBack, hourOfDay, minute, is24HourView, new CallbackHelper(callBack));
    }

    // Need this so we can both pass callbackHelper to the super class and save it off as a variable.
    private TimePickerDialog(final Context context, final int theme, final OnTimeSetListener callBack, final int hourOfDay,
                            final int minute, final boolean is24HourView, final CallbackHelper callbackHelper)
    {
        super(context, theme, callbackHelper, hourOfDay, minute, is24HourView);
        this.callbackHelper = callbackHelper;
        setButtons(context);
    }

    /**
     * @param context Parent.
     * @param theme the theme to apply to this dialog
     * @param callBack How parent is notified.
     * @param hourOfDay The initial hour.
     * @param minute The initial minute.
     * @param is24HourView Whether this is a 24 hour view, or AM/PM.
     */
    public TimePickerDialog(final Context context, final int theme, final OnTimeSetListener callBack, final int hourOfDay,
                            final int minute, final boolean is24HourView)
    {
        this(context, theme, callBack, hourOfDay, minute, is24HourView, new CallbackHelper(callBack));
    }
}
0
stuckj

Eine einfache Lösung wäre, einen Booleschen Wert zu verwenden, um den zweiten Lauf zu überspringen

boolean isShow = false; // define global variable


// when showing time picker
TimePickerDialog timeDlg = new TimePickerDialog( this, new OnTimeSetListener()
            {

                @Override
                public void onTimeSet( TimePicker view, int hourOfDay, int minute )
                {
                    if ( isShow )
                    {
                        isShow = false;
                        // your code
                    }

                }
            }, 8, 30, false );

timeDlg.setButton( TimePickerDialog.BUTTON_NEGATIVE, "Cancel", new DialogInterface.OnClickListener()
            {
                @Override
                public void onClick( DialogInterface dialog, int which )
                {
                    isShow = false;
                }
            } );
timeDlg.setButton( TimePickerDialog.BUTTON_POSITIVE, "Set", new DialogInterface.OnClickListener()
            {
                @Override
                public void onClick( DialogInterface dialog, int which )
                {
                    isShow = true;
                }
            } );

timeDlg.show();
0
chamikaw

Ich benutze Datumsauswahl, Zeitauswahl und Zahlenauswahl. Die Nummernwähler rufen immer dann onValueChanged auf, wenn der Benutzer eine Nummer auswählt, bevor der Picker entlassen wird. Daher hatte ich bereits die folgende Struktur, um etwas mit dem Wert zu tun, nur wenn der Picker entlassen wird:

public int interimValue;
public int finalValue;

public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
    this.interimValue = newVal;
}

public void onDismiss(DialogInterface dialog) {
    super.onDismiss(dialog);
    this.finalValue = this.interimValue;
}

Ich habe dies erweitert, um benutzerdefinierte onClickListener für meine Schaltflächen festzulegen, mit einem Argument, um zu sehen, auf welche Schaltfläche geklickt wurde. Jetzt kann ich überprüfen, welche Taste gedrückt wurde, bevor ich meinen endgültigen Wert einstellte:

public int interimValue;
public int finalValue;
public boolean saveButtonClicked;

public void setup() {
    picker.setButton(DialogInterface.BUTTON_POSITIVE, getString(R.string.BUTTON_SAVE), new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int which) {
            picker.onClick(dialog, which); // added for Android 5.0
            onButtonClicked(true);
        }
    });
    picker.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.BUTTON_CANCEL), new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int which) {
            picker.onClick(dialog, which); // added for Android 5.0
            onButtonClicked(false);
        }
    });
}

public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
    this.interimValue = newVal;
}

public void onButtonClicked(boolean save) {
    this.saveButtonClicked = save;
}

public void onDismiss(DialogInterface dialog) {
    super.onDismiss(dialog);
    if (this.saveButtonClicked) {
        // save
        this.finalValue = this.interimValue;
    } else {
        // cancel
    }
}

Und dann habe ich das erweitert, um mit den Datums- und Zeittypen für Datums- und Zeitwähler sowie dem Int-Typ für Zahlenwähler zu arbeiten.

Ich habe dies gepostet, weil ich dachte, es sei einfacher als einige der oben genannten Lösungen, aber jetzt, wo ich den gesamten Code eingefügt habe, ist es wohl nicht viel einfacher! Aber es passte gut in die Struktur, die ich schon hatte.

pdate für Lollipop: Anscheinend tritt dieser Fehler nicht auf allen Geräten auf Android 4.1-4.4), da ich einige Berichte von Benutzern erhalten habe, deren Datums- und Uhrzeitauswahl nicht möglich war. ' t Aufrufen der Rückrufe onDateSet und onTimeSet. Und der Fehler wurde offiziell in Android 5.0 behoben. Mein Ansatz funktionierte nur auf Geräten, auf denen der Fehler vorhanden ist, da meine benutzerdefinierten Schaltflächen den onClick des Dialogfelds nicht aufgerufen haben Handler, der einzige Ort, an dem onDateSet und onTimeSet aufgerufen werden, wenn der Fehler nicht vorhanden ist. Ich habe den obigen Code aktualisiert, um den onClick-Befehl des Dialogfelds aufzurufen. Jetzt funktioniert es, ob der Fehler vorhanden ist oder nicht.

0
arlomedia

Nachdem ich einige der hier veröffentlichten Vorschläge getestet habe, halte ich diese Lösung für die einfachste. Ich übergebe "null" als Listener im DatePickerDialog-Konstruktor, und wenn ich dann auf die Schaltfläche "OK" klicke, rufe ich meinen onDateSearchSetListener auf:

datePickerDialog = new DatePickerDialog(getContext(), null, dateSearch.get(Calendar.YEAR), dateSearch.get(Calendar.MONTH), dateSearch.get(Calendar.DAY_OF_MONTH));
    datePickerDialog.setCancelable(false);
    datePickerDialog.setButton(DialogInterface.BUTTON_POSITIVE, getString(R.string.dialog_ok), new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            Log.d("Debug", "Correct");
            onDateSearchSetListener.onDateSet(datePickerDialog.getDatePicker(), datePickerDialog.getDatePicker().getYear(), datePickerDialog.getDatePicker().getMonth(), datePickerDialog.getDatePicker().getDayOfMonth());
        }
    });
    datePickerDialog.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.dialog_cancel), new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            Log.d("Debug", "Cancel");
            dialog.dismiss();
        }
    });
0
Birk Bonnicksen

Für TimePickerDialog kann die Problemumgehung wie folgt aussehen:

TimePickerDialog createTimePickerDialog(Context context, int themeResId, TimePickerDialog.OnTimeSetListener orignalListener,
                                                         int hourOfDay, int minute, boolean is24HourView) {
        class KitKatTimeSetListener implements TimePickerDialog.OnTimeSetListener {
            private int hour;
            private int minute;

            private KitKatTimeSetListener() {
            }

            @Override
            public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
                this.hour = hourOfDay;
                this.minute = minute;
            }

            private int getHour() { return hour; }
            private int getMinute() {return minute; }
        };

        KitKatTimeSetListener kitkatTimeSetListener = new KitKatTimeSetListener();
        TimePickerDialog timePickerDialog = new TimePickerDialog(context, themeResId, kitkatTimeSetListener, hourOfDay, minute, is24HourView);

        timePickerDialog.setButton(DialogInterface.BUTTON_POSITIVE, context.getString(Android.R.string.ok), (dialog, which) -> {
            timePickerDialog.onClick(timePickerDialog, DialogInterface.BUTTON_POSITIVE);
            orignalListener.onTimeSet(new TimePicker(context), kitkatTimeSetListener.getHour(), kitkatTimeSetListener.getMinute());
            dialog.cancel();
        });
        timePickerDialog.setButton(DialogInterface.BUTTON_NEGATIVE, context.getString(Android.R.string.cancel), (dialog, which) -> {
            dialog.cancel();
        });

        return timePickerDialog;
    }

Ich delegiere alle Ereignisse an den Wrapper KitKatSetTimeListener und feuere nur dann auf den ursprünglichen OnTimeSetListener zurück, wenn auf BUTTON_POSITIVE geklickt wird.

0
southerton