Current Filters
CurrentFiltersConnector( filterState: FilterState, groupIDs: Set<FilterGroup.ID>?, interactor: CurrentFiltersInteractor, controller: CurrentFiltersController, presenter: Presenter<Filter, Output> )
About this widget
Shows the currently active filters within a given FilterState
and lets users remove filters individually.
Examples
Instantiate a CurrentFiltersConnector
1
2
3
4
5
6
let filterState = FilterState()
let groupID: FilterGroup.ID = .and(name: "color")
let currenfFiltersTableController: CurrentFilterListTableController = .init(tableView: UITableView())
let currentFiltersConnector = CurrentFiltersConnector(filterState: filterState,
groupIDs: [groupID],
controller: currenfFiltersTableController)
Parameters
filterState
|
type: FilterState
Required
The |
groupIDs
|
type: Set<FilterGroup.ID>?
default: nil
Required
When specified, only display current filters matching these filter group ids. |
interactor
|
type: CurrentFiltersInteractor
default: .init()
Required
The logic applied to the current filters. |
controller
|
type: CurrentFiltersController
default: nil
Optional
The Controller interfacing with a concrete current filters view. |
presenter
|
type: Presenter<Filter, Output>
default: DefaultPresenter.Filter.present
Optional
The Presenter defining how filters appears in the controller. |
Presenter
Filter Presenter
|
type: (Filter) -> String
Optional
The presenter that defines the way you want to display a filter. |
||
Copy
|
Low-level API
If you want to fully control the Current Filters
components and connect them manually, you can use the following components:
CurrentFiltersInteractor
: The logic for current filters in theFilterState
.FilterState
: The current state of the filters.CurrentFiltersController
: The controller that interfaces with a concrete current filter view.Presenter
: Optional. The presenter that defines the way you want to display a filter.
1
2
3
4
5
6
let filterState = FilterState()
let groupID: FilterGroup.ID = .and(name: "color")
let currentFiltersTableController: CurrentFilterListTableController = .init(tableView: UITableView())
let currentFiltersInteractor = CurrentFiltersInteractor()
currentFiltersInteractor.connectFilterState(filterState, filterGroupID: groupID)
currentFiltersInteractor.connectController(currentFiltersTableController)
Customizing your view
The controllers provided by default, like the CurrentFilterListTableController
work well when you want to use native UIKit with their default behavior.
If you want to use another component (other than a UITableView
) such as a UICollectionView
, 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 CurrentFiltersController
protocol.
Protocol
func setItems(_ item: [FilterAndID])
:
Function called when current filters are refreshed and need to be updated.
Note that FilterAndID is a struct
that contains the filter
, its ID
, and the text
representation of the filter
var onRemoveItem: ((FilterAndID) -> Void)?
:
Closure to call when a “remove filter” intention is detected on the corresponding current filter.
func reload()
:
Function called when the view needs to reload itself with new data.
Example
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
open class CurrentFilterListTableController: NSObject, CurrentFiltersController, UITableViewDataSource, UITableViewDelegate {
open var onRemoveItem: ((FilterAndID) -> Void)?
public let tableView: UITableView
public var items: [FilterAndID] = []
private let cellIdentifier = "CurrentFilterListTableControllerCellID"
public init(tableView: UITableView) {
self.tableView = tableView
super.init()
tableView.dataSource = self
tableView.delegate = self
tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellIdentifier)
}
open func setItems(_ item: [FilterAndID]) {
items = item
}
open func reload() {
tableView.reloadData()
}
// MARK: - UITableViewDataSource
open func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
open func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath)
let filterAndID = items[indexPath.row]
cell.textLabel?.text = filterAndID.text
return cell
}
// MARK: - UITableViewDelegate
open func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
onRemoveItem?(items[indexPath.row])
}
}
SwiftUI
InstantSearch provides the CurrentFiltersObservableController
data model, which is an implementation of the CurrentFiltersController
protocol adapted for usage with SwiftUI.
CurrentFiltersObservableController
must be connected to the CurrentFiltersConnector
or CurrentFiltersConnector
like any other CurrentFiltersController
implementation.
The example of the current filters view presenting the grouped filters.
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
28
29
30
31
32
33
34
35
struct ContentView: View {
@ObservedObject var currentFiltersController: CurrentFiltersObservableController
var body: some View {
VStack {
Text("Filters")
.font(.title)
let filtersPerGroup = Dictionary(grouping: currentFiltersController.filters) { el in
el.id
}
.mapValues { $0.map(\.filter) }
.map { $0 }
ForEach(filtersPerGroup, id: \.key) { (group, filters) in
HStack {
Text(group.description)
.bold()
.padding(.leading, 5)
Spacer()
}
.padding(.vertical, 5)
.background(Color(.systemGray5))
ForEach(filters, id: \.self) { filter in
HStack {
Text(filter.description)
.padding(.leading, 5)
Spacer()
}
}
}
Spacer()
}
}
}
If you prefer to create a custom SwiftUI view that presents the list of facets, you can directly use the CurrentFiltersObservableController
as a data model.
It provides the filters
property along with toggle
and isSelected
functions to streamline the design process of your custom SwiftUI view.
Check out the example to see this widget in action.