Merge pull request #263 from TouchInstinct/range_filter

Фильтры: Выбор минимального и максимального значения из диапозона
This commit is contained in:
Grigorii 2022-10-17 12:30:50 +04:00 committed by GitHub
commit 3a3ad0211a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 664 additions and 2 deletions

View File

@ -4,6 +4,7 @@
1. Выбор одного/нескольких из доступных значений списка
2. Выбор одного/нескольких значений из перечня тегов
3. Выбор минимального и максимального значения из диапозона
# Использование
@ -89,8 +90,8 @@ val selectorView = ListSelectionView(newContext)
## 2. Выбор одного/нескольких значений из перечня тегов
`TagLayoutView` - view-контейнер для тегов
`TagView` - view для тега. <em>Кастомная разметка для тега должна содержать в корне `TagView`</em>
* `TagLayoutView` - view-контейнер для тегов
* `TagView` - view для тега. <em>Кастомная разметка для тега должна содержать в корне `TagView`</em>
### Как использовать
``` kotlin
@ -116,3 +117,62 @@ binding.tagItemLayout
* `onMoreValuesAction(FilterMoreAction)` и `onPropertySelectedAction(PropertySelectedAction)` используются для передачи колбэков на клик по тегу типа "Еще" и обычного тега соответственно
* после вызова конфигурационных методов обязательно необходимо вызать метод `build()`
* в Builder необходимо передать объект `filterItem: FilterItem`
## 3. Выбор минимального и максимального значения из диапозона
* `RangeChoiceView` - контейнер для слайдера и редактируемых полей
* `FilterRangeSlider` - слайдер - <em>Можно использовать как отдельный элемент</em>
* `HintInputView` - view для редактируемого поля начала и окончания диапозона
### Как использовать
В разметке
``` xml
<ru.touchin.roboswag.base_filters.range.RangeChoiceView
android:id="@+id/range_values_test"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/FilterRangeChoice" //не забудьте указать стиль
app:layout_constraintTop_toTopOf="parent" />
```
Настройка в коде
``` kotlin
fun setupValues(item: FilterRangeItem) {
binding.rangeValuesTest.setupRangeValues(
rangeFilterItem = item,
onChangeCallback = callback
)
}
fun resetValues() {
binding.rangeValuesTest.resetRangeValue()
}
```
### Конфигурации
Вся конфигурация вьюх осуществляется через стили:
* Для `RangeChoiceView`:
* `filterRange_sliderMargin` - расстояние от слайдера до редактируемых полей
* `filterRange_startHint` - ссылка на строку с текстом подсказки в редактируемом поле для начального значения
* `filterRange_endHint` - ссылка на строку с текстом подсказки в редактируемом поле для конечного значения
* `filterRange_theme` - ссылка на тему
* В теме:
* атрибут `filterRange_sliderStyle` - ссылка на стиль слайдера
* атрибут `filterRange_hintViewStyle` - ссылка на стиль `HintInputView`
* атрибут `filterRange_hintTextStyle` - ссылка на стиль `TextView` внутри `HintInputView`
* атрибут `filterRange_valueEditTextStyle` - ссылка на стиль `EditText` внутри `HintInputView`
* Для `FilterRangeSlider`:
* `trackColorActive`
* `trackColorInactive`
* `trackHeight`
* `thumbElevation`
* `thumbColor`
* `labelBehavior`
* `haloRadius`
* `filterRange_stepTextAppearance`
* `filterRange_activeTickColor`
* `filterRange_inactiveTickColor`
* `filterRange_stepValueMarginTop`
* `filterRange_sliderPointSize`
* `filterRange_pointShape`

View File

@ -0,0 +1,173 @@
package ru.touchin.roboswag.base_filters.range
import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Paint.Cap
import android.util.AttributeSet
import androidx.annotation.StyleRes
import androidx.appcompat.widget.AppCompatTextView
import androidx.core.content.withStyledAttributes
import androidx.core.widget.TextViewCompat
import com.google.android.material.shape.CornerFamily
import com.google.android.material.shape.MaterialShapeDrawable
import com.google.android.material.shape.ShapeAppearanceModel
import com.google.android.material.slider.RangeSlider
import ru.touchin.roboswag.base_filters.R
import ru.touchin.roboswag.components.utils.getColorSimple
class FilterRangeSlider @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0,
defStyleRes: Int = 0
) : RangeSlider(context, attrs, defStyleAttr) {
var points: List<Int>? = null
set(value) {
field = value?.sorted()?.filter { it > valueFrom && it < valueTo }
}
private val innerThumbRadius: Int = thumbRadius
private var stepValueMarginTop = 0f
private var inactiveTickColor: Int = context.getColorSimple(R.color.slider_point_inactive)
private var activeTickColor: Int = context.getColorSimple(R.color.slider_point_active)
private var sliderPointSize: Float = 5f
@StyleRes
private var stepTextAppearance: Int = -1
private var shape: Shape = Shape.CIRCLE
private var trackCenterY: Float = -1F
init {
// Set original thumb radius to zero to draw custom one on top
thumbRadius = 0
context.withStyledAttributes(attrs, R.styleable.FilterRangeSlider, defStyleAttr, defStyleRes) {
stepValueMarginTop = getDimension(R.styleable.FilterRangeSlider_filterRange_stepValueMarginTop, stepValueMarginTop)
inactiveTickColor = getColor(R.styleable.FilterRangeSlider_filterRange_inactiveTickColor, inactiveTickColor)
activeTickColor = getColor(R.styleable.FilterRangeSlider_filterRange_activeTickColor, activeTickColor)
sliderPointSize = getDimension(R.styleable.FilterRangeSlider_filterRange_sliderPointSize, sliderPointSize)
stepTextAppearance = getResourceId(R.styleable.FilterRangeSlider_filterRange_stepTextAppearance, -1)
shape = Shape.values()[getInt(R.styleable.FilterRangeSlider_filterRange_pointShape, Shape.CIRCLE.ordinal)]
}
}
private val thumbDrawable = MaterialShapeDrawable().apply {
shadowCompatibilityMode = MaterialShapeDrawable.SHADOW_COMPAT_MODE_ALWAYS
setBounds(0, 0, innerThumbRadius * 2, innerThumbRadius * 2)
elevation = thumbElevation
state = drawableState
fillColor = thumbTintList
shapeAppearanceModel = ShapeAppearanceModel
.builder()
.setAllCorners(shape.value, innerThumbRadius.toFloat())
.build()
}
private val inactiveTicksPaint = getDefaultTickPaint().apply { color = inactiveTickColor }
private val activeTicksPaint = getDefaultTickPaint().apply { color = activeTickColor }
private fun getDefaultTickPaint() = Paint().apply {
isAntiAlias = true
style = Paint.Style.STROKE
strokeCap = Cap.ROUND
strokeWidth = sliderPointSize
}
// Using TextView as a bridge to get text params
private val stepValuePaint: Paint = AppCompatTextView(context).apply {
stepTextAppearance.takeIf { it != -1 }?.let { TextViewCompat.setTextAppearance(this, it) }
}.let { textView ->
Paint().apply {
isAntiAlias = true
color = textView.currentTextColor
textSize = textView.textSize
typeface = textView.typeface
textAlign = Paint.Align.CENTER
}
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
trackCenterY = measuredHeight / 2F
val height = trackCenterY + trackHeight / 2F + stepValueMarginTop + stepValuePaint.textSize
setMeasuredDimension(measuredWidth, height.toInt())
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
drawTicks(canvas)
drawThumb(canvas)
drawStepValues(canvas)
}
private fun drawTicks(canvas: Canvas) {
if (points.isNullOrEmpty()) return
val ticksCoordinates = mutableListOf<Float>()
points?.forEach { point ->
ticksCoordinates.add(normalizeValue(point.toFloat()) * trackWidth + trackSidePadding)
ticksCoordinates.add(trackCenterY)
}
val leftPointsSize = points?.count { it < values[0] } ?: 0
val rightPointSize = points?.count { it > values[1] } ?: 0
val activePointSize = (points?.size ?: 0) - leftPointsSize - rightPointSize
// Draw inactive ticks to the left of the smallest thumb.
canvas.drawPoints(ticksCoordinates.toFloatArray(), 0, leftPointsSize * 2, inactiveTicksPaint)
// Draw active ticks between the thumbs.
canvas.drawPoints(
ticksCoordinates.toFloatArray(),
leftPointsSize * 2,
activePointSize * 2,
activeTicksPaint
)
// Draw inactive ticks to the right of the largest thumb.
canvas.drawPoints(
ticksCoordinates.toFloatArray(),
leftPointsSize * 2 + activePointSize * 2,
rightPointSize * 2,
inactiveTicksPaint
)
}
private fun drawThumb(canvas: Canvas) {
for (value in values) {
canvas.save()
canvas.translate(
(trackSidePadding + (normalizeValue(value) * trackWidth).toInt() - innerThumbRadius).toFloat(),
trackCenterY - innerThumbRadius
)
thumbDrawable.draw(canvas)
canvas.restore()
}
}
private fun drawStepValues(canvas: Canvas) {
points?.forEach { point ->
canvas.drawText(
point.toString(),
normalizeValue(point.toFloat()) * trackWidth + trackSidePadding,
trackCenterY + trackHeight / 2F + stepValueMarginTop + stepValuePaint.textSize - 3F,
stepValuePaint
)
}
}
private fun normalizeValue(value: Float) = (value - valueFrom) / (valueTo - valueFrom)
private enum class Shape(val value: Int) {
CIRCLE(CornerFamily.ROUNDED),
CUT(CornerFamily.CUT)
}
}

View File

@ -0,0 +1,39 @@
package ru.touchin.roboswag.base_filters.range
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import ru.touchin.roboswag.base_filters.databinding.ViewHintInputBinding
class HintInputView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0,
defStyleRes: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr, defStyleRes) {
private val binding = ViewHintInputBinding.inflate(LayoutInflater.from(context), this)
var inputText: String = ""
set(value) {
setText(value)
field = value
}
fun setHint(value: String?) {
binding.startHint.text = value.orEmpty()
}
fun setOnEditorActionListener(listener: TextView.OnEditorActionListener) =
binding.editText.setOnEditorActionListener(listener)
private fun setText(value: String) {
binding.editText.run {
setText(value)
setSelection(text?.length ?: 0)
}
}
}

View File

@ -0,0 +1,168 @@
package ru.touchin.roboswag.base_filters.range
import android.annotation.SuppressLint
import android.content.Context
import android.util.AttributeSet
import android.view.ContextThemeWrapper
import android.view.LayoutInflater
import android.view.inputmethod.EditorInfo
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.withStyledAttributes
import androidx.core.view.updateLayoutParams
import com.google.android.material.slider.RangeSlider
import ru.touchin.roboswag.base_filters.R
import ru.touchin.roboswag.base_filters.databinding.RangeChoiceViewBinding
import ru.touchin.roboswag.base_filters.range.model.FilterRangeItem
import ru.touchin.roboswag.base_filters.range.model.SelectedValues
import kotlin.properties.Delegates
typealias FilterRangeChanged = (FilterRangeItem) -> Unit
class RangeChoiceView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0,
defStyleRes: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr, defStyleRes) {
private val defaultTheme = R.style.Theme_FilterRangeSlider
private var binding: RangeChoiceViewBinding by Delegates.notNull()
private var valueChangedAction: FilterRangeChanged? = null
private var rangeItem: FilterRangeItem? = null
set(value) {
field = value
binding.fromInput.inputText = value?.selectedValues?.min?.toString()
?: value?.start?.toString().orEmpty()
binding.toInput.inputText = value?.selectedValues?.max?.toString()
?: value?.end?.toString().orEmpty()
binding.rangeSlider.run {
values = listOf(
value?.selectedValues?.min?.toFloat() ?: value?.start?.toFloat(),
value?.selectedValues?.max?.toFloat() ?: value?.end?.toFloat()
)
}
}
init {
context.withStyledAttributes(attrs, R.styleable.FilterRangeChoice, defStyleAttr, defStyleRes) {
val theme = getResourceId(R.styleable.FilterRangeChoice_filterRange_theme, defaultTheme)
val themeContext = ContextThemeWrapper(context, theme)
binding = RangeChoiceViewBinding.inflate(LayoutInflater.from(themeContext), this@RangeChoiceView)
binding.fromInput.setHint(getString(R.styleable.FilterRangeChoice_filterRange_startHint))
binding.toInput.setHint(getString(R.styleable.FilterRangeChoice_filterRange_endHint))
binding.rangeSliderGuideline.updateLayoutParams<MarginLayoutParams> {
topMargin = getDimension(R.styleable.FilterRangeChoice_filterRange_sliderMargin, 0f).toInt()
}
}
}
fun setupRangeValues(
rangeFilterItem: FilterRangeItem,
onChangeCallback: FilterRangeChanged
) {
rangeItem = rangeFilterItem
valueChangedAction = onChangeCallback
with(binding) {
addChangeValuesListener()
setupRangeSlider(rangeFilterItem)
}
}
fun resetRangeValue() {
rangeItem = rangeItem?.resetSelectedValues()
}
private fun addChangeValuesListener() {
binding.fromInput.addChangeValueListener { rangeItem?.setValue(selectedMinValue = it.toIntOrNull()) }
binding.toInput.addChangeValueListener { rangeItem?.setValue(selectedMaxValue = it.toIntOrNull()) }
}
private fun setupRangeSlider(rangeFilterItem: FilterRangeItem) {
with(binding) {
rangeSlider.apply {
valueFrom = rangeFilterItem.start.toFloat()
valueTo = rangeFilterItem.end.toFloat()
points = rangeFilterItem.intermediates
}
rangeSlider.addOnChangeListener { _, _, _ ->
fromInput.inputText = rangeSlider.values[0].toInt().toString()
toInput.inputText = rangeSlider.values[1].toInt().toString()
}
rangeSlider.addOnSliderTouchListener(object : RangeSlider.OnSliderTouchListener {
@SuppressLint("RestrictedApi")
override fun onStartTrackingTouch(slider: RangeSlider) = Unit
@SuppressLint("RestrictedApi")
override fun onStopTrackingTouch(slider: RangeSlider) {
binding.rangeSlider.apply {
when (focusedThumbIndex) {
0 -> {
rangeItem = rangeItem?.setValue(selectedMinValue = from().toInt())
rangeItem?.let { valueChangedAction?.invoke(it) }
}
1 -> {
rangeItem = rangeItem?.setValue(selectedMaxValue = to().toInt())
rangeItem?.let { valueChangedAction?.invoke(it) }
}
}
}
}
})
}
}
private fun HintInputView.addChangeValueListener(updateValue: (String) -> FilterRangeItem?) {
setOnEditorActionListener { view, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_DONE) {
rangeItem = updateValue(view.text.toString().filterNot { it.isWhitespace() })
rangeItem?.let { valueChangedAction?.invoke(it) }
}
false
}
}
private fun RangeSlider.from() = values[0].toInt().toString()
private fun RangeSlider.to() = values[1].toInt().toString()
@SuppressWarnings("detekt.ComplexMethod")
private fun FilterRangeItem.setValue(
selectedMaxValue: Int? = selectedValues?.max,
selectedMinValue: Int? = selectedValues?.min
): FilterRangeItem {
val isMaxValueUpdated = selectedMaxValue != selectedValues?.max
val isMinValueUpdated = selectedMinValue != selectedValues?.min
val isMinValueOutOfRange = selectedMinValue != null && isMinValueUpdated && selectedMinValue > (selectedMaxValue ?: end)
val isMaxValueOutOfRange = selectedMaxValue != null && isMaxValueUpdated && selectedMaxValue < (selectedMinValue ?: start)
val updatedValues = when {
selectedMaxValue == end && selectedMinValue == start -> null
isMinValueOutOfRange -> SelectedValues(
max = selectedMaxValue ?: end,
min = selectedMaxValue ?: end
)
isMaxValueOutOfRange -> SelectedValues(
max = selectedMinValue ?: start,
min = selectedMinValue ?: start
)
else -> SelectedValues(
max = selectedMaxValue?.takeIf { it < end } ?: end,
min = selectedMinValue?.takeIf { it > start } ?: start
)
}
return copyWithSelectedValue(selectedValues = updatedValues)
}
private fun FilterRangeItem.resetSelectedValues() = copyWithSelectedValue(selectedValues = null)
}

View File

@ -0,0 +1,34 @@
package ru.touchin.roboswag.base_filters.range.model
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
@Parcelize
open class FilterRangeItem(
val id: String,
val start: Int,
val end: Int,
val title: String,
val intermediates: List<Int>? = null,
val step: Int? = null,
val selectedValues: SelectedValues? = null
) : Parcelable {
fun isCorrectValues() = end > start
fun copyWithSelectedValue(selectedValues: SelectedValues?) = FilterRangeItem(
id = id,
start = start,
end = end,
title = title,
intermediates = intermediates,
step = step,
selectedValues = selectedValues
)
}
@Parcelize
data class SelectedValues(
val max: Int,
val min: Int
) : Parcelable

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="8dp" />
<solid android:color="@android:color/white"/>
<stroke
android:width="1dp"
android:color="@color/slider_point_inactive" />
</shape>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<size
android:width="1dp" />
<solid
android:color="@color/slider_thumb" />
<padding
android:top="-2sp"
android:bottom="-2sp" />
</shape>

View File

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<merge
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"
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/center_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" />
<ru.touchin.roboswag.base_filters.range.HintInputView
android:id="@+id/from_input"
style="?attr/filterRange_hintViewStyle"
android:layout_width="0dp"
android:layout_height="42dp"
app:layout_constraintEnd_toStartOf="@+id/center_guideline"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<ru.touchin.roboswag.base_filters.range.HintInputView
android:id="@+id/to_input"
style="?attr/filterRange_hintViewStyle"
android:layout_width="0dp"
android:layout_height="42dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/center_guideline"
app:layout_constraintTop_toTopOf="parent"/>
<ru.touchin.roboswag.base_filters.range.FilterRangeSlider
android:id="@+id/range_slider"
style="?attr/filterRange_sliderStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="@id/range_slider_guideline"
app:layout_constraintBottom_toTopOf="@id/range_slider_guideline"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
<View
android:id="@+id/range_slider_guideline"
android:layout_height="0dp"
android:layout_width="wrap_content"
android:orientation="horizontal"
app:layout_constraintTop_toBottomOf="@id/from_input"/>
</merge>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<merge
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"
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
<EditText
android:id="@+id/edit_text"
style="?attr/filterRange_valueEditTextStyle"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<TextView
android:id="@+id/start_hint"
style="?attr/filterRange_hintTextStyle"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="@+id/input_text"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/input_text" />
</merge>

View File

@ -6,4 +6,31 @@
<attr name="sheetSelection_radioStyle" format="reference" />
</declare-styleable>
<declare-styleable name="FilterRangeSlider">
<attr name="filterRange_activeTickColor" format="color"/>
<attr name="filterRange_inactiveTickColor" format="color"/>
<attr name="filterRange_stepValueMarginTop" format="dimension"/>
<attr name="filterRange_sliderPointSize" format="dimension"/>
<attr name="filterRange_stepTextAppearance" format="reference"/>
<attr name="filterRange_pointShape" format="enum">
<enum name="circle" value="0" />
<enum name="cut" value="1" />
</attr>
</declare-styleable>
<declare-styleable name="FilterRangeChoice">
<attr name="filterRange_sliderStyle" format="reference" />
<attr name="filterRange_hintViewStyle" format="reference" />
<attr name="filterRange_editTextStyle" format="reference" />
<attr name="filterRange_sliderMargin" format="dimension" />
<attr name="filterRange_startHint" format="reference" />
<attr name="filterRange_endHint" format="reference" />
<attr name="filterRange_theme" format="reference" />
</declare-styleable>
<declare-styleable name="FilterEditTextWithHint">
<attr name="filterRange_hintTextStyle" format="reference" />
<attr name="filterRange_valueEditTextStyle" format="reference" />
</declare-styleable>
</resources>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="slider_point_inactive">#B9B9B9</color>
<color name="slider_point_active">#E35100</color>
<color name="slider_track_active_part">#EE9766</color>
<color name="slider_track_inactive_part">#E7E7E7</color>
<color name="slider_thumb">#E35100</color>
</resources>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="start_hint">от</string>
<string name="end_hint">до</string>
</resources>

View File

@ -15,4 +15,55 @@
<item name="android:layout_marginEnd">16dp</item>
</style>
<style name="Widget.FilterRangeSlider.Default" parent="@style/Widget.MaterialComponents.Slider">
<item name="trackColorActive">@color/slider_track_active_part</item>
<item name="trackColorInactive">@color/slider_track_inactive_part</item>
<item name="trackHeight">3dp</item>
<item name="thumbElevation">0dp</item>
<item name="thumbColor">@color/slider_thumb</item>
<item name="labelBehavior">gone</item>
<item name="haloRadius">0dp</item>
<item name="filterRange_activeTickColor">@color/slider_point_active</item>
<item name="filterRange_inactiveTickColor">@color/slider_point_inactive</item>
<item name="filterRange_stepValueMarginTop">12dp</item>
<item name="filterRange_sliderPointSize">5dp</item>
<item name="filterRange_pointShape">circle</item>
<item name="android:layout_marginStart">11dp</item>
<item name="android:layout_marginEnd">11dp</item>
</style>
<style name="Theme.FilterRangeSlider" parent="@style/Theme.MaterialComponents.Light">
<item name="filterRange_sliderStyle">@style/Widget.FilterRangeSlider.Default</item>
<item name="filterRange_hintViewStyle">@style/Widget.HintInputView</item>
<item name="filterRange_hintTextStyle">@style/Widget.HintInputView.HintText</item>
<item name="filterRange_valueEditTextStyle">@style/Widget.HintInputView.EditText</item>
</style>
<style name="FilterRangeChoice">
<item name="filterRange_sliderMargin">23dp</item>
<item name="filterRange_startHint">@string/start_hint</item>
<item name="filterRange_endHint">@string/end_hint</item>
<item name="filterRange_theme">@style/Theme.FilterRangeSlider</item>
</style>
<style name="Widget.HintInputView" parent="@style/Widget.MaterialComponents.TextView">
<item name="android:layout_marginEnd">5dp</item>
<item name="android:layout_marginTop">12dp</item>
<item name="android:layout_marginStart">16dp</item>
</style>
<style name="Widget.HintInputView.HintText" parent="@style/Widget.MaterialComponents.TextView">
<item name="android:layout_marginStart">12dp</item>
<item name="android:elevation">1dp</item>
<item name="android:gravity">center_vertical</item>
</style>
<style name="Widget.HintInputView.EditText" parent="@style/Widget.AppCompat.EditText">
<item name="android:paddingStart">34dp</item>
<item name="android:inputType">number</item>
<item name="android:imeOptions">actionDone</item>
<item name="android:background">@drawable/background_hint_input</item>
<item name="android:textCursorDrawable">@drawable/cursor_background_text_input_view</item>
</style>
</resources>