果冻豆DatePickerDialog ---有办法取消吗? [英] Jelly Bean DatePickerDialog --- is there a way to cancel?

查看:220
本文介绍了果冻豆DatePickerDialog ---有办法取消吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

--- 主持人注意:今天(7月15日),我注意到有人已经面临这个问题了这里。但是我不知道把它作为一个重复是合适的,因为我认为我提供了更好的解释这个问题。我不知道我是否应该编辑另一个问题,并将该内容粘贴到此处,但我不太乐意改变别人的问题。 ---

--- Note to moderators: Today (July 15), I've noticed that someone already faced this problem here. But I'm not sure if it's appropriate to close this as a duplicate, since i think I provided a much better explanation of the issue. I'm not sure if I should edit the other question and paste this content there, but I'm not comfortable changing someone else's question too much. ---

我在这里有一些奇怪的东西

I have something weird here.

我不认为问题取决于您构建的SDK。设备操作系统版本是重要的。

I don't think the problem depends on which SDK you build against. The device OS version is what matters.

DatePickerDialog 在Jelly Bean中已更改(?),现在只提供一个完成按钮。以前的版本包括一个取消按钮,这可能会影响用户体验(不一致,以前的Android版本的肌肉记忆)。

DatePickerDialog was changed (?) in Jelly Bean and now only provides a Done button. Previous versions included a Cancel button, and this may affect user experience (inconsistency, muscle memory from previous Android versions).

em>复制: 创建一个基本项目。将它放在 onCreate 中:

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

期望: A 取消按钮显示在对话框中。

Expected: A Cancel button to appear in the dialog.

当前: A 取消按钮不显示。

截图: 4.0.3 (OK)和 4.1.1 (可能是错误的?)

Screenshots: 4.0.3 (OK) and 4.1.1 (possibly wrong?).

对话框调用无论哪个监听器应该调用, em> always 调用 OnDateSetListener 监听器。取消仍然调用set方法,并设置它调用该方法两次。

Dialog calls whichever listener it should call indeed, and then always calls OnDateSetListener listener. Canceling still calls the set method, and setting it calls the method twice.

复制: 使用#1代码,但添加下面的代码(你会看到这个解决#1,但只有visual / UI):

Replicate: Use #1 code, but add code below (you'll see this solves #1, but only visually/UI):

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

预期:

Expected:


  • 按BACK键或点击对话框外应不做任何


  • 按设置应该打印选择器设置!

  • Pressing the BACK key or clicking outside the dialog should do nothing.
  • Pressing "Cancel" should print Picker Cancel!.
  • Pressing "Set" should print Picker Set!.

当前:

Current:


  • 按BACK键或在对话框外点击打印选择器设置!

  • 按取消打印选择器取消! <>>选择器设置!

  • 按设置打印选择器设置!,然后选择器设置! strong>。

  • Pressing the BACK key or clicking outside the dialog prints Picker Set!.
  • Pressing "Cancel" prints Picker Cancel! and then Picker Set!.
  • Pressing "Set" prints Picker Set! and then Picker Set!.

显示行为的日志行:

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!



其他注释和评论




  • 将它围绕在 DatePickerFragment 之间。我简化了你的问题,但我已经测试了。

  • Other notes and comments

    • Wrapping it around a DatePickerFragment doesn't matter. I simplified the problem for you, but I've tested it.
    • 推荐答案

      注意: 修正了Lollipop source here 。自动化客户端使用的类别(与所有Android版本兼容)。 / p>

      TL; DR:1-2-3全球解决方案的简单步骤:



      Note: Fixed as of Lollipop, source here. Automated class for use in clients (compatible with all Android versions) updated as well.


      1. 下载这个类。

      2. 实现 OnDateSetListener 在您的活动中(或更改课程以满足您的需要)。

      3. 使用此代码触发对话框(在此示例中,我使用它一个 Fragment ):

      1. Download this class.
      2. Implement OnDateSetListener in your activity (or change the class to suit your needs).
      3. Trigger the dialog with this code (in this sample, I use it inside a 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");
      


      这就是需要! 我仍然将我的答案保持为接受的原因是因为我仍然喜欢我的解决方案,因为它的客户端代码的占用空间非常小,它解决了基本问题(在框架类中调用的监听器),工作通过配置更改,它将路由代码逻辑到以前的Android版本中的默认实现,不受此错误的困扰(请参阅类源代码)。

      And that's all it takes! The reason I still keep my answer as "accepted" is because I still prefer my solution since it has a very small footprint in client code, it addresses the fundamental issue (the listener being called in the framework class), works fine across config changes and it routes the code logic to the default implementation in previous Android versions not plagued by this bug (see class source).

      好的,看起来确实如此一个bug和其他人已经填满了。 问题34833

      OK, looks like it's indeed a bug and someone else already filled it. Issue 34833.

      我发现问题可能在 DatePickerDialog.java 中。它的内容如下:

      I've found that the problem is possibly in DatePickerDialog.java. Where it reads:

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

      我猜这可能是:

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

      现在,如果有人可以告诉我如何提出补丁/错误报告Android,我很高兴。同时,我提出了一个可能的修复(简单)作为 DatePickerDialog.java 的附件版本。

      Now if someone can tell me how I can propose a patch/bug report to Android, I'd be glad to. Meanwhile, I suggested a possible fix (simple) as an attached version of DatePickerDialog.java in the Issue there.

      将构建器中的监听器设置为 null ,并创建自己的 BUTTON_POSITIVE 按钮稍后

      Set the listener to null in the constructor and create your own BUTTON_POSITIVE button later on. That's it, details below.

      由于 DatePickerDialog.java ,您可以在源代码中看到问题,调用存储在构造函数中传递的监听器的全局变量( mCallBack ):

      The problem happens because DatePickerDialog.java, as you can see in the source, calls a global variable (mCallBack) that stores the listener that was passed in the constructor:

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

      所以,诀窍是提供一个 / code>监听器作为监听器存储,然后滚动自己的一组按钮(以下是#1的原始代码,更新):

      So, the trick is to provide a null listener to be stored as the listener, and then roll your own set of buttons (below is the original code from #1, updated):

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

      现在它将工作,因为我上面发布了可能的更正。

      Now it will work because of the possible correction that I posted above.

      由于 DatePickerDialog.java 检查 null 每当它读取 mCallback 从API 3 / 1.5的日子起,似乎 ---当然不能检查蜂窝),它不会触发异常。考虑到棒棒糖修复了问题,我不是要查看它:只需使用默认实现(覆盖在我提供的类中)。

      And since DatePickerDialog.java checks for a null whenever it reads mCallback (since the days of API 3/1.5 it seems --- can't check Honeycomb of course), it won't trigger the exception. Considering Lollipop fixed the issue, I'm not going to look into it: just use the default implementation (covered in the class I provided).

      起初我害怕没有调用 clearFocus(),但我已经测试了这里,日志行是干净的。所以我提出的这一行甚至可能根本不需要,但我不知道。

      At first I was afraid of not calling the clearFocus(), but I've tested here and the Log lines were clean. So that line I proposed may not even be necessary after all, but I don't know.

      正如我在下面的评论中指出的那样,这是一个概念,你可以。我使用的方式,默认的系统实现用于不受该错误影响的版本。

      As I pointed in the comment below, that was a concept, and you can download the class I'm using from my Google Drive account. The way I used, the default system implementation is used on versions not affected by the bug.

      我采取了一些适合我的假设(按钮名称等)需要,因为我想将客户端类中的样板代码降至最低。完整的使用示例:

      I took a few assumptions (button names etc.) that are suitable for my needs because I wanted to reduce boilerplate code in client classes to a minimum. Full usage example:

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

      这篇关于果冻豆DatePickerDialog ---有办法取消吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆