【问题标题】:RxSwift: Observing UITextFields from TableViewCell inside a child view controllerRxSwift:从子视图控制器内的 TableViewCell 观察 UITextFields
【发布时间】:2018-08-14 10:03:24
【问题描述】:

我在父 viewController 中有一个 tableView 和一个 childController,ParentViewController 中的 tableView 可以有 1-4 个单元格,每个单元格包含一个 UITextField。

ChildController 也有一个 TableView,它根据 ParentViewController tableView 单元格中任何 TextField 中输入的内容列出结果(自动完成)。

我希望 childController 始终监听任何 UITextField 并在 tablView 上显示结果。这是我目前拥有的

private var query = Variable<String>("")
var queryDriver: Driver<String> {
    return query.asDriver()
}

表格视图

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    guard let cell = tableView
        .dequeueReusableCell(
            withIdentifier: "StopCell", for: indexPath) as? StopCell else {
                fatalError("Cannot dequeue StopCell")
    }
    cell.delegate = self

    cell.locationTextField.rx.text.map {$0 ?? ""}
        .bind(to: query)
        .disposed(by: disposeBag)

    cell.locationTextField.rx.controlEvent(.editingDidEnd)
        .asDriver(onErrorJustReturn: ())
        .drive(onNext: { [unowned self] in
            cell.locationTextField.resignFirstResponder()
        })
        .disposed(by: disposeBag)
    return cell
}

添加子控制器

override func viewDidLoad() {
    super.viewDidLoad()
    view.backgroundColor = .white
    let noteVC = NoteVc()
    addChildController(viewController: noteVC)
}

NoteVC

class NoteVc: UIViewController {
  override func viewDidLoad() {
    super.viewDidLoad()
    view.backgroundColor = .white
    view.addSubview(tableView)
    viewModel = SearchLocationViewModel(query: <#T##SharedSequence<DriverSharingStrategy, String>#>)
}

视图模型

class SearchLocationViewModel {

let disposeBag = DisposeBag()
// MARK: - Properties

var querying: Driver<Bool> { return _querying.asDriver() }
var locations: Driver<[Location]> { return _locations.asDriver() }

// MARK: -

var hasLocations: Bool { return numberOfLocations > 0 }
var numberOfLocations: Int { return _locations.value.count }

// MARK: -

private let _querying = BehaviorRelay<Bool>(value: false)
private let _locations = BehaviorRelay<[Location]>(value: [])

// MARK: -

private let disposeBag = DisposeBag()

// MARK: - Initializtion

init(query: Driver<String>) {
    Behave.shared.queryDriver
        .throttle(0.5)
        .distinctUntilChanged()
        .drive(onNext: { [weak self] (addressString) in
            self?.geocode(addressString: addressString)
        })
        .disposed(by: disposeBag)
}

就像在 Uber 应用中实现的一样,用户最多可以添加三个目的地,下图中黄色矩形框是我的 ChildViewController

【问题讨论】:

  • 您需要将文本字段的数据绑定到一个数组,然后将该数组绑定到您的子控制器的 tableView
  • @ShahzaibQureshi 你介意帮忙写一个代码吗,我试过了,但没有得到它,我也更新了问题,以便清楚

标签: ios swift rx-swift


【解决方案1】:

这是我能想到的最简单的。我将 viewModel 设为全局常量,但您可能希望更详细地使用它。:

class ViewModel {
    let inputs: [AnyObserver<String>]
    let outputs: [Observable<String>]

    init(count: Int) {
        let subjects = (0..<count).map { _ in BehaviorSubject<String>(value: "") }
        inputs = subjects.map { $0.asObserver() }
        outputs = subjects.map { $0.asObservable() }
    }
}

class ParentViewController: UIViewController {

    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let bag = self.bag
        Observable.just(viewModel.inputs)
            .bind(to: tableView.rx.items(cellIdentifier: "Cell", cellType: UITableViewCell.self)) { _, element, cell in
                let textField = cell.viewWithTag(99) as! UITextField
                textField.rx.text.orEmpty
                    .bind(to: element)
                    .disposed(by: bag)
            }
            .disposed(by: bag)
    }

    let bag = DisposeBag()
}

class ChildViewController: UIViewController {

    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let bag = self.bag
        Observable.just(viewModel.outputs)
            .bind(to: tableView.rx.items(cellIdentifier: "Cell", cellType: UITableViewCell.self)) { _, element, cell in
                element
                    .bind(to: cell.textLabel!.rx.text)
                    .disposed(by: bag)
            }
            .disposed(by: bag)
    }

    let bag = DisposeBag()
}

【讨论】:

  • 你好丹尼尔,很抱歉回复晚了,实际上我一直在尝试复制上面的解决方案,但我可能需要你帮助编辑答案,我已经更新了问题并附上了图片。
猜你喜欢
  • 2021-11-25
  • 2020-10-04
  • 2011-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-21
  • 1970-01-01
相关资源
最近更新 更多