Merge pull request #259 from TouchInstinct/new_filters_list
Фильтры: Выбор одного/нескольких из доступных значений списка
This commit is contained in:
commit
0650ba73a8
|
|
@ -0,0 +1 @@
|
||||||
|
/build
|
||||||
|
|
@ -0,0 +1,89 @@
|
||||||
|
# Описание
|
||||||
|
|
||||||
|
Модуль содержит реализацию следующих типов фильтров:
|
||||||
|
|
||||||
|
1. Выбор одного из доступных значений списка
|
||||||
|
2. Выбор нескольких доступных значений из списка
|
||||||
|
3. <em>добавить остальные по ходу реализаации</em>
|
||||||
|
|
||||||
|
# Использование
|
||||||
|
|
||||||
|
## Выбор одного/нескольких из доступных значений списка
|
||||||
|
|
||||||
|
### Как использовать
|
||||||
|
``` kotlin
|
||||||
|
val selectorView = ListSelectionView<DefaultSelectionItem, SelectionItemViewHolder<DefaultSelectionItem>>(context)
|
||||||
|
.Builder()
|
||||||
|
.setItems(navArgs.items)
|
||||||
|
.addItemDecoration((TopDividerItemDecoration(
|
||||||
|
context = requireContext(),
|
||||||
|
drawableId = R.drawable.list_divider_1dp,
|
||||||
|
startMargin = START_MARGIN_DIVIDER_DP.px
|
||||||
|
)))
|
||||||
|
.withSelectionType(ListSelectionView.SelectionType.SINGLE_SELECT)
|
||||||
|
.onResultListener { items ->
|
||||||
|
viewModel.dispatchAction(SelectItemAction.SelectItem(items))
|
||||||
|
}
|
||||||
|
.build()
|
||||||
|
```
|
||||||
|
### Конфигурации
|
||||||
|
* при создании `ListSelectionView<ItemType, HolderType>` необходимо передлать `ItemType` - класс модели данных в списке, `HolderType` - класс viewHolder-а в recyclerView.
|
||||||
|
Для использования дефолтной реализации необходимо использовать типы `<DefaultSelectionItem, SelectionItemViewHolder<DefaultSelectionItem>>`
|
||||||
|
* в метод `setItems(List<ItemType>)` необходимо передать список объектов
|
||||||
|
* метод `addItemDecoration(itemDecoration: RecyclerView.ItemDecoration)` можно использовать для передачи объекта `RecyclerView.ItemDecoration`
|
||||||
|
* метод `withSelectionType(type: SelectionType)` используется для указания типа выбора:
|
||||||
|
* `SINGLE_SELECT` - <em>по умолчанию</em> - позволяет выбрать один выариант, при этом будет выбран всегда как минимум один вариант
|
||||||
|
* `MULTI_SELECT` - позволяет выбрать несколько вариантов из списка, при этом можно полностью выбрать все варианты и убрать выделение со всех вариантов
|
||||||
|
* метод `showInHolder(HolderFactoryType<ItemType>)` используется для определения кастомного viewHolder для списка с недефолтной разметкой.
|
||||||
|
``` kotlin
|
||||||
|
val selectorView = ListSelectionView<TestSelectionItem, TestItemViewHolder>(context)
|
||||||
|
.Builder()
|
||||||
|
.showInHolder { parent, clickListener, selectionType ->
|
||||||
|
TestItemViewHolder(
|
||||||
|
binding = TestSelectionItemBinding.inflate(LayoutInflater.from(parent.context), parent, false),
|
||||||
|
onItemSelectAction = clickListener,
|
||||||
|
selectionType = selectionType
|
||||||
|
)
|
||||||
|
}
|
||||||
|
...
|
||||||
|
.build()
|
||||||
|
```
|
||||||
|
* колбэк `onSelectedItemsListener(listener: OnSelectedItemsListener<ItemType>)` можно использовать для получения списка всех элементов `ItemType` после каждого выбора
|
||||||
|
* колбэк `onSelectedItemListener(listener: OnSelectedItemListener<ItemType>)` можно использовать для получения элемента списка `ItemType`, по которому произошел клик
|
||||||
|
* после вызова конфигурационных методов обязательно необходимо вызать метод `build()`
|
||||||
|
|
||||||
|
### Кастомизация стиля дефолтной реализации ViewHolder без необходимости создания кастомного layout и viewHolder
|
||||||
|
|
||||||
|
#### 1. Определить кастомную тему и стили элементов
|
||||||
|
1. Стиль для **текста элемента списка** должен быть наследником стиля `Widget.FilterSelection.Item`
|
||||||
|
``` xml
|
||||||
|
<style name="Widget.Custom.FilterSelection.Item" parent="@style/Widget.FilterSelection.Item">
|
||||||
|
<item name="android:textAppearance">@style/Text15sp.Regular.Black</item>
|
||||||
|
<item name="android:paddingTop">2dp</item>
|
||||||
|
<item name="android:lineSpacingExtra">3sp</item>
|
||||||
|
<item name="android:translationY">-1.71sp</item>
|
||||||
|
</style>
|
||||||
|
```
|
||||||
|
2. Стиль для **индикатора выбора** должен быть наследником стиля `Widget.FilterSelection.Radio`
|
||||||
|
Передайте `selector-drawable` для кастомизации вида индикатора в конце строки
|
||||||
|
``` xml
|
||||||
|
<style name="Widget.Custom.FilterSelection.Radio" parent="@style/Widget.FilterSelection.Radio">
|
||||||
|
<item name="android:button">@drawable/selector_checkbox</item>
|
||||||
|
</style>
|
||||||
|
```
|
||||||
|
3. Создайте **тему**, которая должна быть наследником `Theme.FilterSelection`
|
||||||
|
``` xml
|
||||||
|
<style name="Theme.Custom.FilterSelection" parent="@style/Theme.FilterSelection">
|
||||||
|
<item name="sheetSelection_itemStyle">@style/Widget.Custom.FilterSelection.Item</item>
|
||||||
|
<item name="sheetSelection_radioStyle">@style/Widget.Custom.FilterSelection.Radio</item>
|
||||||
|
</style>
|
||||||
|
```
|
||||||
|
#### 2. Применить тему при создании view
|
||||||
|
При создании вью в коде можно указать тему, используя `ContextThemeWrapper`
|
||||||
|
``` kotlin
|
||||||
|
val newContext = ContextThemeWrapper(requireContext(), R.style.Theme_Custom_FilterSelection)
|
||||||
|
val selectorView = ListSelectionView(newContext)
|
||||||
|
.Builder()
|
||||||
|
...
|
||||||
|
.build()
|
||||||
|
```
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
apply from: "../android-configs/lib-config.gradle"
|
||||||
|
apply plugin: 'kotlin-parcelize'
|
||||||
|
|
||||||
|
android {
|
||||||
|
buildFeatures {
|
||||||
|
viewBinding true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation project(":utils")
|
||||||
|
implementation project(":recyclerview-adapters")
|
||||||
|
implementation project(":navigation-base")
|
||||||
|
implementation project(":kotlin-extensions")
|
||||||
|
|
||||||
|
implementation("org.jetbrains.kotlin:kotlin-stdlib")
|
||||||
|
|
||||||
|
implementation("androidx.core:core-ktx")
|
||||||
|
|
||||||
|
implementation("androidx.appcompat:appcompat")
|
||||||
|
implementation("com.google.android.material:material")
|
||||||
|
implementation("androidx.constraintlayout:constraintlayout") {
|
||||||
|
version {
|
||||||
|
require '2.0.0'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constraints {
|
||||||
|
implementation("androidx.appcompat:appcompat") {
|
||||||
|
version {
|
||||||
|
require '1.0.0'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
implementation("androidx.core:core-ktx") {
|
||||||
|
version {
|
||||||
|
require '1.0.0'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
<manifest
|
||||||
|
package="ru.touchin.roboswag.base_filters"/>
|
||||||
|
|
@ -0,0 +1,136 @@
|
||||||
|
package ru.touchin.roboswag.base_filters.select_list_item
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.view.ContextThemeWrapper
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
|
||||||
|
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
import androidx.annotation.StyleRes
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import ru.touchin.roboswag.base_filters.databinding.SelectionItemBinding
|
||||||
|
import ru.touchin.roboswag.base_filters.select_list_item.adapter.BaseSelectionViewHolder
|
||||||
|
import ru.touchin.roboswag.base_filters.select_list_item.adapter.HolderFactoryType
|
||||||
|
import ru.touchin.roboswag.base_filters.select_list_item.adapter.SelectionItemViewHolder
|
||||||
|
import ru.touchin.roboswag.base_filters.select_list_item.adapter.SheetSelectionAdapter
|
||||||
|
import ru.touchin.roboswag.base_filters.select_list_item.model.BaseSelectionItem
|
||||||
|
|
||||||
|
private typealias OnSelectedItemListener<ItemType> = (item: ItemType) -> Unit
|
||||||
|
private typealias OnSelectedItemsListener<ItemType> = (items: List<ItemType>) -> Unit
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base [ListSelectionView] to use in filters screen for choosing single or multi items in list.
|
||||||
|
*
|
||||||
|
* @param ItemType Type of model's element in list.
|
||||||
|
* It must implement [BaseSelectionItem] abstract class.
|
||||||
|
*
|
||||||
|
* @param HolderType Type of viewHolder in recyclerView.
|
||||||
|
* It must extend [BaseSelectionViewHolder] abstract class.
|
||||||
|
*
|
||||||
|
**/
|
||||||
|
|
||||||
|
class ListSelectionView<ItemType, HolderType> @JvmOverloads constructor(
|
||||||
|
context: Context,
|
||||||
|
attrs: AttributeSet? = null,
|
||||||
|
defStyleAttr: Int = 0
|
||||||
|
) : RecyclerView(context, attrs, defStyleAttr)
|
||||||
|
where ItemType : BaseSelectionItem,
|
||||||
|
HolderType : BaseSelectionViewHolder<ItemType> {
|
||||||
|
|
||||||
|
enum class SelectionType { SINGLE_SELECT, MULTI_SELECT }
|
||||||
|
|
||||||
|
constructor(context: Context, @StyleRes themeResId: Int) : this(ContextThemeWrapper(context, themeResId))
|
||||||
|
|
||||||
|
private var mutableItems: List<ItemType> = emptyList()
|
||||||
|
private var selectionType = SelectionType.SINGLE_SELECT
|
||||||
|
|
||||||
|
private var onSelectedItemChanged: OnSelectedItemListener<ItemType>? = null
|
||||||
|
private var onSelectedItemsChanged: OnSelectedItemsListener<ItemType>? = null
|
||||||
|
private var factory: HolderFactoryType<ItemType> = getDefaultFactory()
|
||||||
|
|
||||||
|
init {
|
||||||
|
layoutParams = ViewGroup.LayoutParams(MATCH_PARENT, WRAP_CONTENT)
|
||||||
|
layoutManager = LinearLayoutManager(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getDefaultFactory(): HolderFactoryType<ItemType> = { parent, clickListener, selectionType ->
|
||||||
|
SelectionItemViewHolder(
|
||||||
|
binding = SelectionItemBinding.inflate(LayoutInflater.from(parent.context), parent, false),
|
||||||
|
onItemSelectAction = clickListener,
|
||||||
|
selectionType = selectionType
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val selectionAdapter by lazy {
|
||||||
|
SheetSelectionAdapter(
|
||||||
|
onItemSelectAction = onItemSelectedListener,
|
||||||
|
selectionType = selectionType,
|
||||||
|
factory = factory
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val onItemSelectedListener: (item: ItemType) -> Unit = { item ->
|
||||||
|
onSelectedItemChanged?.invoke(item)
|
||||||
|
updateAfterSelection(item)
|
||||||
|
onSelectedItemsChanged?.invoke(mutableItems)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateItems(items: List<ItemType>) {
|
||||||
|
mutableItems = items
|
||||||
|
updateList()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateList() {
|
||||||
|
selectionAdapter.submitList(mutableItems)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateAfterSelection(selectedItem: ItemType) {
|
||||||
|
mutableItems = mutableItems.map { item ->
|
||||||
|
when {
|
||||||
|
item.isItemTheSame(selectedItem) -> selectedItem
|
||||||
|
selectionType == SelectionType.SINGLE_SELECT -> item.copyWithSelection(isSelected = false)
|
||||||
|
else -> item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateList()
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class Builder {
|
||||||
|
|
||||||
|
fun setItems(items: List<ItemType>) = apply {
|
||||||
|
mutableItems = items
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> setItems(
|
||||||
|
source: List<T>,
|
||||||
|
mapper: (T) -> ItemType
|
||||||
|
) = setItems(source.map { item -> mapper.invoke(item) })
|
||||||
|
|
||||||
|
fun showInHolder(holderFactory: HolderFactoryType<ItemType>) = apply {
|
||||||
|
factory = holderFactory
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addItemDecoration(itemDecoration: RecyclerView.ItemDecoration) = apply {
|
||||||
|
this@ListSelectionView.addItemDecoration(itemDecoration)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onSelectedItemListener(listener: OnSelectedItemListener<ItemType>) = apply {
|
||||||
|
this@ListSelectionView.onSelectedItemChanged = listener
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onSelectedItemsListener(listener: OnSelectedItemsListener<ItemType>) = apply {
|
||||||
|
this@ListSelectionView.onSelectedItemsChanged = listener
|
||||||
|
}
|
||||||
|
|
||||||
|
fun withSelectionType(type: SelectionType) = apply {
|
||||||
|
selectionType = type
|
||||||
|
}
|
||||||
|
|
||||||
|
fun build() = this@ListSelectionView.also {
|
||||||
|
it.adapter = selectionAdapter
|
||||||
|
updateList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
package ru.touchin.roboswag.base_filters.select_list_item.adapter
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import ru.touchin.roboswag.base_filters.select_list_item.model.BaseSelectionItem
|
||||||
|
|
||||||
|
abstract class BaseSelectionViewHolder<ItemType : BaseSelectionItem>(val view: View)
|
||||||
|
: RecyclerView.ViewHolder(view) {
|
||||||
|
|
||||||
|
abstract fun bind(item: ItemType)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
package ru.touchin.roboswag.base_filters.select_list_item.adapter
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import ru.touchin.roboswag.base_filters.databinding.SelectionItemBinding
|
||||||
|
import ru.touchin.roboswag.base_filters.select_list_item.ListSelectionView
|
||||||
|
import ru.touchin.roboswag.base_filters.select_list_item.model.BaseSelectionItem
|
||||||
|
|
||||||
|
class SelectionItemViewHolder<ItemType : BaseSelectionItem>(
|
||||||
|
private val binding: SelectionItemBinding,
|
||||||
|
private val onItemSelectAction: (ItemType) -> Unit,
|
||||||
|
private val selectionType: ListSelectionView.SelectionType
|
||||||
|
) : BaseSelectionViewHolder<ItemType>(binding.root) {
|
||||||
|
|
||||||
|
override fun bind(item: ItemType) {
|
||||||
|
binding.itemTitle.text = item.title
|
||||||
|
binding.itemRadiobutton.isChecked = item.isSelected
|
||||||
|
|
||||||
|
setupCheckListener(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupCheckListener(item: ItemType) = with(binding) {
|
||||||
|
val checkListener = View.OnClickListener {
|
||||||
|
itemRadiobutton.isChecked = true
|
||||||
|
onItemSelectAction.invoke(item.copyWithSelection(isSelected = when (selectionType) {
|
||||||
|
ListSelectionView.SelectionType.SINGLE_SELECT -> true
|
||||||
|
else -> !item.isSelected
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
root.setOnClickListener(checkListener)
|
||||||
|
itemRadiobutton.setOnClickListener(checkListener)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
package ru.touchin.roboswag.base_filters.select_list_item.adapter
|
||||||
|
|
||||||
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
|
import ru.touchin.roboswag.base_filters.select_list_item.ListSelectionView
|
||||||
|
import ru.touchin.roboswag.base_filters.select_list_item.model.BaseSelectionItem
|
||||||
|
import ru.touchin.roboswag.recyclerview_adapters.adapters.DelegationListAdapter
|
||||||
|
|
||||||
|
class SheetSelectionAdapter<ItemType : BaseSelectionItem>(
|
||||||
|
onItemSelectAction: (ItemType) -> Unit,
|
||||||
|
selectionType: ListSelectionView.SelectionType,
|
||||||
|
factory: HolderFactoryType<ItemType>
|
||||||
|
) : DelegationListAdapter<BaseSelectionItem>(object : DiffUtil.ItemCallback<BaseSelectionItem>() {
|
||||||
|
|
||||||
|
override fun areItemsTheSame(oldItem: BaseSelectionItem, newItem: BaseSelectionItem): Boolean =
|
||||||
|
oldItem.isItemTheSame(newItem)
|
||||||
|
|
||||||
|
override fun areContentsTheSame(oldItem: BaseSelectionItem, newItem: BaseSelectionItem): Boolean =
|
||||||
|
oldItem.isContentTheSame(newItem)
|
||||||
|
|
||||||
|
}) {
|
||||||
|
|
||||||
|
init {
|
||||||
|
addDelegate(SheetSelectionDelegate(
|
||||||
|
onItemSelectAction = onItemSelectAction,
|
||||||
|
selectionType = selectionType,
|
||||||
|
factory = factory
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
package ru.touchin.roboswag.base_filters.select_list_item.adapter
|
||||||
|
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import ru.touchin.roboswag.base_filters.select_list_item.ListSelectionView.SelectionType
|
||||||
|
import ru.touchin.roboswag.base_filters.select_list_item.model.BaseSelectionItem
|
||||||
|
import ru.touchin.roboswag.recyclerview_adapters.adapters.ItemAdapterDelegate
|
||||||
|
|
||||||
|
typealias HolderFactoryType<ItemType> = (ViewGroup, (ItemType) -> Unit, SelectionType) -> BaseSelectionViewHolder<ItemType>
|
||||||
|
|
||||||
|
class SheetSelectionDelegate<ItemType>(
|
||||||
|
private val onItemSelectAction: (ItemType) -> Unit,
|
||||||
|
private val selectionType: SelectionType,
|
||||||
|
private val factory: HolderFactoryType<ItemType>
|
||||||
|
) : ItemAdapterDelegate<BaseSelectionViewHolder<ItemType>, ItemType>()
|
||||||
|
where ItemType : BaseSelectionItem {
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup): BaseSelectionViewHolder<ItemType> =
|
||||||
|
factory.invoke(parent, onItemSelectAction, selectionType)
|
||||||
|
|
||||||
|
override fun onBindViewHolder(
|
||||||
|
holder: BaseSelectionViewHolder<ItemType>,
|
||||||
|
item: ItemType,
|
||||||
|
adapterPosition: Int,
|
||||||
|
collectionPosition: Int,
|
||||||
|
payloads: MutableList<Any>
|
||||||
|
) = holder.bind(item)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
package ru.touchin.roboswag.base_filters.select_list_item.model
|
||||||
|
|
||||||
|
abstract class BaseSelectionItem(
|
||||||
|
open val id: Int,
|
||||||
|
open val title: String,
|
||||||
|
open val isSelected: Boolean
|
||||||
|
) {
|
||||||
|
|
||||||
|
abstract fun isItemTheSame(compareItem: BaseSelectionItem): Boolean
|
||||||
|
|
||||||
|
abstract fun isContentTheSame(compareItem: BaseSelectionItem): Boolean
|
||||||
|
|
||||||
|
abstract fun <ItemType> copyWithSelection(isSelected: Boolean): ItemType
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
package ru.touchin.roboswag.base_filters.select_list_item.model
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
data class DefaultSelectionItem(
|
||||||
|
override val id: Int,
|
||||||
|
override val title: String,
|
||||||
|
override val isSelected: Boolean = false
|
||||||
|
) : BaseSelectionItem(id, title, isSelected), Parcelable {
|
||||||
|
|
||||||
|
override fun isItemTheSame(compareItem: BaseSelectionItem): Boolean = when {
|
||||||
|
compareItem is DefaultSelectionItem && id == compareItem.id -> true
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isContentTheSame(compareItem: BaseSelectionItem): Boolean =
|
||||||
|
this == compareItem
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
override fun <ItemType> copyWithSelection(isSelected: Boolean): ItemType =
|
||||||
|
this.copy(isSelected = isSelected) as ItemType
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?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="wrap_content">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/item_title"
|
||||||
|
style="?attr/sheetSelection_itemStyle"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/item_radiobutton"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
tools:text="Заголовок" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatRadioButton
|
||||||
|
android:id="@+id/item_radiobutton"
|
||||||
|
style="?attr/sheetSelection_radioStyle"
|
||||||
|
android:layout_width="22dp"
|
||||||
|
android:layout_height="22dp"
|
||||||
|
android:checked="true"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
|
||||||
|
<declare-styleable name="FilterSelection">
|
||||||
|
<attr name="sheetSelection_itemStyle" format="reference" />
|
||||||
|
<attr name="sheetSelection_radioStyle" format="reference" />
|
||||||
|
</declare-styleable>
|
||||||
|
|
||||||
|
</resources>
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
|
||||||
|
<style name="Theme.FilterSelection" parent="@style/Theme.MaterialComponents.Light.BottomSheetDialog">
|
||||||
|
<item name="sheetSelection_itemStyle">@style/Widget.FilterSelection.Item</item>
|
||||||
|
<item name="sheetSelection_radioStyle">@style/Widget.FilterSelection.Radio</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="Widget.FilterSelection.Item" parent="@style/Widget.MaterialComponents.TextView">
|
||||||
|
<item name="android:layout_margin">16dp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="Widget.FilterSelection.Radio" parent="@style/Widget.MaterialComponents.CompoundButton.RadioButton">
|
||||||
|
<item name="android:layout_marginTop">16dp</item>
|
||||||
|
<item name="android:layout_marginEnd">16dp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
</resources>
|
||||||
Loading…
Reference in New Issue