DatePicker Widget 不会占用 Nexus 6 上的整个 AlertDialog

DatePicker Widget does not take up entire AlertDialog on Nexus 6

我有一个使用非常简单的自定义布局的 DatePickerFragment。该布局在较小的设备(HTC One m7)上占据了整个警报对话框,但在 Nexus 6 上却没有。有谁知道为什么 DatePicker 没有占据 Nexus 6 警报对话框的整个宽度或从哪里开始进行故障排除?谢谢!

Nexus 6(注意日期 header 没有填满整个警报对话框)

HTC One m7

dialog_date.xml

<?xml version="1.0" encoding="utf-8"?>
<DatePicker xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/dialog_date_date_picker"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:calendarViewShown="false">
</DatePicker>

DatePickerFragment 的 onCreateDialog()

public Dialog onCreateDialog(Bundle savedInstanceState) {
        Date date = (Date) getArguments().getSerializable(ARG_DATE);

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int year = calendar.get(Calendar.YEAR);
        int month = calendar.get(Calendar.MONTH);
        int day = calendar.get(Calendar.DAY_OF_MONTH);

        View v = LayoutInflater.from(getActivity())
                 .inflate(R.layout.dialog_date, null);

        mDatePicker = (DatePicker)
  v.findViewById(R.id.dialog_date_date_picker);
        mDatePicker.init(year, month, day, null);

        return new AlertDialog.Builder(getActivity())
                 .setView(v)
//                     .setTitle(R.string.date_picker_title)
                 .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                     @Override
                     public void onClick(DialogInterface dialog, int which) {
                         int year = mDatePicker.getYear();
                         int month = mDatePicker.getMonth();
                         int day = mDatePicker.getDayOfMonth();
                         Date date = new GregorianCalendar(year, month, day).getTime();
                         sendResult(Activity.RESULT_OK, date);
                     }
                 })
                 .create();
        }

警报对话框有一些严格的(奇怪的?)规则来控制它的大小。我不确定如何实际解决它,但有一个解决方法 - 显示对话框后,您可以强制其宽度与日期选择器的宽度相匹配。这为我解决了这个问题,希望它也对你有用:

public Dialog onCreateDialog(Bundle savedInstanceState) {
    ...
    final AlertDialog alertDialog = new AlertDialog.Builder(getActivity())
            ...
            .create();

    alertDialog.setOnShowListener(new DialogInterface.OnShowListener() {
        @Override public void onShow(DialogInterface dialog) {
            WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
            final Window window = getDialog().getWindow();
            lp.copyFrom(window.getAttributes());
            final View picker = window.findViewById(R.id.dialog_date_date_picker);
            lp.width = picker.getWidth();
            lp.height = picker.getHeight();
            window.setAttributes(lp);
        }
    });

    return alertDialog;
}

我无法使用 nitzanj 的建议使其工作,但我改变了创建 DatePickerDialog 的方式,它现在按预期工作。完整的来源如下。关键区别在于 onCreateDialog.

public class DatePickerFragment extends DialogFragment
        implements DatePickerDialog.OnDateSetListener{

    public static final String EXTRA_DATE =
            "com.amicly.acaringtext.date";

    private static final String ARG_DATE = "date";

    @NonNull
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        Date date = (Date) getArguments().getSerializable(ARG_DATE);

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int year = calendar.get(Calendar.YEAR);
        int month = calendar.get(Calendar.MONTH);
        int day = calendar.get(Calendar.DAY_OF_MONTH);

        return new DatePickerDialog(getActivity(), this, year, month, day);
    }

    public static DatePickerFragment newInstance(Date date) {
        Bundle args = new Bundle();
        args.putSerializable(ARG_DATE, date);
        DatePickerFragment fragment = new DatePickerFragment();
        fragment.setArguments(args);
        return fragment;
    }

    private void sendResult(int resultCode, Date date) {
        if (getTargetFragment() == null) {
            return;
        }
        Intent intent = new Intent();
        intent.putExtra(EXTRA_DATE, date);

        getTargetFragment().
                onActivityResult(getTargetRequestCode(), resultCode, intent);
    }

    @Override
    public void onDateSet(DatePicker datePicker, int year, int month, int day) {
        Date date = new GregorianCalendar(year, month, day).getTime();
        sendResult(Activity.RESULT_OK, date);
    }
}

如果有人为此苦恼(我肯定是在处理了六个小时之后),那么这可能对你有用。

不要使用带有 DatePicker 的 AlertDialog,而是使用 DatePickerDialog。不仅设置起来更容易,而且实际显示效果如预期。

用法示例:

DateTime dateTime = new DateTime();

new DatePickerDialog(
                    getActivity(),
                    R.style.DatePickerDialogCustom,
                    new DatePickerDialog.OnDateSetListener() {
                        @Override
                        public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) {
                            dateTime = new DateTime(
                                    year,
                                    month + 1,
                                    dayOfMonth,
                                    dateTime.getHourOfDay(),
                                    dateTime.getMinuteOfHour()
                            );
                            etDate.setText(dateFormatter.print(dateTime));
                        }
                    },
                    dateTime.getYear(),
                    dateTime.getMonthOfYear() - 1,
                    dateTime.getDayOfMonth()
            ).show();

月份偏移 1,因为 DatePicker returns 月份值介于 0 和 11 之间。

对于样式,请勿使用警告对话框样式。这实际上是导致原始问题的原因。如果不需要自定义样式,只需将其从构造函数中删除(不要使用 null)。如果您使用的是自定义样式,则只需在 styles.xml:

中创建一个新样式
<style name="DatePickerDialogCustom" parent="@style/Theme.AppCompat.Dialog">
    <item name="android:colorBackground">@color/background</item>
    <item name="colorAccent">@color/colorAccent</item>
    <item name="android:datePickerStyle">@style/DatePickerCustom</item>
</style>

<style name="DatePickerCustom" parent="@android:style/Widget.Material.DatePicker">
    <item name="android:headerBackground">@color/colorAccent</item>
</style>

我不知道同样的问题是否困扰着 TimePickers,但如果是的话,我想类似的解决方案会奏效。

原因是 AlertDialog 比子 DatePicker space 占用更多。

确保使用不带 .Alert 后缀的对话框主题(例如 Theme.AppCompat.Light.Dialog)。