FilterRangeConnector(
filterState: FilterState,
attribute: Attribute,
bounds: ClosedRange<T>?,
range: ClosedRange<T>?
)
Filter Numeric Range is a filtering view made to filter between two numeric values.
The most common interface for this is a slider.
The Android View and Compose UI code samples (part of the Android widget showcase repository on GitHub) illustrate the use of sliders.
Examples
class MyActivity : AppCompatActivity() {
val searcher = HitsSearcher(
applicationID = ApplicationID("YourApplicationID"),
apiKey = APIKey("YourSearchOnlyAPIKey"),
indexName = IndexName("YourIndexName")
)
val price = Attribute("price")
val groupID = FilterGroupID(price)
val primaryBounds = 0..15
val initialRange = 0..15
val filters = filters {
group(groupID) {
range(price, initialRange)
}
}
val filterState = FilterState(filters)
val range = FilterRangeConnector(
filterState = filterState,
attribute = price,
range = initialRange,
bounds = primaryBounds
)
val connection = ConnectionHandler(range, searcher.connectFilterState(filterState))
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val view: NumberRangeView<Int> = MyNumberRangeView(textLabel) // your `NumberRangeView<T>` implementation
connection += range.connectView(view)
searcher.searchAsync()
}
override fun onDestroy() {
super.onDestroy()
connection.disconnect()
searcher.cancel()
}
}
Low-level API
If you want to fully control the Filter Numeric Range components and connect them manually, use the following components:
Searcher
. The Searcher
that handles your searches.
FilterState
. The current state of the filters.
FilterRangeViewModel
. The logic applied to the numeric ranges.
NumberRangeView
. The view that renders the numeric range filter.
class MyActivity : AppCompatActivity() {
val searcher = HitsSearcher(
applicationID = ApplicationID("YourApplicationID"),
apiKey = APIKey("YourSearchOnlyAPIKey"),
indexName = IndexName("YourIndexName")
)
val filterState = FilterState()
val attribute = Attribute("price")
val viewModel = FilterRangeViewModel<Int>()
val connection = ConnectionHandler()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val view: NumberRangeView<Int> = MyNumberRangeView(textLabel) // your `NumberRangeView<T>` implementation
connection += searcher.connectFilterState(filterState)
connection += viewModel.connectFilterState(filterState, attribute)
connection += viewModel.connectView(view)
searcher.searchAsync()
}
override fun onDestroy() {
super.onDestroy()
connection.disconnect()
searcher.cancel()
}
}
Compose UI
InstantSearch provides the NumberRangeState
as a state model,
which is an implementation of the NumberRangeView
interface.
You need to connect NumberRangeState
to the FilterRangeConnector
or FilterRangeViewModel
like any other NumberRangeView
implementation.
class MyActivity : AppCompatActivity() {
val searcher = HitsSearcher(
applicationID = ApplicationID("YourApplicationID"),
apiKey = APIKey("YourSearchOnlyAPIKey"),
indexName = IndexName("YourIndexName")
)
val price = Attribute("price")
val groupID = FilterGroupID(price)
val primaryBounds = 0..15
val initialRange = 0..15
val filters = filters {
group(groupID) {
range(price, initialRange)
}
}
val filterState = FilterState(filters)
val sliderState = NumberRangeState<Int>()
val range = FilterRangeConnector(
filterState = filterState,
attribute = price,
range = initialRange,
bounds = primaryBounds
)
val connections = ConnectionHandler(range)
init {
connections += searcher.connectFilterState(filterState)
connections += range.connectView(sliderState)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyRangeSlider(sliderState) // your own UI composable to display range and bounds as `Range<T>`
}
searcher.searchAsync()
}
fun Range<Int>.toClosedFloatRange(): ClosedFloatingPointRange<Float> {
return min.toFloat()..max.toFloat()
}
override fun onDestroy() {
super.onDestroy()
connections.disconnect()
searcher.cancel()
}
}
Parameters
The limits of the acceptable range within which values are coerced.
The range of values within the bounds.
View
The view that renders the numeric range filter.val view = MyNumberRangeView(textLabel)
range.connectView(view)
// Example of `NumberRangeView<T>` implementation
class MyNumberRangeView(val view: TextView) : NumberRangeView<Int> {
override var onRangeChanged: Callback<Range<Int>>? = null
private var bounds: Range<Int>? = null
override fun setBounds(bounds: Range<Int>?) {
this.bounds = bounds
view.text = bounds?.let {
"Bounds: ${it.min} to ${it.max}"
} ?: "No bounds"
}
override fun setRange(range: Range<Int>?) = Unit
}