jetpack compose 是否有日期时间选择器视图,或者我应该自己创建它?我试图用谷歌搜索它,但我找不到准备使用的组件。
9 回答
似乎他们仍在努力,与此同时,如果您需要一些非常简单的东西,您可以使用 compose 与 Android Views 的互操作:
@Composable
fun DatePicker(onDateSelected: (LocalDate) -> Unit, onDismissRequest: () -> Unit) {
val selDate = remember { mutableStateOf(LocalDate.now()) }
//todo - add strings to resource after POC
Dialog(onDismissRequest = { onDismissRequest() }, properties = DialogProperties()) {
Column(
modifier = Modifier
.wrapContentSize()
.background(
color = MaterialTheme.colors.surface,
shape = RoundedCornerShape(size = 16.dp)
)
) {
Column(
Modifier
.defaultMinSize(minHeight = 72.dp)
.fillMaxWidth()
.background(
color = MaterialTheme.colors.primary,
shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp)
)
.padding(16.dp)
) {
Text(
text = "Select date".toUpperCase(Locale.ENGLISH),
style = MaterialTheme.typography.caption,
color = MaterialTheme.colors.onPrimary
)
Spacer(modifier = Modifier.size(24.dp))
Text(
text = selDate.value.format(DateTimeFormatter.ofPattern("MMM d, YYYY")),
style = MaterialTheme.typography.h4,
color = MaterialTheme.colors.onPrimary
)
Spacer(modifier = Modifier.size(16.dp))
}
CustomCalendarView(onDateSelected = {
selDate.value = it
})
Spacer(modifier = Modifier.size(8.dp))
Row(
modifier = Modifier
.align(Alignment.End)
.padding(bottom = 16.dp, end = 16.dp)
) {
TextButton(
onClick = onDismissRequest
) {
//TODO - hardcode string
Text(
text = "Cancel",
style = MaterialTheme.typography.button,
color = MaterialTheme.colors.onPrimary
)
}
TextButton(
onClick = {
onDateSelected(selDate.value)
onDismissRequest()
}
) {
//TODO - hardcode string
Text(
text = "OK",
style = MaterialTheme.typography.button,
color = MaterialTheme.colors.onPrimary
)
}
}
}
}
}
@Composable
fun CustomCalendarView(onDateSelected: (LocalDate) -> Unit) {
// Adds view to Compose
AndroidView(
modifier = Modifier.wrapContentSize(),
factory = { context ->
CalendarView(ContextThemeWrapper(context, R.style.CalenderViewCustom))
},
update = { view ->
view.minDate = // contraints
view.maxDate = // contraints
view.setOnDateChangeListener { _, year, month, dayOfMonth ->
onDateSelected(
LocalDate
.now()
.withMonth(month + 1)
.withYear(year)
.withDayOfMonth(dayOfMonth)
)
}
}
)
}
<style name="CalenderViewCustom" parent="ThemeOverlay.MaterialComponents.MaterialCalendar">
<item name="colorAccent"><day selection color></item>
<item name="colorOnPrimary"><text color></item>
<item name="colorSurface"><background color></item>
</style>
你最终会得到这样的结果:
使用库
在撰写本文时,它尚未实施。但是有一个开源库Compose Material Dialogs
没有图书馆
您也可以在没有库的情况下执行此操作,您可以将其放在 onclick 操作中
private fun showDatePicker() {
val picker = MaterialDatePicker.Builder.datePicker().build()
activity?.let {
picker.show(it.supportFragmentManager, picker.toString())
picker.addOnPositiveButtonClickListener {
}
}
}
目前,jetpack compose 处于 Alpha 状态,androidx.ui.* 中没有 DateTime Picker。但是,稍后 android 团队将添加它或使 jetpack compose 与其他组件(如 android.widget.DatePicker)互操作,或者我们可以使用 jetpack compose 从 stratch 开发漂亮的日期时间选择器,就像 Flutter所做的那样
目前,
class DateTimeActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val c = Calendar.getInstance()
val year = c.get(Calendar.YEAR)
val month = c.get(Calendar.MONTH)
val day = c.get(Calendar.DAY_OF_MONTH)
val mHour = c[Calendar.HOUR_OF_DAY]
val mMinute = c[Calendar.MINUTE]
val datePickerDialog = DatePickerDialog(
this, DatePickerDialog.OnDateSetListener
{ datePicker: DatePicker, day: Int, month: Int, year: Int ->
setContent {
Column {
Text("$day, $month, $year")
}
}
}, year, month, day
)
val timePickerDialog = TimePickerDialog(
this,
TimePickerDialog.OnTimeSetListener { view, hourOfDay, minute ->
setContent {
Column {
Text("$hourOfDay:$minute")
}
}
}, mHour, mMinute, false
)
setContent {
Column {
Button(text = "Date",
style = OutlinedButtonStyle(),
onClick = {
datePickerDialog.show()
})
Button(text = "Time",
style = OutlinedButtonStyle(),
onClick = {
timePickerDialog.show()
})
}
}
}
}
您可以在 jetpack compose 中显示几行日期选择器
AndroidView(
{ CalendarView(it) },
modifier = Modifier.wrapContentWidth(),
update = { views ->
views.setOnDateChangeListener { calendarView, i, i2, i3 ->
}
}
)
没有 3rd 方库,使用 Android View 解决方案:
import android.app.TimePickerDialog
@Composable
fun ShowTimePicker(context: Context, initHour: Int, initMinute: Int) {
val time = remember { mutableStateOf("") }
val timePickerDialog = TimePickerDialog(
context,
{_, hour : Int, minute: Int ->
time.value = "$hour:$minute"
}, initHour, initMinute, false
)
Button(onClick = {
timePickerDialog.show()
}) {
Text(text = "Open Time Picker")
}
}
你可以使用 DatePickerDialog
val calendar = Calendar.getInstance()
val listener = DatePickerDialog.OnDateSetListener { view, year, month, dayOfMonth ->
calendar[Calendar.DAY_OF_MONTH] = dayOfMonth
calendar[Calendar.MONTH] = month
calendar[Calendar.YEAR] = year
selectedDate = calendar.timeInMillis
}
DatePickerDialog(
context,
listener,
calendar[Calendar.YEAR],
calendar[Calendar.MONTH],
calendar[Calendar.DAY_OF_MONTH]
).show()
据我所知,Jetpack Compose 中仍然缺少很多小部件。实现它们的唯一方法是使用 AndroidView 和膨胀布局。这是我的时间选择器代码: XML 文件:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TimePicker
android:id="@+id/simpleTimePicker"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:datePickerMode="spinner"
android:timePickerMode="spinner"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/btn_set_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Set Time"
android:textColor="#FFFFFF"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/simpleTimePicker"
tools:ignore="TextContrastCheck" />
<Button
android:id="@+id/btn_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Cancel"
android:textColor="#FFFFFF"
app:layout_constraintEnd_toStartOf="@+id/btn_set_time"
app:layout_constraintTop_toBottomOf="@+id/simpleTimePicker"
tools:ignore="TextContrastCheck" />
</androidx.constraintlayout.widget.ConstraintLayout>
还有我在 Kotlin 的 Jetpack compose 窗口中的代码:
Dialog(onDismissRequest = { timePickerStart = false }) {
AndroidView(
factory = { context: Context ->
LayoutInflater.from(context).inflate(R.layout.customtimepicker, null, false)
},
modifier = Modifier.fillMaxWidth()
.background(Color.White),
update = { view ->
val setTimebutton = view.findViewById<Button>(R.id.btn_set_time)
val cancelButton = view.findViewById<Button>(R.id.btn_cancel)
val simpleTimePicker = view.findViewById<TimePicker>(R.id.simpleTimePicker)
simpleTimePicker.setIs24HourView(true)
setTimebutton.setOnClickListener {
var hour = simpleTimePicker.hour
var minute = simpleTimePicker.minute
addNotePlusViewModel.startTime.value = convertToInstant(hour, minute)
timePickerStart = false
}
cancelButton.setOnClickListener {
timePickerStart = false
}
}
)
}
我创建了一个小型库,用于在 Compose 中呈现日历:https ://github.com/boguszpawlowski/ComposeCalendar 。它本身不是日期选择器,但您可以将其配置为表现得像一个。
你可以做这样的事情
import androidx.annotation.StringRes
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.remember
import com.google.android.material.datepicker.CalendarConstraints
import com.google.android.material.datepicker.MaterialDatePicker
import com.google.android.material.datepicker.MaterialPickerOnPositiveButtonClickListener
import java.util.*
import kotlin.time.Duration.Companion.hours
import kotlin.time.DurationUnit
@Composable
fun rememberDatePickerDialog(
@StringRes title: Int,
select: Date? = null,
bounds: CalendarConstraints? = null,
onDateSelected: (Date) -> Unit = {},
): MaterialDatePicker<Long> {
val datePicker = remember {
MaterialDatePicker.Builder.datePicker()
.setSelection((select?.time
?: Date().time) + 24.hours.toLong(DurationUnit.MILLISECONDS))
.setCalendarConstraints(bounds)
.setTitleText(title)
.build()
}
DisposableEffect(datePicker) {
val listener = MaterialPickerOnPositiveButtonClickListener<Long> {
if (it != null) onDateSelected(Date(it))
}
datePicker.addOnPositiveButtonClickListener(listener)
onDispose {
datePicker.removeOnPositiveButtonClickListener(listener)
}
}
return datePicker
}
FragmentManager
用于显示选择器(单击按钮)。在使用以下内容之前,请确保您的活动从 a开始。FragmentActivity
@Composable
fun rememberFragmentManager(): FragmentManager {
val context = LocalContext.current
return remember(context) {
(context as FragmentActivity).supportFragmentManager
}
}
示例用例。
val DATE_FORMAT = SimpleDateFormat("dd/MM/yyyy", Locale.getDefault())
var date by remember {
mutableStateOf(TextFieldValue(DATE_FORMAT.format(Date())))
}
val fragmentManager = rememberFragmentManager()
val datePicker = rememberDatePickerDialog(
select = DATE_FORMAT.parse(date.text),
title = R.string.select_date,
) { date = TextFieldValue(DATE_FORMAT.format(it)) }
TextField(
readOnly = true,
value = date,
onValueChange = { date = it },
trailingIcon = {
IconButton({ datePicker.show(fragmentManager, "Date") }) {
Icon(Icons.Default.DateRange,contentDescription = null)
}
},
)