Состояние UIButton isEnabled иногда не обновляется без извлечения представления таблицы. RxSwift - PullRequest
0 голосов
/ 18 июня 2020

Я реализовал табличное представление с пользовательскими ячейками, содержащими UITextField. В нижнем колонтитуле у меня есть кнопка «Продолжить», которая становится доступной, когда все текстовые поля заполнены. Проблема в том, что когда я заполняю все текстовые поля, иногда кнопка не обновляет состояние isEnabled без вывода табличного представления, что вы можете увидеть на видео: enter image description here

Есть предложения? Спасибо!

Это моя реализация ячейки:

import UIKit
import RxSwift
import RxCocoa

class CompleteInputDataCell:UITableViewCell {

    var bag = DisposeBag()

    static let cellIdentifier = "completeDataCellIdentifier"

    @IBOutlet weak var fieldNameTitle:UILabel!
    @IBOutlet weak var textField:CustomTextField!

    var vm:CompleteInputDataCellViewModelProtocol? {
        didSet {
            oldValue?.dispose()
            self.bindUI()
        }
    }

    override func awakeFromNib() {
        super.awakeFromNib()
        self.bindUI()
    }

    override func prepareForReuse() {
        super.prepareForReuse()
        self.bag = DisposeBag()
    }

    private func bindUI() {
        guard let vm = self.vm else { return }

        vm.cellStyle.observeOn(MainScheduler.asyncInstance).bind { (style) in
            self.contentView.backgroundColor = style.backgroundColor
            self.textField.backgroundColor = style.textFieldBackgroundColor
            self.textField.defaultTextAttributes = style.textFieldTextAttributes
        }.disposed(by: vm.bag)

        Observable.combineLatest(vm.titleText, vm.cellStyle).map { (text, style) -> NSAttributedString? in
            return text?.toAttributed(attributes: style.textFieldTitleAttributes)
        }.bind(to: self.fieldNameTitle.rx.attributedText).disposed(by: vm.bag)

        Observable.combineLatest(vm.textFieldPlaceholderText, vm.cellStyle).map { (text, style) -> NSAttributedString? in
            return text?.toAttributed(attributes: style.textFieldPlaceholderAttributes)
        }.observeOn(MainScheduler.asyncInstance).bind(onNext: { [weak self] (text) in
            self?.textField.attributedPlaceholder = text
        }).disposed(by: vm.bag)

        self.textField.rx.text.bind(to: vm.inputText).disposed(by: vm.bag)
    }
}

Это мой класс textField:

import Foundation
import UIKit

class CustomTextField:UITextField {

    let padding = UIEdgeInsets(top: 20, left: 16, bottom: 16, right: 20)

    override func awakeFromNib() {
        super.awakeFromNib()
        layer.cornerRadius = 8
        textColor = UIColor.DoveGray
    }

    override func textRect(forBounds bounds: CGRect) -> CGRect {
        return bounds.inset(by: self.padding)
    }

    override func editingRect(forBounds bounds: CGRect) -> CGRect {
        return bounds.inset(by: self.padding)
    }

    override func placeholderRect(forBounds bounds: CGRect) -> CGRect {
        return bounds.inset(by: self.padding)
    }


}

И таким образом я привязываю обновление состояния кнопки:

 vm.isContinueButtonEnabled().observeOn(MainScheduler.asyncInstance).bind(onNext: {[weak self] (value) in
            value ? self?.continueButton.setCurrent(state: .enabled) : self?.continueButton.setCurrent(state: .disabled)
        }).disposed(by: vm.bag)

Этот метод определяет, все ли текстовые поля заполнены, и если да, возвращает true, что означает, что кнопка продолжения активирована:

override func isContinueButtonEnabled() -> Observable<Bool> {
    do {
        let elements = try self.dataSource.value().filter({ (type) -> Bool in
            switch type {
            case .InputCell(_, _):
                return true
            default:
                return false
            }
        }).map({ (type) -> BehaviorSubject<String?> in
            switch type {
            case .InputCell(let vmProtocol, _):
                return vmProtocol.inputText
            default:
                let text = CompleteInputDataCellVM().inputText
                text.onNext("dfs")
                return text
            }
        })

        return Observable.combineLatest(elements).map { (values) -> Bool in
            var isEnabled = true

            values.forEach { (value) in

                isEnabled = isEnabled && (value != nil) && (value != "")
            }
            return isEnabled
        }
    } catch {
        return BehaviorSubject<Bool>(value: false)
    }
}
...