setting ids on item in Stackview

*爱你&永不变心* 提交于 2019-12-02 11:51:33

In order to answer this question, we first have to make the stack view reactive and declarative. This means that we have to be able to set the view using a single assignment and that needs to be an observer. This is just like what the RxCocoa library does for UICollectionView, UITableView and UIPickerView.

Writing the function is a bit advanced. First we take the signature from the other views above to define the shape of the function.

func items<Sequence: Swift.Sequence, Source: ObservableType>(_ source: Source) -> (_ viewForRow: @escaping (Int, Sequence.Element, UIView?) -> UIView) -> Disposable where Source.Element == Sequence

The above probably looks daunting. It's a function that takes a source sequence of sequences and returns a function that takes a closure for assembling the views and returns a Dispoable.

The completed function looks like this:

extension Reactive where Base: UIStackView {

    func items<Sequence: Swift.Sequence, Source: ObservableType>(_ source: Source) -> (_ viewForRow: @escaping (Int, Sequence.Element, UIView?) -> UIView) -> Disposable where Source.Element == Sequence {
        return { viewForRow in
            return source.subscribe { event in
                switch event {
                case .next(let values):
                    let views = self.base.arrangedSubviews
                    let viewsCount = views.count
                    var valuesCount = 0
                    for (index, value) in values.enumerated() {
                        if index < viewsCount {
                            // update views that already exist
                            _ = viewForRow(index, value, views[index])
                        }
                        else {
                            // add new views if needed
                            let view = viewForRow(index, value, nil)
                            self.base.addArrangedSubview(view)
                        }
                        valuesCount = index
                    }
                    if valuesCount + 1 < viewsCount {
                        for index in valuesCount + 1 ..< viewsCount {
                            // remove extra views if necessary
                            self.base.removeArrangedSubview(views[index])
                            views[index].removeFromSuperview()
                        }
                    }
                case .error(let error):
                    fatalError("Errors can't be allowed: \(error)")
                case .completed:
                    break
                }
            }
        }
    }
}

The above can be used like this:

self.stackFeature.axis = .vertical
self.stackFeature.distribution = .fill
self.stackFeature.spacing = 8

let features = NetworkAdapter.instance.getFeaturesAmeneities()
    .map { $0.data }
    .share(replay: 1)

features
    .bind(onNext: { [weak self] in self?.features.append(contentsOf: $0) })
    .disposed(by: disposeBag)

features
    .bind(to: stackFeature.rx.items) { (row, element, view) in
        let myView = (view as? CheckboxStackView) ?? CheckboxStackView()
        myView.label.text = element.name
        myView.checkBox.tag = element.id ?? 0
        return myView
    }
    .disposed(by: disposeBag)
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!