API Reference / InstantSearch iOS Widgets / Filter Numeric Range

Filter Numeric Range

Widget signature
NumberRangeConnector<Number>(
  filterState: FilterState,
  attribute: Attribute,
  bounds: ClosedRange<Number>?,
  range: ClosedRange<Number>,
  operator: RefinementOperator,
  groupName: String?,
  controller: NumberRangeController
)

About this widget

Filter Numeric Range is a filtering component made to filter between two numeric values. The most common interface for this is a slider.

Examples

Instantiate a NumberRangeConnector and launch an initial search on its searcher.

1
2
3
4
5
6
7
8
9
10
11
12
13
let searcher: SingleIndexSearcher = .init(appID: "YourApplicationID",
                                          apiKey: "YourApiKey",
                                          indexName: "YourIndexName")
let filterState: FilterState = .init()

let numberRangeController: RangeSliderController = .init(rangeSlider: .init())

let numericRangeConnector: NumberRangeConnector<Double> = .init(searcher: searcher,
                                                                filterState: filterState,
                                                                attribute: "price",
                                                                controller: numberRangeController)

searcher.search()

Parameters

searcher
type: SingleIndexSearcher
Required

The Searcher that handles your searches.

filterState
type: FilterState
Required

The FilterState that holds your filters.

attribute
type: Attribute
Required

The attribute to filter.

interactor
type: NumberRangeInteractor<Number>
default: .init()
Required

The logic applied to the numeric range.

bounds
type: ClosedRange<Number>?
default: nil
Optional

The Bounds limiting the max and the min value of the range.

range
type: ClosedRange<Number>
default: nil
Optional

The initial range value.

operator
type: RefinementOperator
default: .and
Optional

Whether the filter is added to a conjuncitve(and) or a disjuncitve (or) group in the filter state.

groupName
type: String
default: The value of the `attribute` parameter
Optional

Filter group name in the FilterState

controller
type: NumberRangeController
default: nil
Optional

The Controller interfacing with a concrete number range view.

Low-level API

If you want to fully control the Filter Numeric Range components and connect them manually, you can use the following components:

  • Searcher: The Searcher that handles your searches.
  • FilterState: The current state of the filters.
  • NumberRangeInteractor: The logic applied to the numeric ranges.
  • NumberRangeController: The controller that interfaces with a concrete numeric range view.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let searcher: SingleIndexSearcher = .init(appID: "YourApplicationID",
                                          apiKey: "YourApiKey",
                                          indexName: "YourIndexName")
let filterState: FilterState = .init()

let numericRangeInteractor: NumberRangeInteractor<Double> = .init()
let numberRangeController: RangeSliderController = .init(rangeSlider: .init())

let priceAttribute: Attribute = "price"
  
searcher.connectFilterState(filterState)

numericRangeInteractor.connectFilterState(filterState, attribute: priceAttribute)
numericRangeInteractor.connectSearcher(searcher, attribute: priceAttribute)
numericRangeInteractor.connectController(numberRangeController)

searcher.search()

Customizing your view

If you want to use a third-party input view, or you want to introduce some custom behavior to the already provided UIKit component, you can create your own controller conforming to the NumberRangeController protocol.

Protocol

func setBounds(_ bounds: ClosedRange<Double>):

Function called when the minimum and maximum of numeric filter view have been defined.

var onRangeChanged: ((ClosedRange<Double>) -> Void)?

Closure to call when new bounds is set for the numeric range filter.

Example

Let’s assume you have a range slider control providing the following API:

1
2
3
4
5
6
class RangeSlider: UIControl {
  var lowerValue: Double
  var upperValue: Double
  var minimumValue: Double
  var maximumValue: Double
}

Then, you could implement the NumberRangeController including this control as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class RangeSliderController: NumberRangeController {
  
  let rangeSlider: RangeSlider

  var onRangeChanged: ((ClosedRange<Double>) -> Void)?
  
  func setBounds(_ bounds: ClosedRange<Double>) {
    rangeSlider.minimumValue = bounds.lowerBound
    rangeSlider.maximumValue = bounds.upperBound
    setItem(bounds)
  }
  
  func setItem(_ item: ClosedRange<Double>) {
    rangeSlider.lowerValue = item.lowerBound
    rangeSlider.upperValue = item.upperBound
  }
  
  init(rangeSlider: RangeSlider) {
    self.rangeSlider = rangeSlider
    rangeSlider.addTarget(self, action: #selector(onValueChanged(sender:)), for: [.touchUpInside, .touchUpOutside])
  }
  
  @objc func onValueChanged(sender: RangeSlider) {
    onRangeChanged?(sender.lowerValue...sender.upperValue)
  }
  
}

Did you find this page helpful?