You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android数据绑定任务应用中Material Date Picker与Room集成方案

解决方案:Material Date Picker 与 Room 数据库集成

你的代码框架已经搭建完成,只需要补全日期选择后的数据传递、界面显示和列表渲染这几个环节即可完成集成,具体步骤如下:


1. 布局新增日期显示控件

在 FragmentMesimah.xml 的日期选择按钮下方,添加一个 TextView 用于展示用户选中的日期范围,方便用户确认选择结果:

<com.google.android.material.button.MaterialButton
    android:id="@+id/btn_open_date_picker"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:text="@string/btn_select_date"
    app:cornerRadius="16dp"
    app:strokeColor="@color/black"
    app:strokeWidth="2dp"/>

<!-- 新增:显示选中的日期范围 -->
<TextView
    android:id="@+id/selected_date_range"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:layout_marginTop="8dp"
    android:text="@{viewModel.selectedDateRange}"
    android:textSize="16sp"/>

<Button
    android:id="@+id/save_button"
    .../>

2. ViewModel 扩展日期处理逻辑

在 TasksViewModel 中添加日期显示的可观察变量,以及更新日期的方法,将选中的时间戳同步到 Room 所需的 Long 类型变量:

class TasksViewModel(val dao: TaskDao) : ViewModel() {
    private val TAG = "TASKS_VIEW_MODEL"
    private val _navigateToMesimah = MutableLiveData<Long?>()
    val navigateToMesimah: LiveData<Long?>
        get() = _navigateToMesimah

    var newTaskName = ""
    var newTaskDescription = ""
    var start_date: Long = 0L
    var end_date: Long = 0L
    val tasks = dao.getAll()

    // 新增:用于界面显示的日期范围字符串
    val selectedDateRange = MutableLiveData<String>("未选择日期")

    // 新增:更新选中日期的方法
    fun updateSelectedDates(start: Long, end: Long) {
        start_date = start
        end_date = end
        // 格式化日期为可读字符串
        val formatter = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
        val startStr = formatter.format(Date(start))
        val endStr = formatter.format(Date(end))
        selectedDateRange.value = "$startStr - $endStr"
    }

    // 原有方法保持不变
    fun addTask() { ... }
    fun onTaskClicked(taskId: Long) { ... }
    fun onTaskNavigated() { ... }
}

3. 完善 DatePicker 回调逻辑

修改 MesimahFragment 中的 showDateRangePicker 方法,将选中的日期时间戳传递给 ViewModel,替代原来仅显示 Toast 的逻辑:

private fun showDateRangePicker() {
    val dateRangePicker = MaterialDatePicker.Builder.dateRangePicker()
        .setTitleText("选择日期范围")
        .build()

    dateRangePicker.show(parentFragmentManager, "date_range_picker")
    dateRangePicker.addOnPositiveButtonClickListener { dateRange ->
        // 获取选中的开始/结束时间戳(处理空值情况)
        val selectedStart = dateRange.first ?: System.currentTimeMillis()
        val selectedEnd = dateRange.second ?: System.currentTimeMillis()
        // 通知ViewModel更新日期
        viewModel.updateSelectedDates(selectedStart, selectedEnd)
    }
}

4. 列表项显示日期

在任务列表的 Item 布局(如 item_mesimah.xml)中添加日期显示控件,同时在适配器中格式化 Long 类型的时间戳为可读日期:

布局示例:

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="8dp">

    <TextView
        android:id="@+id/task_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@{task.taskName}"
        android:textSize="18sp"
        android:textStyle="bold"/>

    <!-- 新增:显示开始/结束日期 -->
    <TextView
        android:id="@+id/task_dates"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@{@string/task_dates_label + task.startDate + @string/date_separator + task.endDate}"
        android:textSize="14sp"
        android:textColor="@color/gray"/>
</LinearLayout>

适配器格式化逻辑:

class MesimahItemAdapter(private val onTaskClicked: (Long) -> Unit) :
    ListAdapter<Mesimah, MesimahItemAdapter.MesimahViewHolder>(DiffCallback()) {

    private val dateFormatter = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())

    inner class MesimahViewHolder(private val binding: ItemMesimahBinding) :
        RecyclerView.ViewHolder(binding.root) {
        fun bind(task: Mesimah) {
            binding.task = task
            // 格式化时间戳为字符串
            binding.taskDates = "${dateFormatter.format(Date(task.startDate))} ~ ${dateFormatter.format(Date(task.endDate))}"
            binding.root.setOnClickListener { onTaskClicked(task.taskId) }
            binding.executePendingBindings()
        }
    }

    // 原有DiffCallback实现保持不变
    class DiffCallback : DiffUtil.ItemCallback<Mesimah>() {
        override fun areItemsTheSame(oldItem: Mesimah, newItem: Mesimah): Boolean {
            return oldItem.taskId == newItem.taskId
        }

        override fun areContentsTheSame(oldItem: Mesimah, newItem: Mesimah): Boolean {
            return oldItem == newItem
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MesimahViewHolder {
        val binding = ItemMesimahBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return MesimahViewHolder(binding)
    }

    override fun onBindViewHolder(holder: MesimahViewHolder, position: Int) {
        val task = getItem(position)
        holder.bind(task)
    }
}

5. 编辑任务时的日期初始化(可选)

如果需要支持编辑任务时回显已选日期,在编辑页面的 showDateRangePicker 方法中添加初始选中值:

private fun showEditDateRangePicker(task: Mesimah) {
    val initialSelection = androidx.core.util.Pair(task.startDate, task.endDate)
    val dateRangePicker = MaterialDatePicker.Builder.dateRangePicker()
        .setTitleText("修改日期范围")
        .setSelection(initialSelection)
        .build()

    dateRangePicker.show(parentFragmentManager, "edit_date_range_picker")
    dateRangePicker.addOnPositiveButtonClickListener { dateRange ->
        val newStart = dateRange.first ?: task.startDate
        val newEnd = dateRange.second ?: task.endDate
        // 更新任务的日期并保存到Room
        val updatedTask = task.copy(startDate = newStart, endDate = newEnd)
        viewModel.updateTask(updatedTask)
    }
}

内容的提问来源于stack exchange,提问作者18.5

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 02:24:52