是否可以向 MaterialDateRange Picker 添加页脚?
Is it possible to add a footer to the MaterialDateRange Picker?
我很确定这是不可能的,但我只是想在使用第 3 方库之前检查一下。 DatePicker 并不能真正让您自定义 UI,它基本上是一个全屏 DialogFragment,因此在上方或下方(甚至在顶部)放置某些内容似乎不是一个选项。
我的日历目前是这样的:
但我希望它看起来像这个底部有页脚的设计文档。如果您有任何想法,请告诉我,因为我不在其中。谢谢!
val builder = MaterialDatePicker.Builder.dateRangePicker()
.setTheme(R.style.ThemeOverlay_MaterialComponents_MaterialCalendar_Fullscreen)
.setCalendarConstraints(
CalendarConstraints.Builder()
.setStart(Date().time)
.setEnd(oneYearFrom().time)
.setValidator(AvailabilityValidator(it.unavailableDays)).build()
)
builder.setInputMode(MaterialDatePicker.INPUT_MODE_CALENDAR)
builder.build().show(requireActivity().supportFragmentManager, TAG_DATE_RANGE_PICKER)
向 MaterialDateRangePicker
添加页脚的唯一方法是访问 Picker 根视图,从那里您可以找到 Picker FrameLayout Container
(ID 为 app:id/mtrl_calendar_frame
)和访问它的子视图 Vertical LinearLayout Container
,其中包含三个子视图:(一个 Days-GridView
、一个 Separator-View
和一个 RecyclerView
)在垂直方向。您想要的是在 RecyclerView 下方添加一个页脚。因为父级是 LinearLayout,所以您可以将 weight
属性添加到它的所有子级,使其成为 weight=0
除了 RecyclerView
(呈现月份)是 weight=1
以获得所有剩下的 space.
要访问 Picker 根视图,您必须观察 MaterialDatePicker
(DialogFragment) 生命周期并在 DialogFragment 的 onStart()
中添加页脚视图。为此,您可以使用 DefaultLifecycleObserver
.
下面是添加页脚视图的完整工作示例:
private fun showRangeDatePicker() {
//initialize dateRangePicker
val builder = MaterialDatePicker.Builder.dateRangePicker()
builder.setTheme(R.style.ThemeOverlay_MaterialComponents_MaterialCalendar_Fullscreen)
//set CalendarConstraints
val constraintsBuilder = CalendarConstraints.Builder()
val c: Calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"))
constraintsBuilder.setStart(c.getTimeInMillis())
c.add(Calendar.YEAR, 1)
constraintsBuilder.setEnd(c.getTimeInMillis())
builder.setCalendarConstraints(constraintsBuilder.build())
//set InputMode and Title
builder.setInputMode(MaterialDatePicker.INPUT_MODE_CALENDAR)
builder.setTitleText("Pick dates")
//get MaterialDatePicker instance and set a lifecycle Observer to listen for DialogFragment lifecycle
//DefaultLifecycleObserver needs androidx.appcompat:appcompat:1.4.0 and add the FooterView in onStart of DialogFragment
val picker: MaterialDatePicker<*> = builder.build()
picker.lifecycle.addObserver(object : DefaultLifecycleObserver
{
override fun onCreate(owner: LifecycleOwner) {
}
override fun onStart(owner: LifecycleOwner) {
//add footerView in onStart of DialogFragment so you can access the picker.view
addMyFooterView(picker)
}
override fun onResume(owner: LifecycleOwner) {
}
override fun onDestroy(owner: LifecycleOwner) {
//remove Lifecycle Observer
picker.lifecycle.removeObserver(this)
}
})
picker.show(supportFragmentManager, picker.toString())
}
private fun addMyFooterView(picker: MaterialDatePicker<*>) {
//get the MaterialDatePicker root View
val rootView = picker.view as LinearLayout
//find the Picker FrameLayout Container with ID: app:id/mtrl_calendar_frame
val frameLayout = rootView.findViewById<FrameLayout>(resources.getIdentifier("mtrl_calendar_frame", "id", packageName))
//and get the Picker LinearLayout Container (which contains of 3 children: Days-GridView, Separator-View and a RecyclerView)
val linearContainer = frameLayout.getChildAt(0) as LinearLayout
//for each child in Vertical LinearLayout Container set the weight to RecyclerView to 1 and 0 to all others.
//(This is necessary before adding the footerView to distribute correctly each children Height)
for (i in 0 until linearContainer.childCount) {
val v = linearContainer.getChildAt(i)
val params = v.layoutParams as LinearLayout.LayoutParams
params.weight = if (v is RecyclerView) 1f else 0f
v.layoutParams = params
}
//and finally add the 4th child in the above linearContainer to be the FooterView
val myFooterView = layoutInflater.inflate(R.layout.footer_layout, null)
val myFooterViewHeight = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50f, resources.displayMetrics).toInt()
myFooterView.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, myFooterViewHeight, 0f)
myFooterView.setBackgroundColor(Color.WHITE)
linearContainer.addView(myFooterView)
//set any FooterView click listeners
myFooterView.findViewById<View>(R.id.textView2).setOnClickListener {}
}
其中 footer_layout
是您的自定义页脚 xml 布局,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="50dp">
<View
android:id="@+id/separatorView"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_alignParentTop="true"
android:background="@android:color/darker_gray"/>
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15sp"
android:textStyle="bold"
android:layout_marginEnd="10dp"
android:layout_centerVertical="true"
android:layout_alignParentStart="true"
android:text="Match exact dates" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15sp"
android:textStyle="normal"
android:layout_marginEnd="10dp"
android:layout_centerVertical="true"
android:layout_toEndOf="@+id/textView1"
android:text="±1 day" />
<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15sp"
android:textStyle="normal"
android:layout_marginEnd="10dp"
android:layout_centerVertical="true"
android:layout_toEndOf="@+id/textView2"
android:text="±3 days" />
</RelativeLayout>
结果:
我很确定这是不可能的,但我只是想在使用第 3 方库之前检查一下。 DatePicker 并不能真正让您自定义 UI,它基本上是一个全屏 DialogFragment,因此在上方或下方(甚至在顶部)放置某些内容似乎不是一个选项。
我的日历目前是这样的:
但我希望它看起来像这个底部有页脚的设计文档。如果您有任何想法,请告诉我,因为我不在其中。谢谢!
val builder = MaterialDatePicker.Builder.dateRangePicker()
.setTheme(R.style.ThemeOverlay_MaterialComponents_MaterialCalendar_Fullscreen)
.setCalendarConstraints(
CalendarConstraints.Builder()
.setStart(Date().time)
.setEnd(oneYearFrom().time)
.setValidator(AvailabilityValidator(it.unavailableDays)).build()
)
builder.setInputMode(MaterialDatePicker.INPUT_MODE_CALENDAR)
builder.build().show(requireActivity().supportFragmentManager, TAG_DATE_RANGE_PICKER)
向 MaterialDateRangePicker
添加页脚的唯一方法是访问 Picker 根视图,从那里您可以找到 Picker FrameLayout Container
(ID 为 app:id/mtrl_calendar_frame
)和访问它的子视图 Vertical LinearLayout Container
,其中包含三个子视图:(一个 Days-GridView
、一个 Separator-View
和一个 RecyclerView
)在垂直方向。您想要的是在 RecyclerView 下方添加一个页脚。因为父级是 LinearLayout,所以您可以将 weight
属性添加到它的所有子级,使其成为 weight=0
除了 RecyclerView
(呈现月份)是 weight=1
以获得所有剩下的 space.
要访问 Picker 根视图,您必须观察 MaterialDatePicker
(DialogFragment) 生命周期并在 DialogFragment 的 onStart()
中添加页脚视图。为此,您可以使用 DefaultLifecycleObserver
.
下面是添加页脚视图的完整工作示例:
private fun showRangeDatePicker() {
//initialize dateRangePicker
val builder = MaterialDatePicker.Builder.dateRangePicker()
builder.setTheme(R.style.ThemeOverlay_MaterialComponents_MaterialCalendar_Fullscreen)
//set CalendarConstraints
val constraintsBuilder = CalendarConstraints.Builder()
val c: Calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"))
constraintsBuilder.setStart(c.getTimeInMillis())
c.add(Calendar.YEAR, 1)
constraintsBuilder.setEnd(c.getTimeInMillis())
builder.setCalendarConstraints(constraintsBuilder.build())
//set InputMode and Title
builder.setInputMode(MaterialDatePicker.INPUT_MODE_CALENDAR)
builder.setTitleText("Pick dates")
//get MaterialDatePicker instance and set a lifecycle Observer to listen for DialogFragment lifecycle
//DefaultLifecycleObserver needs androidx.appcompat:appcompat:1.4.0 and add the FooterView in onStart of DialogFragment
val picker: MaterialDatePicker<*> = builder.build()
picker.lifecycle.addObserver(object : DefaultLifecycleObserver
{
override fun onCreate(owner: LifecycleOwner) {
}
override fun onStart(owner: LifecycleOwner) {
//add footerView in onStart of DialogFragment so you can access the picker.view
addMyFooterView(picker)
}
override fun onResume(owner: LifecycleOwner) {
}
override fun onDestroy(owner: LifecycleOwner) {
//remove Lifecycle Observer
picker.lifecycle.removeObserver(this)
}
})
picker.show(supportFragmentManager, picker.toString())
}
private fun addMyFooterView(picker: MaterialDatePicker<*>) {
//get the MaterialDatePicker root View
val rootView = picker.view as LinearLayout
//find the Picker FrameLayout Container with ID: app:id/mtrl_calendar_frame
val frameLayout = rootView.findViewById<FrameLayout>(resources.getIdentifier("mtrl_calendar_frame", "id", packageName))
//and get the Picker LinearLayout Container (which contains of 3 children: Days-GridView, Separator-View and a RecyclerView)
val linearContainer = frameLayout.getChildAt(0) as LinearLayout
//for each child in Vertical LinearLayout Container set the weight to RecyclerView to 1 and 0 to all others.
//(This is necessary before adding the footerView to distribute correctly each children Height)
for (i in 0 until linearContainer.childCount) {
val v = linearContainer.getChildAt(i)
val params = v.layoutParams as LinearLayout.LayoutParams
params.weight = if (v is RecyclerView) 1f else 0f
v.layoutParams = params
}
//and finally add the 4th child in the above linearContainer to be the FooterView
val myFooterView = layoutInflater.inflate(R.layout.footer_layout, null)
val myFooterViewHeight = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50f, resources.displayMetrics).toInt()
myFooterView.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, myFooterViewHeight, 0f)
myFooterView.setBackgroundColor(Color.WHITE)
linearContainer.addView(myFooterView)
//set any FooterView click listeners
myFooterView.findViewById<View>(R.id.textView2).setOnClickListener {}
}
其中 footer_layout
是您的自定义页脚 xml 布局,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="50dp">
<View
android:id="@+id/separatorView"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_alignParentTop="true"
android:background="@android:color/darker_gray"/>
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15sp"
android:textStyle="bold"
android:layout_marginEnd="10dp"
android:layout_centerVertical="true"
android:layout_alignParentStart="true"
android:text="Match exact dates" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15sp"
android:textStyle="normal"
android:layout_marginEnd="10dp"
android:layout_centerVertical="true"
android:layout_toEndOf="@+id/textView1"
android:text="±1 day" />
<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15sp"
android:textStyle="normal"
android:layout_marginEnd="10dp"
android:layout_centerVertical="true"
android:layout_toEndOf="@+id/textView2"
android:text="±3 days" />
</RelativeLayout>
结果: