Merge pull request #322 from TouchInstinct/feature/list_filters
Фильтры в виде списка
This commit is contained in:
commit
dde0eba7a8
|
|
@ -3,6 +3,7 @@
|
|||
### 1.27.0
|
||||
|
||||
- **Add**: Tag like filter collection view
|
||||
- **ADD**: List like filter table view
|
||||
|
||||
### 1.26.0
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
import TIUIKitCore
|
||||
import UIKit
|
||||
|
||||
public struct FilterCellStateAppearance {
|
||||
|
|
@ -32,12 +33,15 @@ public struct FilterCellStateAppearance {
|
|||
public let contentInsets: UIEdgeInsets
|
||||
public let cornerRadius: CGFloat
|
||||
|
||||
public let stateImages: UIControl.StateImages?
|
||||
|
||||
public init(borderColor: UIColor,
|
||||
backgroundColor: UIColor,
|
||||
fontColor: UIColor,
|
||||
borderWidth: CGFloat,
|
||||
contentInsets: UIEdgeInsets = .init(top: 4, left: 8, bottom: 4, right: 8),
|
||||
cornerRadius: CGFloat = 6) {
|
||||
cornerRadius: CGFloat = 6,
|
||||
stateImages: UIControl.StateImages? = nil) {
|
||||
|
||||
self.borderColor = borderColor
|
||||
self.backgroundColor = backgroundColor
|
||||
|
|
@ -45,5 +49,6 @@ public struct FilterCellStateAppearance {
|
|||
self.borderWidth = borderWidth
|
||||
self.contentInsets = contentInsets
|
||||
self.cornerRadius = cornerRadius
|
||||
self.stateImages = stateImages
|
||||
}
|
||||
}
|
||||
|
|
@ -42,6 +42,7 @@ open class BaseFilterViewModel<CellViewModelType: FilterCellViewModelProtocol &
|
|||
}
|
||||
|
||||
public weak var filtersCollection: Updatable?
|
||||
public weak var pickerDelegate: FiltersPickerDelegate?
|
||||
|
||||
public private(set) var cellsViewModels: [CellViewModelType]
|
||||
|
||||
|
|
@ -70,6 +71,8 @@ open class BaseFilterViewModel<CellViewModelType: FilterCellViewModelProtocol &
|
|||
viewModel: cellsViewModels[$0.offset])
|
||||
}
|
||||
|
||||
pickerDelegate?.filters(didSelected: selected)
|
||||
|
||||
return changedItems
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,166 @@
|
|||
//
|
||||
// Copyright (c) 2022 Touch Instinct
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the Software), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
import TISwiftUtils
|
||||
import TIUIElements
|
||||
import TIUIKitCore
|
||||
import UIKit
|
||||
|
||||
@available(iOS 13.0, *)
|
||||
open class BaseFiltersTableView<CellType: UITableViewCell & ConfigurableView,
|
||||
PropertyValue: FilterPropertyValueRepresenter & Hashable>:
|
||||
UITableView,
|
||||
InitializableViewProtocol,
|
||||
Updatable,
|
||||
UITableViewDelegate where CellType.ViewModelType: FilterCellViewModelProtocol & Hashable {
|
||||
|
||||
public enum DefaultSection: String {
|
||||
case main
|
||||
}
|
||||
|
||||
public typealias DataSource = UITableViewDiffableDataSource<String, CellType.ViewModelType>
|
||||
public typealias Snapshot = NSDiffableDataSourceSnapshot<String, CellType.ViewModelType>
|
||||
|
||||
public let viewModel: BaseFilterViewModel<CellType.ViewModelType, PropertyValue>
|
||||
|
||||
public lazy var tableViewDataSource = createDataSource()
|
||||
|
||||
// MARK: - Init
|
||||
|
||||
public init(viewModel: BaseFilterViewModel<CellType.ViewModelType, PropertyValue>,
|
||||
allowsMultipleSelection: Bool = true,
|
||||
style: UITableView.Style = .plain) {
|
||||
|
||||
self.viewModel = viewModel
|
||||
|
||||
super.init(frame: .zero, style: style)
|
||||
|
||||
self.allowsMultipleSelection = allowsMultipleSelection
|
||||
|
||||
initializeView()
|
||||
viewDidLoad()
|
||||
}
|
||||
|
||||
@available(*, unavailable)
|
||||
required public init?(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
// MARK: - Life cycle
|
||||
|
||||
open func addViews() {
|
||||
// override in subclass
|
||||
}
|
||||
|
||||
open func configureLayout() {
|
||||
// override in subclass
|
||||
}
|
||||
|
||||
open func bindViews() {
|
||||
delegate = self
|
||||
}
|
||||
|
||||
open func configureAppearance() {
|
||||
alwaysBounceVertical = false
|
||||
}
|
||||
|
||||
open func localize() {
|
||||
// override in subclass
|
||||
}
|
||||
|
||||
open func viewDidLoad() {
|
||||
registerCell()
|
||||
|
||||
viewModel.filtersCollection = self
|
||||
}
|
||||
|
||||
open func viewDidAppear() {
|
||||
applySnapshot()
|
||||
}
|
||||
|
||||
// MARK: - UITableViewDelegate
|
||||
|
||||
public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
filterDidTapped(atIndexPath: indexPath)
|
||||
}
|
||||
|
||||
public func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
|
||||
filterDidTapped(atIndexPath: indexPath)
|
||||
}
|
||||
|
||||
// MARK: - Updatable
|
||||
|
||||
open func update() {
|
||||
applySnapshot()
|
||||
}
|
||||
|
||||
// MARK: - Open methods
|
||||
|
||||
open func registerCell() {
|
||||
register(CellType.self, forCellReuseIdentifier: CellType.reuseIdentifier)
|
||||
}
|
||||
|
||||
open func filterDidTapped(atIndexPath indexPath: IndexPath) {
|
||||
let changes = viewModel.filterDidSelected(atIndexPath: indexPath)
|
||||
|
||||
applyChanges(changes)
|
||||
}
|
||||
|
||||
open func applySnapshot() {
|
||||
var snapshot = Snapshot()
|
||||
|
||||
snapshot.appendSections([DefaultSection.main.rawValue])
|
||||
snapshot.appendItems(viewModel.cellsViewModels, toSection: DefaultSection.main.rawValue)
|
||||
|
||||
tableViewDataSource.apply(snapshot, animatingDifferences: true)
|
||||
}
|
||||
|
||||
open func createDataSource() -> DataSource {
|
||||
let cellProvider: DataSource.CellProvider = { tableView, indexPath, itemIdentifier in
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: CellType.reuseIdentifier, for: indexPath) as? CellType
|
||||
|
||||
cell?.configure(with: itemIdentifier)
|
||||
|
||||
return cell
|
||||
}
|
||||
|
||||
return .init(tableView: self, cellProvider: cellProvider)
|
||||
}
|
||||
|
||||
open func applyChanges(_ changes: [BaseFilterViewModel<CellType.ViewModelType, PropertyValue>.Change]) {
|
||||
changes.forEach { change in
|
||||
guard let cell = cellForRow(at: change.indexPath) as? CellType else {
|
||||
return
|
||||
}
|
||||
|
||||
cell.configure(with: change.viewModel)
|
||||
|
||||
if let selectableCell = cell as? Selectable {
|
||||
selectableCell.setSelected(change.viewModel.isSelected)
|
||||
}
|
||||
|
||||
change.viewModel.isSelected
|
||||
? selectRow(at: change.indexPath, animated: false, scrollPosition: ScrollPosition.none)
|
||||
: deselectRow(at: change.indexPath, animated: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
//
|
||||
// Copyright (c) 2022 Touch Instinct
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the Software), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
@available(iOS 13.0, *)
|
||||
public typealias DefaultFiltersTableView = BaseFiltersTableView<DefaultFilterTableViewCell, DefaultFilterPropertyValue>
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
//
|
||||
// Copyright (c) 2022 Touch Instinct
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the Software), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
import TISwiftUtils
|
||||
import TIUIElements
|
||||
import TIUIKitCore
|
||||
import UIKit
|
||||
|
||||
open class DefaultFilterTableViewCell: ContainerTableViewCell<DefaultPickerView>, ConfigurableView, Selectable {
|
||||
|
||||
open var selectedStateAppearance: FilterCellStateAppearance {
|
||||
.defaultSelectedRowAppearance
|
||||
}
|
||||
|
||||
open var normalStateAppearance: FilterCellStateAppearance {
|
||||
.defaultRowAppearance
|
||||
}
|
||||
|
||||
open override var isSelected: Bool {
|
||||
didSet {
|
||||
let appearance = isSelected ? selectedStateAppearance : normalStateAppearance
|
||||
updateAppearance(with: appearance)
|
||||
wrappedView.setSelected(isSelected)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Life cycle
|
||||
|
||||
open override func configureAppearance() {
|
||||
super.configureAppearance()
|
||||
|
||||
updateAppearance(with: normalStateAppearance)
|
||||
}
|
||||
|
||||
// MARK: - ConfigurableView
|
||||
|
||||
open func configure(with viewModel: DefaultFilterCellViewModel) {
|
||||
wrappedView.text = viewModel.title
|
||||
}
|
||||
|
||||
// MARK: - Open methods
|
||||
|
||||
open func updateAppearance(with appearance: FilterCellStateAppearance) {
|
||||
contentInsets = appearance.contentInsets
|
||||
wrappedView.textColor = appearance.fontColor
|
||||
wrappedView.images = appearance.stateImages ?? [:]
|
||||
|
||||
backgroundColor = appearance.backgroundColor
|
||||
layer.borderColor = appearance.borderColor.cgColor
|
||||
layer.borderWidth = appearance.borderWidth
|
||||
layer.round(corners: .allCorners, radius: appearance.cornerRadius)
|
||||
}
|
||||
}
|
||||
|
||||
extension FilterCellStateAppearance {
|
||||
|
||||
@available(iOS 13, *)
|
||||
private static let defaultStateImages: UIControl.StateImages = [.normal: nil,
|
||||
.selected: UIImage(systemName: "checkmark")]
|
||||
private static let defaultContentInsets = UIEdgeInsets(top: 16, left: 8, bottom: 16, right: 8)
|
||||
|
||||
static var defaultSelectedRowAppearance: FilterCellStateAppearance {
|
||||
var stateImages: UIControl.StateImages?
|
||||
|
||||
if #available(iOS 13, *) {
|
||||
stateImages = defaultStateImages
|
||||
}
|
||||
|
||||
return .init(borderColor: .clear,
|
||||
backgroundColor: .white,
|
||||
fontColor: .black,
|
||||
borderWidth: .zero,
|
||||
contentInsets: defaultContentInsets,
|
||||
cornerRadius: .zero,
|
||||
stateImages: stateImages)
|
||||
}
|
||||
|
||||
static var defaultRowAppearance: FilterCellStateAppearance {
|
||||
var stateImages: UIControl.StateImages?
|
||||
|
||||
if #available(iOS 13, *) {
|
||||
stateImages = defaultStateImages
|
||||
}
|
||||
|
||||
return .init(borderColor: .clear,
|
||||
backgroundColor: .white,
|
||||
fontColor: .black,
|
||||
borderWidth: .zero,
|
||||
contentInsets: defaultContentInsets,
|
||||
cornerRadius: .zero,
|
||||
stateImages: stateImages)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
//
|
||||
// Copyright (c) 2022 Touch Instinct
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the Software), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
import TIUIElements
|
||||
import TIUIKitCore
|
||||
import TISwiftUtils
|
||||
import UIKit
|
||||
|
||||
open class DefaultPickerView: BaseInitializableView, Selectable {
|
||||
|
||||
private let titleLabel = UILabel()
|
||||
private let selectionStateImageView = UIImageView()
|
||||
|
||||
open var images: UIControl.StateImages = [:] {
|
||||
didSet {
|
||||
if images.contains(where: { $0.key == .highlighted }) {
|
||||
selectionStateImageView.highlightedImage = images[.highlighted] ?? nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open var text: String? {
|
||||
get {
|
||||
titleLabel.text
|
||||
}
|
||||
set {
|
||||
titleLabel.text = newValue
|
||||
}
|
||||
}
|
||||
|
||||
open var textColor: UIColor {
|
||||
get {
|
||||
titleLabel.textColor
|
||||
}
|
||||
set {
|
||||
titleLabel.textColor = newValue
|
||||
}
|
||||
}
|
||||
|
||||
open var isSelected: Bool = false {
|
||||
didSet {
|
||||
selectionStateImageView.image = images[isSelected ? .selected : .normal] ?? nil
|
||||
}
|
||||
}
|
||||
|
||||
open var defaultImageSize: CGFloat {
|
||||
20
|
||||
}
|
||||
|
||||
open override func addViews() {
|
||||
super.addViews()
|
||||
|
||||
addSubviews(titleLabel, selectionStateImageView)
|
||||
}
|
||||
|
||||
open override func configureLayout() {
|
||||
super.configureLayout()
|
||||
|
||||
titleLabel.translatesAutoresizingMaskIntoConstraints = false
|
||||
selectionStateImageView.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
titleLabel.leadingAnchor.constraint(equalTo: leadingAnchor),
|
||||
titleLabel.centerYAnchor.constraint(equalTo: centerYAnchor),
|
||||
titleLabel.heightAnchor.constraint(equalTo: heightAnchor),
|
||||
|
||||
selectionStateImageView.trailingAnchor.constraint(equalTo: trailingAnchor),
|
||||
selectionStateImageView.centerYAnchor.constraint(equalTo: centerYAnchor),
|
||||
selectionStateImageView.heightAnchor.constraint(equalToConstant: defaultImageSize),
|
||||
selectionStateImageView.widthAnchor.constraint(equalToConstant: defaultImageSize)
|
||||
])
|
||||
}
|
||||
}
|
||||
|
|
@ -68,14 +68,14 @@ open class BaseFiltersCollectionView<CellType: UICollectionViewCell & Configurab
|
|||
// override in subclass
|
||||
}
|
||||
|
||||
open func bindViews() {
|
||||
delegate = self
|
||||
}
|
||||
|
||||
open func configureLayout() {
|
||||
// override in subclass
|
||||
}
|
||||
|
||||
open func bindViews() {
|
||||
delegate = self
|
||||
}
|
||||
|
||||
open func configureAppearance() {
|
||||
backgroundColor = .white
|
||||
}
|
||||
|
|
@ -121,7 +121,7 @@ open class BaseFiltersCollectionView<CellType: UICollectionViewCell & Configurab
|
|||
|
||||
let changes = viewModel.filterDidSelected(atIndexPath: indexPath)
|
||||
|
||||
applyChange(changes)
|
||||
applyChanges(changes)
|
||||
}
|
||||
|
||||
open func applySnapshot() {
|
||||
|
|
@ -147,10 +147,10 @@ open class BaseFiltersCollectionView<CellType: UICollectionViewCell & Configurab
|
|||
return cell
|
||||
}
|
||||
|
||||
return DataSource(collectionView: self, cellProvider: cellProvider)
|
||||
return .init(collectionView: self, cellProvider: cellProvider)
|
||||
}
|
||||
|
||||
open func applyChange(_ changes: [BaseFilterViewModel<CellType.ViewModelType, PropertyValue>.Change]) {
|
||||
open func applyChanges(_ changes: [BaseFilterViewModel<CellType.ViewModelType, PropertyValue>.Change]) {
|
||||
changes.forEach { change in
|
||||
guard let cell = cellForItem(at: change.indexPath) as? CellType else {
|
||||
return
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
//
|
||||
// Copyright (c) 2022 Touch Instinct
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the Software), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
public protocol FiltersPickerDelegate: AnyObject {
|
||||
func filters(didSelected filters: [FilterPropertyValueRepresenter])
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
//
|
||||
// Copyright (c) 2022 Touch Instinct
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the Software), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
public protocol Selectable: AnyObject {
|
||||
var isSelected: Bool { get set }
|
||||
|
||||
func setSelected(_ isSelected: Bool)
|
||||
}
|
||||
|
||||
public extension Selectable {
|
||||
func setSelected(_ isSelected: Bool) {
|
||||
self.isSelected = isSelected
|
||||
}
|
||||
}
|
||||
|
|
@ -41,7 +41,7 @@ open class ContainerTableViewCell<View: UIView>: BaseInitializableCell, WrappedV
|
|||
override open func addViews() {
|
||||
super.addViews()
|
||||
|
||||
addSubview(wrappedView)
|
||||
contentView.addSubview(wrappedView)
|
||||
}
|
||||
|
||||
override open func configureLayout() {
|
||||
|
|
|
|||
|
|
@ -32,3 +32,9 @@ extension UICollectionViewCell: ReuseIdentifierProtocol {
|
|||
.init(describing: Self.self)
|
||||
}
|
||||
}
|
||||
|
||||
extension UITableViewCell: ReuseIdentifierProtocol {
|
||||
public static var reuseIdentifier: String {
|
||||
.init(describing: Self.self)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue