Jelly Bean DatePickerDialog - iptal etmenin bir yolu var mı?


148

--- Moderatörler için not: Bugün (15 Temmuz), birisinin burada bu problemle karşılaştığını fark ettim . Ama meselenin daha iyi bir açıklamasını sağladığımı düşündüğüm için bunu bir kopya olarak kapatmanın uygun olup olmadığından emin değilim. Diğer soruyu düzenlemem ve bu içeriği buraya yapıştırmam gerekip gerekmediğinden emin değilim, ama başka birinin sorusunu çok fazla değiştirmekten rahat değilim.---

Garip bir şeyim varBurada var.

Sorunun hangi SDK'ya karşı oluşturduğunuza bağlı olduğunu düşünmüyorum. Önemli olan cihaz işletim sistemi sürümü.

Sorun # 1: Varsayılan olarak tutarsızlık

DatePickerDialogJelly Bean'de değiştirildi (?) ve şimdi yalnızca Bitti düğmesi sağlıyor. Önceki sürümlerde bir İptal düğmesi vardı ve bu kullanıcı deneyimini etkileyebilir (tutarsızlık, önceki Android sürümlerindeki kas belleği).

Çoğalt: Temel bir proje oluşturun. Şunu koyunonCreate:

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

Beklenen: İletişim kutusunda görünmesi içinbir İptal düğmesi.

Akım: Bir İptal düğmesi görünmez.

Ekran görüntüleri: 4.0.3 (Tamam) ve 4.1.1 (muhtemelen yanlış mı?).

Sorun # 2: Yanlış davranma davranışı

İletişim kutusu, gerçekten dinlemesi gereken dinleyiciyi arar ve her zamanOnDateSetListener dinleyiciyi arar . İptal işlemi hala ayarlanan yöntemi çağırır ve ayarlanması yöntemi iki kez çağırır.

Çoğaltma: # 1 kod kullanın, ancak aşağıya kod ekleyin (bu # 1 çözdüğünü göreceksiniz, ancak yalnızca görsel olarak / UI):

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

Beklenen:

  • GERİ tuşuna basmak veya iletişim kutusunun dışına tıklamak hiçbir şey yapmaz .
  • "İptal" düğmesine basmak Seçici İptali yazdırmalıdır !.
  • "Set" tuşuna basıldığında, Seçici Seti yazdırılmalıdır ! .

Güncel:

  • BACK tuşuna basıldığında veya iletişim kutusunun dışına tıklandığında Picker Set!.
  • "İptal" düğmesine basıldığında Seçici İptal! ve daha sonra Seçici Seti!.
  • "Ayarla" düğmesine basıldığında Seçici Seti yazdırılır ! ve daha sonra Seçici Seti! .

Davranışı gösteren günlük satırları:

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!

Diğer notlar ve yorumlar

  • Etrafına sarmak DatePickerFragmentönemli değil. Sorunu sizin için basitleştirdim, ama test ettim.

Tebrikler, Android'de bir hata buldunuz. Buradan rapor edebilirsiniz .
Michael Hampton

1
Çok iyi yazılmış hata raporu. Ben kodu çalıştırmak test etmek zorunda kalmadan tamamen anlayabiliyorum.
Cheok Yan Cheng

6
Herkesi bu konuyu oylamaya çağırıyorum! Sayı 34833
Bradley

Diyalogun dışına dokunduğunuzda devre dışı bırakılmış gibi davranmak için düğme işlevini geçersiz kılamaz mısınız?
Karthik Balakrishnan

2
Böcek 2 yıl sonra hala açık ... inanılmaz.
erdomester

Yanıtlar:


115

Not: Lollipop'un olarak düzeltildi , burada kaynak . İstemcilerde kullanım için otomatik sınıf (tüm Android sürümleriyle uyumlu) da güncellendi.

TL; DR: Küresel bir çözüm için 1-2-3 ölü kolay adım:

  1. Bunu indir sınıfı .
  2. uygulamak OnDateSetListener için aktivitesinde (veya ihtiyaçlarınıza göre sınıfını değiştirin).
  3. Bu kodla iletişim kutusunu tetikleyin (bu örnekte, a içinde kullanıyorum 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");

Ve tüm gereken bu!Cevabımı hala "kabul edilmiş" olarak tutmamın nedeni, müşteri kodunda çok az yer kapladığı için çözümümü tercih etmem, temel sorunu (çerçeve sınıfında çağrılan dinleyici) ele alması, yapılandırma değişikliklerinde iyi çalışmasıdır. kod mantığını bu hatadan rahatsız olmayan önceki Android sürümlerinde varsayılan uygulamaya yönlendirir (sınıf kaynağına bakın).

Orijinal cevap (tarihsel ve didaktik nedenlerle saklanır):

Hata kaynağı

Tamam, gerçekten bir hata gibi görünüyor ve başka biri zaten doldurdu. Sayı 34833 .

Sorunun muhtemelen içinde olduğunu gördüm DatePickerDialog.java. Nerede okuyor:

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

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

Sanırım bu olabilirdi:

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

Birisi bana Android'e nasıl yama / hata raporu önerebileceğimi söyleyebilirse memnun olurum. Bu arada, DatePickerDialog.javaoradaki Sayıda ekli bir sürüm olarak olası bir düzeltme (basit) önerdim.

Hata önlemek için kavram

Dinleyiciyi nullyapıcıda olarak ayarlayın ve BUTTON_POSITIVEdaha sonra kendi düğmenizi oluşturun . İşte bu, detaylar aşağıda.

Sorun DatePickerDialog.java, kaynakta görebileceğiniz gibi mCallBack, yapıcıda iletilen dinleyiciyi depolayan bir global değişkeni ( ) çağırdığı için oluşur :

    /**
 * @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.
}

Bu nedenle, püf noktası, bir nulldinleyicinin dinleyici olarak saklanmasını sağlamak ve ardından kendi düğme setinizi yuvarlamaktır (aşağıda güncellenen orijinal kod 1 numaradır ):

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

Şimdi yukarıda gönderdiğim olası düzeltme nedeniyle işe yarayacak.

Ve bu yana DatePickerDialog.javabir denetler nullokur zaman mCallback( API günlerinden beri 3 / 1,5 öyle görünüyor --- elbette Honeycomb kontrol edemez), bu durum tetiklemez. Lollipop'un sorunu düzelttiği düşünüldüğünde, buna bakmayacağım: sadece varsayılan uygulamayı kullanın (sağladığım sınıfta kapsanan).

İlk başta ben aramaktan korkuyordum clearFocus(), ama burada test ettim ve Log hatları temizdi. Sonuçta önerdiğim bu çizgi bile gerekli olmayabilir, ama bilmiyorum.

Önceki API düzeyleriyle uyumluluk (düzenlendi)

Aşağıdaki açıklamaya işaret ettiğim gibi, bu bir kavramdı ve kullandığım sınıfı Google Drive hesabımdan indirebilirsiniz . Kullandığım şekilde, varsayılan sistem uygulaması hatadan etkilenmeyen sürümlerde kullanılır.

Istemci sınıflarında ortak kodunu en aza indirmek istedim çünkü benim ihtiyaçları için uygun birkaç varsayımlar (düğme adları vb) aldı. Tam kullanım örneği:

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

11
Araştırmada harika iş! Gerekli olduğu için üzgün, ama yine de harika.
CommonsWare

1
Çok hoş! Metin alanlarını güncelleme ve doğru geri aramalar çağırıyor / çağırmıyor bu konuda kafamı duvara çekiç oldum. Teşekkür ederim! Önerilen geçici çözümün "gelecek kanıtı" olup olmadığını veya hata giderildiğinde sorunlara neden olacağını düşünüyorsanız, merak ediyorum.
span

1
@RomainGuidoux sonunda güncellenmiş cevaba bakın. Bağlantıdaki sınıf, sadece jöle fasulyesinde bu yöntemi çağıracak akıllılara sahiptir. Aşağıdaki herhangi bir şeyde bunu atlar ve varsayılan sistem uygulamasını kullanır, sistem çağrısını ondateset için etkinliğinize yönlendirir. Sadece jöle fasulyesinde geri çağrıyı yönlendirmeden önce ek hatalar (hatadan kaçınma) alır ve bu petek + yöntemini çağırmayı içerir. Ama yine, sadece JB'de.
davidcsb

1
Burada harika bir çalışma. Bu sorunun ne kadar saçma olduğuna dair kelimelerim yok.
Bill Phillips

5
TimePickerDialog'a ne dersiniz? TimePickerDialog bir getTimePicker () yok gibi görünüyor
lokoko

16

Fragments kullanmamanız durumunda David Cesarino'nun yayınladığı çözüme kendi riff'imi ekleyeceğim ve tüm sürümlerde (2.1'den 4.1'e) düzeltmenin kolay bir yolunu istiyorum:

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*/ }
  }
}

Sadece hatırlamak: Eğer düğme isimlerini tamam ve iptal etmek için kablo kullanıyorsanız, muhtemelen kullanıcının yerine standart android.R.string.okve android.R.string.cancelalanları kullanmak daha iyidir . Ve cevap için teşekkürler.
davidcsb

Ah, güzel, Tamam ve İptal metni sağladıklarını fark etmedim. Teşekkürler!
17'de dmon

super'de nullpointer istisnası alma (bağlam, tema, null, dateToShow.get (YEAR), dateToShow.get (MONTH), dateToShow.get (DAY_OF_MONTH));
Kishore

Hata ... boş dateToShowmu geçiyorsun ? Orada diğer null aslında "düzeltme" yani orada olmalıdır. Hangi versiyondasın?
dmon

Hangisi importiçin olduğunu bana söyler misin Field? 6 seçeneğim var ve hiçbiri işe yaramadı.
Adil Malik

8

Hata düzeltilene kadar DatePickerDialog veya TimePickerDialog kullanmamanızı öneririm. TimePicker / DatePicker widget'ıyla özel yapılmış AlertDialog kullanın;

TimePickerDialog'u;

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

DatePickerDialog ile;

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

4

David Cesarino'nun çözümüne dayanan TimePicker için "TL; DR: küresel bir çözüm için 1-2-3 ölü kolay adım"

TimePickerDialog, DatePickerDialog.getDatePicker gibi işlevsellik sağlamaz. Bu nedenle, OnTimeSetListener dinleyicisi sağlanmalıdır. DatePicker geçici çözümüyle benzerliği korumak için eski mListener konseptini korudum. Gerekirse değiştirebilirsiniz.

Arama ve Dinleyici orijinal çözümle aynıdır. Sadece dahil et

import android.app.TimePickerDialog;
import android.app.TimePickerDialog.OnTimeSetListener;

ebeveyn sınıfını genişletmek,

... implements OnDateSetListener, OnTimeSetListener

uygulamak

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

örnek arama

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

(İptal işlemek için güncellendi)

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

S3 API 18 üzerinde çalışırken benim için çalışmıyor
AbdelHady

3

Herkes hızlı bir geçici çözüm isterse, kullandığım kod:

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

}

Layout.date_picker_view öğesinin tek öğe olduğu gibi DatePicker ile basit bir düzen kaynağı olduğu:

<!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"/>

İşte tam öğretici Eğer ilgileniyorsanız durumda.


Bu benim için harika çalıştı. Anlaması kolay, uygulaması kolay! 4.4
erdomester

3

Benim basit çözümüm. Yeniden ateşlenmesini istediğinizde "resetFired" komutunu çalıştırmanız yeterlidir (iletişim kutusunu tekrar açarken söyleyin).

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

@AbdelHady kod düzenleme yanlıştı ama daha açık hale getirmek için düzenledim. Bir "isJellyBeanOrAbove ()" yöntemi eklemeye gerek yoktur, hiçbir avantajı yoktur, sadece gereksiz karmaşıklık ekler. ResetFired araması ucuzdur.
Daniel Ryan

buradaki kod yanlıştır, çünkü onDateSetiletişim kutusu herhangi bir yöntemle kapatıldığında bir kez çağrılır ve eğer bu zaman ayarlamak için ortalama ise tekrar tetiklenir, bu yüzden ilk çağrıyı değil, ikinci çağrıyı yakalamamız gerekir yaptığınız gibi,
AbdelHady

İlgili olarak isJellyBeanOrAbove(), Jellybean'dan daha düşük sürümler bu sorunun tümüyle ilgili bir hataya sahip değil ve ikinci çağrıyı yakalamak istediğimizi düşünürsek, bu kontrolü yapmadıkça kod çalışmaz, inan bana, denedim Emülatörler ve gerçek cihazlarda kod (farklı sürümlerle) birkaç kez & bir cazibe gibi çalışıyor
AbdelHady

Bunun bir aşağı değer olup olmadığından emin değilim. Bunu 2 yıl önce yayınladım, o zamandan beri iyi çalışıyor. KG ekibimiz veya binlerce kullanıcımız tarafından bildirilen bir hata yok. Bu, insanların genişletebileceği basit bir cevaptır. Tekrar ateşlenmesini istediğinizde "resetFired" çağırın.
Daniel Ryan

Bizim app "isJellyBeanOrAbove" gerekli değildir. Doğru alanlarda "resetFired" çağrısı yaparsanız uygulama tüm sürümlerde sorunsuz çalışır.
Daniel Ryan

3

Ankur Chaudhary'in benzer konudaki parlak cevabına göre , verilen görünümün olup olmadığını TimePickerDialogkontrol edersek , tüm sorunu minimal çaba ile çözecek, seçiciyi genişletmeye veya kodun etrafında dolaşan bazı iğrenç bayrakları kontrol etmeye gerek kalmayacak. hatta işletim sistemi sürümünü kontrol etmek için aşağıdakileri yapmanız yeterlidir:onDateSetisShown()

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

ve tabii ki onTimeSetAnkur'un cevabı için de aynısı yapılabilir.


1
En iyi cevap diğerlerinden!
hiew1

2

Bu durumu yönetme şeklimde bir bayrak kullanmak ve onCancel ve onDismiss yöntemlerini geçersiz kılmaktı.

onCancel yalnızca kullanıcı iletişim kutusunun dışına veya geri düğmesine dokunduğunda çağrılır. onDismiss her zaman çağrılır

OnCancel yönteminde bir bayrak ayarlamak, onDismiss yönteminde kullanıcının amacını filtrelemeye yardımcı olabilir: eylemi iptal etme veya eylemi tamamlama. Fikri gösteren bazı kodların altında.

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

1

Uygulamanız eylem çubuğunu kullanmıyorsa, çok basit bir çözüm vardır. Bu arada, bazı uygulamaların çalışabilmesi için bu işlevselliğe güvendiğini unutmayın, çünkü tarih seçicinin iptal edilmesinin özel bir anlamı vardır (örneğin, tarih alanını boş bir dizeye temizler; bu, bazı uygulamalar için geçerli ve anlamlı bir girdi türüdür ) ve tarihin iki kez Tamam olarak ayarlanmasını önlemek için boole bayraklarının kullanılması bu durumda size yardımcı olmaz.

Yeniden. asıl düzeltme, yeni düğmeler veya kendi iletişim kutunuzu oluşturmanız gerekmez. Mesele, Android'in eski sürümleri, buggy olanları (4. ) ve gelecekteki herhangi biriyle uyumlu olmaktır, ancak ikincisinden emin olmak imkansızdır. Android 2.'de, android.app.Dialog için onStop () işlevinin hiçbir şey yapmadığını ve 4. * uygulamasında yalnızca uygulamanızın bir eylem çubuğu varsa önemli olan mActionBar.setShowHideAnimationEnabled (false) işlevinin bulunduğunu unutmayın. Dialog'dan devralınan DatePickerDialog'daki onStop (), yalnızca gerekli görünmeyen mDatePicker.clearFocus () öğesine (Android kaynakları 4.3'teki en son düzeltmeden itibaren) katkıda bulunur.

Bu nedenle, onStop () öğesini, hiçbir şey yapmayan bir yöntemle değiştirmek, birçok durumda uygulamanızı düzeltmeli ve öngörülebilir gelecek için böyle kalmasını sağlamalıdır. Böylece DatePickerDialog sınıfını kendinizle genişletin ve kukla bir yöntemle onStop () öğesini geçersiz kılın. Ayrıca gereksinimlerinize göre bir veya iki kurucu sağlamanız gerekecektir. Ayrıca, örneğin doğrudan etkinlik çubuğunda bir şeyler yapmaya çalışarak bu düzeltmeyi aşmaya çalışmak için cazip olmamalı, çünkü uyumluluğunuzu yalnızca Android'in en son sürümleriyle sınırlar. Ayrıca, DatePickerDialog'un süper sınıfında değil, yalnızca DatePickerDialog'un kendisinde onStop () 'da olduğu için DatePicker'ın onStop () için super'i çağırabileceğinizi de unutmayın. Ancak, bu özel sınıfınızdan super.super.onStop () öğesini çağırmanızı gerektirir, hangi Java izin vermeyecektir, çünkü kapsülleme felsefesine karşı gider :) Aşağıda DatePickerDialog vermek için kullanılan benim küçük sınıf. Umarım bu yorum birileri için yararlı olur. 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.
}   

}


Bir ActionBar kullanılsa bile, ActionBar'ı asla gizlemediğiniz / göstermediğiniz takdirde bu kabul edilebilir bir geçici çözüm olabilir. İşleri daha güvenli hale getirmek için, hiçbir şey yapmamak için onStart'ı geçersiz kılabilirsiniz (o zaman animasyon çağrıları güvenli bir şekilde çağrılmaz). Ve gizleseniz / gösterseniz bile, sadece devre dışı bırakılan animasyon.
Daniel

0


Aşağıdaki kavramları deneyin.

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


onDateSet () yöntemi iki kez çağırır (u emulator.it'te kontrol ediyorsanız iki kez çağırır. gerçek cihazı kullanıyorsanız, o zaman doğru bir şekilde çağırır. Sayaç değişkenini yoksay.Gerçek cihaz için benim için çalışıyor.)
Kullanıcı DatePickerDialog'daki düğmeyi tıkladığında.
bunun için bir sayaç değeri korumalısınız ve mothod ilk kez aradığında hiçbir şey yapmamalı ve yöntem 2. kez çağırdığında işlemi gerçekleştirmemelidir.
Aşağıdaki kod parçacıklarına bakın

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



Datepicker dilalog iptal etmek benim için çalışıyor. Emülatör için onun wokring değil

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


Benim için gerçek bir cihaz için çalışıyor.Ama öykünücü için doğru çalışmıyor. Bence bir android emülatör hatası.


0

Basit bir çözüm, ikinci koşuyu atlamak için bir boole kullanmak olabilir

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

Bir kez daha, senden önce diğer adamı söylediğin gibi, bu mu değil Çözmesi. Kulağa kaba gelmek istemiyorum, ama siz buraya göndermeden önce kendi çözümünüzü test etmelisiniz ... sadece benim amacımı kanıtlamak, kodunuzu kullanmak ve kullanıcının iletişim kutusunu iptal etmek ve ne demek istediğimi görmek için geri basmasına izin vermek. Böceğin nedeni , onStopgerekmediğinde yöntemi çağırıyor ... iki kez ateşleme, hatanın bir sonucudur.
davidcsb

Yeterince net olmasaydım, şunu söyleyeyim: diyalog çağrılarını iptal etmek için geri basmak onDateSet. Böylece, kırık.
davidcsb

Hatayı gösterdiğiniz için teşekkür ederiz. Cevabı geri düğmesi ile çalışacak şekilde düzenliyorum. Cevabınız çalışıyor ancak DatePicker dp = picker.getDatePicker (); getTimePicker () yöntemi eklenmediğinden TimePickers ile çalışmıyor. Bu geçerli bir cevap olacaktır
chamikaw

İkinci çalıştırmayı nasıl atlamaya çalışıyoruz? !!, birkaç kez denedim, iletişim kutusunu kapatırken bir onDateSetkez çağrılacak, ancak "tamamlandı" veya "ayarlandı" seçildiğinde iki kez çağrılacak. Bu nedenle sadece
ilkini atlamamız

0

Negatif kullanıcı eylemlerini tespit etmek için onCancel () 'i geçersiz kılabilir ve setOnDismissListener () kullanabilirsiniz. DatePickerDialog.BUTTON_POSITIVE ile kullanıcının yeni bir tarih ayarlamak istediğini bilirsiniz.

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

sonra setDate'i kontrol edin:

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

0

Burada, DatePickerDialog için iptal düğmesinin yanı sıra geri düğmesiyle bırakma geçici çözüm sınıfım. DatePickerDialog tarzında kopyalama ve kullanma (Dinleyici durumlu olduğundan, kullanım sırasında yeni bir örnek oluşturmalıyız, aksi takdirde çalışmasını sağlamak için daha fazla kod gerekir)

kullanın:

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

Sınıf:

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

Tarih seçicileri, zaman seçicileri ve sayı seçicileri kullanıyorum. Kullanıcı toplayıcı çıkarılmadan önce, kullanıcı bir sayı seçtiğinde numara seçicileri çağrılır.

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

Düğmelerim için özel onClickListeners ayarlamak için hangi düğmenin tıklandığını görmek için bir argümanla bunu genişlettim. Şimdi son değerimi ayarlamadan önce hangi düğmeye dokunulduğunu kontrol edebilirim:

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

Ve sonra bunu tarih ve saat seçicileri için tarih ve saat türleriyle ve sayı seçiciler için int türüyle çalışacak şekilde genişlettim.

Bunu yukarıdaki çözümlerin bazılarından daha basit olduğunu düşündüğüm için yayınladım, ancak şimdi tüm kodu dahil ettiğime göre, sanırım çok daha basit değil! Ama zaten sahip olduğum yapıya çok iyi uyuyor.

Lollipop Güncellemesi: Görünüşe göre bu hata tüm Android 4.1-4.4 cihazlarında gerçekleşmiyor, çünkü tarih ve saat seçicileri onDateSet ve onTimeSet geri aramalarını aramayan kullanıcılardan birkaç rapor aldım. Ve hata Android 5.0'da resmen düzeltildi. Benim yaklaşımım sadece hatanın bulunduğu cihazlarda çalıştı, çünkü özel düğmelerim iletişim kutusunun onClick işleyicisini çağırmadı, bu hata mevcut olmadığında onDateSet ve onTimeSet'in çağrıldığı tek yer. Yukarıdaki kodumu iletişim kutusunun onClick'i çağırmak için güncelledim, bu yüzden şimdi hata mevcut olsun veya olmasın çalışır.


0

Yukarıdaki David Cesarino'nun cevabını beğendim, ancak kırık iletişim kutusunun yerine bir damla olan ve iptal / yanlış iptal davranışına sahip olmayan herhangi bir iletişim kutusu üzerinde çalışacak bir şey istedim. İşte DatePickerDialog / TimePickerDialog için değiştirmelerde damla olarak çalışması gereken türetilmiş sınıflar. Bunlar özel görünümler değildir. Sistem iletişim kutusunu kullanır, ancak iptal / geri düğmesi davranışını beklendiği gibi çalışacak şekilde değiştirir.

Bu, API düzey 3 ve üstünde çalışır. Yani, temelde Android'in herhangi bir sürümü (özellikle jellybean ve lolipop üzerinde test ettim).

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

Bu, Deniz'in yukarıdaki cevabına oldukça benzer.
stuckj

0

Lambda Expressions kullanarak ClearButton ile çalışma sürümüm:

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

TimePickerDialog için geçici çözüm aşağıdaki gibi olabilir:

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

Tüm etkinlikleri sarmalayıcı KitKatSetTimeListener'a delege ediyorum ve yalnızca orijinal OnTimeSetListener'a BUTTON_POSITIVE tıklatıldığında geri dönüyorum.


0

Burada yayınlanan bazı önerileri test ettikten sonra, kişisel olarak bu çözümün en basit olduğunu düşünüyorum. DatePickerDialog yapıcısında dinleyicim olarak "null" iletiyorum ve sonra "Tamam" düğmesini tıklattığımda onDateSearchSetListener'ımı çağırıyorum:

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

-1

Bu yazının neredeyse bir yıldır burada olduğunu biliyorum ama bulgularımı yayınlamam gerektiğini düşündüm. Dinleyiciyi hala (mull olarak ayarlamak yerine) tutabilir ve yine de beklediğiniz gibi çalıştırabilirsiniz. Anahtar, "Tamam" veya (ve) "iptal" düğmelerini dolaylı olarak ayarlamaktır. Test ettim ve benim için minnetle çalışıyor. Dinleyici iki kez kovulmaz.

Bu örneğe bakın,

private void setTime(){
final Calendar c = Calendar.getInstance();
int hour = c.get(Calendar.HOUR_OF_DAY);
int minute = c.get(Calendar.MINUTE);

final TimePickerDialog timepicker = new TimePickerDialog(this.getActivity(),
        timePickerListener,
        hour, 
        minute, 
        DateFormat.is24HourFormat(getActivity()));

timepicker.setButton(DialogInterface.BUTTON_POSITIVE, "Print", new    
    android.content.DialogInterface.OnClickListener(){
        @Override
        public void onClick(DialogInterface dialog,int which) {
            print = true;
            timepicker.dismiss();           
        }
});

timepicker.setButton(DialogInterface.BUTTON_NEGATIVE, "Cancel", new 
    android.content.DialogInterface.OnClickListener(){
        @Override
        public void onClick(DialogInterface dialog,int which){
            print = false;
            timepicker.dismiss();       
        }
});

timepicker.setCancelable(false);
timepicker.show();
}

Sade ve basit, anlattığınız gibi çalışmıyor. timePickerListeneriletişim kutunuzda ne yaparsanız yapın yine de çağrılır. Hatta olduğunu bilmek teste gerek yok, sadece bakmak gerekir kaynaklardan : Eğer ayarlayın yoksa null, tryNotifyTimeSet()dinleyici arayacak onTimeSet()onun hem onClick()ve onStop().
davidcsb

Başka bir deyişle, do not (Oluşturucu içinde geçirmeden, yani) yerel sınıf dinleyici başvuru tutayım. Düğmelerle nasıl başa çıktığınız önemsizdir.
davidcsb

Merhaba David, Bunu test etmedin ve işe yaramayacağını varsaydın. Bu şu anda benim app kullanıyorum kod tam parçası ve bir şampiyon gibi çalışır.
Timsah

1) Hiç işe yaramadığını söylemedim. Söylediğin gibi çalışmadığını söyledim. Lütfen tekrar okuyun. 2) Eğer gereksiz değiştirmek için insan-saat israf, LSP ve SRP ihlal tüm senin tüm başlamak için herhangi bir değişiklik gerek yoktu istemci mantığı. 3) Cevabınız soruyu ele alıyor, evet, aksi takdirde kaldırılması için "cevap değil" olarak işaretlerim, ancak 4) cevabınız hala (bunun için üzgünüm) çok verimsiz ve temel tasarım sorununu (dinleyici denir) ), dolayısıyla sadece aşağı oy. 6) devre dışı sırt ve bunu boole zorlamak için kalıcı bir pencere yaptı. Yani, 6 ciddi sorun var!
davidcsb
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.