从DatePickerDialog片段返回日期时出现问题

时间:2019-05-27 04:45:41

标签: android kotlin android-datepicker android-architecture-navigation

我试图返回从DatePickerDialog中选择的日期。我知道在SO上对此有一些疑问,我确定已经检查了代码中的内容,但仍无法将日期重新输入到调用DatePickerDialog的片段中。

我正在使用“导航”界面显示对话框,这可能是导致问题的原因吗?

这是我的DatePickerDialog:

class DatePickerFragment : DialogFragment(), DatePickerDialog.OnDateSetListener {

    private var onDateSetListener: DatePickerDialog.OnDateSetListener? = null

    fun setListeningActivity(listener: DatePickerDialog.OnDateSetListener) {
        onDateSetListener = listener
    }

    override fun onDateSet(view: DatePicker?, year: Int, month: Int, dayOfMonth: Int) {
        onDateSetListener?.onDateSet(view,year, month, dayOfMonth)
    }

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        // Use the current date as the default date in the picker
        val c = Calendar.getInstance()
        val year = c.get(Calendar.YEAR)
        val month = c.get(Calendar.MONTH)
        val day = c.get(Calendar.DAY_OF_MONTH)

        // Create a new instance of DatePickerDialog and return it
        return DatePickerDialog(context, this, year, month, day)
    }
}

片段中调用Datepicker的相关代码:

private fun showDatePicker(hasFocus: Boolean, view: View) {
    Log.i(FRAGMENT_NAME, "Has focus $hasFocus")
    val fragment = DatePickerFragment()
    fragment.setListeningActivity(this)
    if (hasFocus) {
        Navigation.findNavController(view).navigate(R.id.datePickerFragment)
    }
}

override fun onDateSet(view: DatePicker, year: Int, month: Int, day: Int) {
    Log.i(FRAGMENT_NAME, "Date received: $year-$month-$day")
    fragmentView.dateOfBirthField.editText?.setText("$year-$month-$day")
}

这就是我调用showDatePicker方法的方式:

  

fragmentView.dateOfBirthField.editText?.setOnFocusChangeListener {_,hasFocus-> showDatePicker(hasFocus,fragmentView)}

问题:如何将日期重新放回调用DatePickerDialog的Fragment中。我不想将DatePickerDialog作为调用它的类的内部类。

2 个答案:

答案 0 :(得分:1)

当您使用导航体系结构组件时,最好的片段数据传递方法是将livedataviewmodel一起使用。

步骤1 创建ViewModel,它将保存您的selectedDate。创建LiveData的实例,以便您可以观察到更改。

class SharedViewModel: ViewModel() {
    val selectedDate: MutableLiveData<String> = MutableLiveData()
}

步骤2 获取SharedViewModel的实例并更新selectedDate变量以通知其观察者。 (在DatePickerFragment中)

override fun onDateSet(view: DatePicker, year: Int, month: Int, day: Int) {
    val viewModel = ViewModelProviders.of(activity!!)[SharedViewModel::class.java]
    viewModel.selectedDate.value = "$year $month $day"
}

步骤3 获取要观察更改的SharedViewModel实例。 (在我们的情况下,是从datePickerFragment处调用的。)

override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)

    ViewModelProviders.of(activity!!)[SharedViewModel::class.java]
            .selectedDate
            .observe(activity!!, Observer { dateOfBirthField.editText.setText(it) })
}

如果您正在使用androidx工件。然后您可能需要依赖。

implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0-alpha01'

答案 1 :(得分:0)

一个人都可以设置目标Fragment

val fragment = DatePickerFragment()
fragment.setTargetFragment(this, requestCode)

或让其将结果传递到Activity

val fragment = DatePickerFragment()
fragment.setListeningActivity(this)

这应该在显示DialogFragment之前发生;这样DialogFragment就已经知道将结果传送到哪里了。对于任何一个传递目的地,方法onDateSet()需要返回带有附加Intent ...的Bundle,而onActivityResult()需要处理该结果并相应地更新GUI。 ActivityFragment之间的通信就是这样进行的-这也适用于DialogFragment。方法onActivityResult()可以处理来自ActivityFragment的回调。

在Java中,这类似于-在方法DialogFragment中通过override fun onDateSet(view: DatePicker, year: Int, month: Int, day: Int)返回结果:

/* converting the selection to long integer */
GregorianCalendar date = new java.util.GregorianCalendar();
date.set(GregorianCalendar.YEAR, year);
date.set(GregorianCalendar.MONTH, month);
date.set(GregorianCalendar.DAY_OF_MONTH, day);
Log.d(LOG_TAG, "confirmed " + date.getTime());
long dueDate = date.getTime().getTime();

if (getTargetFragment() != null) {

    /* stuffing the result value into a Bundle */
    Intent intent = this.getActivity().getIntent();
    Bundle extras = new Bundle();
    extras.putLong(ArgumentKeys.ARGUMENT_SELECT_DUE_DATE, dueDate);
    intent.putExtras(extras);

    /* this delivers the result */
    getTargetFragment().onActivityResult(getTargetRequestCode(), Activity.RESULT_OK, intent);

    /* close dialog */
    this.dismiss();

} else {
    Log.w(LOG_TAG, ".setTargetFragment() had not been called.");
}

或类似地返回到Activity

if(this.dialog.getOwnerActivity() != null) {
    ...
}

以及onActivityResult()Activity中打开Fragment的{​​{1}}:

DialogFragment

返回@Override public void onActivityResult(int requestCode, int resultCode, Intent intent) { Bundle extras = intent.getExtras(); if(resultCode == Activity.RESULT_OK) { switch (requestCode) { case RequestCodes.REQUESTCODE_TASK_DUE_DATE: { if(extras != null) { long dueDate = extras.getLong(ArgumentKeys.ARGUMENT_SELECT_DUE_DATE, -1); /* set the value in here */ } } } ... } } 结果的工作原理几乎类似于返回Fragment结果。