Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

83
Vistas
Cómo completar la vista personalizada de encabezado/pie de página cuando se usa RxDatasources para la fuente de datos

Estoy usando RxDatasources para crear mi fuente de datos. Más tarde, configuro celdas en mi controlador de vista. La cuestión es que los encabezados/pies de página no tienen nada con la fuente de datos (excepto que podemos establecer un título, pero si usamos un pie de página de encabezado personalizado, este título se anulará).

Ahora, así es como configuro mis celdas de vista de tabla:

 private func observeDatasource(){ let dataSource = RxTableViewSectionedAnimatedDataSource<ConfigStatusSectionModel>( configureCell: { dataSource, tableView, indexPath, item in if let cell = tableView.dequeueReusableCell(withIdentifier: ConfigItemTableViewCell.identifier, for: indexPath) as? BaseTableViewCell{ cell.setup(data: item.model) return cell } return UITableViewCell() }) botConfigViewModel.sections .bind(to: tableView.rx.items(dataSource: dataSource)) .disposed(by: disposeBag) }

ahora porque

 dataSource.titleForHeaderInSection = { dataSource, index in return dataSource.sectionModels[index].model }

... no funcionará, porque quiero cargar un encabezado personalizado y llenarlo con datos de RxDatasource , me pregunto cuál sería la forma adecuada de:

  • obtener datos de mi fuente de datos que se define en mi modelo de vista
  • rellene el encabezado, en función de una sección (tengo varias secciones) con los datos correctos, de forma que siempre esté actualizado con una fuente de datos.

Aquí está mi modelo de vista:

 class ConfigViewModel{ private let disposeBag = DisposeBag() let sections:BehaviorSubject<[ConfigStatusSectionModel]> = BehaviorSubject(value: []) func startObserving(){ let observable = getDefaults() observable.map { conditions -> [ConfigStatusSectionModel] in return self.createDatasource(with: conditions) }.bind(to: self.sections).disposed(by: disposeBag) } private func getDefaults()->Observable<ConfigDefaultConditionsModel> { return Observable.create { observer in FirebaseManager.shared.getConfigDefaults { conditions in observer.onNext(conditions!) } failure: { error in observer.onError(error!) } return Disposables.create() } } private func createDatasource(with defaults:ConfigDefaultConditionsModel)->[ConfigStatusSectionModel]{ let firstSectionItems = defaults.start.elements.map{ConfigItemModel(item: $0, data: nil)} let firstSection = ConfigStatusSectionModel(model: defaults.start.title, items: firstSectionItems.compactMap{ConfigCellModel(model: $0)}) let secondSectionItems = defaults.stop.elements.map{ConfigItemModel(item: $0, data: nil)} let secondSection = ConfigStatusSectionModel(model: defaults.stop.title, items: secondSectionItems.compactMap{ConfigCellModel(model: $0)}) let sections:[ConfigStatusSectionModel] = [firstSection, secondSection] return sections } }

Ahora, lo que pude hacer es configurar un delegado de vista de tabla, así:

 tableView.rx.setDelegate(self).disposed(by: disposeBag)

y luego implementar los métodos de delegado apropiados para crear/devolver un encabezado personalizado:

 extension BotConfigViewController: UITableViewDelegate { func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { guard let header = tableView.dequeueReusableHeaderFooterView( withIdentifier: ConfigSectionTableViewHeader.identifier) as? ConfigSectionTableViewHeader else { return nil } return header } func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { return UITableView.automaticDimension } func tableView(_ tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat { return 40 } }

¿Cómo completar mi encabezado personalizado con datos de mi fuente de datos? No quiero hacer cosas como switch (section){...} , porque entonces no está completamente sincronizado con una fuente de datos, sino manualmente, y si la fuente de datos cambia, no afectará la configuración del encabezado automáticamente.

Aquí están mis estructuras modelo:

 typealias ConfigStatusSectionModel = AnimatableSectionModel<String, ConfigCellModel> struct ConfigItemData { let conditionsLink:String? let iconPath:String? } struct ConfigItemModel { let item:OrderConditionModel let data:ConfigItemData? } struct ConfigCellModel : Equatable, IdentifiableType { static func == (lhs: ConfigCellModel, rhs: ConfigCellModel) -> Bool { return lhs.model.item.symbol == rhs.model.item.symbol } var identity: String { return model.item.symbol } let model: ConfigItemModel }

Traté de usar esto , pero no pude hacer que funcionara por completo, porque supongo que no estaba proporcionando un encabezado personalizado de manera/momento correcto.

over 4 years ago · Santiago Trujillo
1 Respuestas
Responde la pregunta

0

El problema fundamental aquí es que tableView(_:viewForHeaderInSection:) es un método basado en extracción y Rx está diseñado para sistemas basados en inserción. Obviamente se puede hacer. Después de todo, la biblioteca base lo hizo para tableView(_:cellForRowAt:) pero es un poco más complejo. Puede seguir el mismo sistema que usa la biblioteca base para la última función.

A continuación se muestra un sistema de este tipo. Se puede usar así:

 source .bind(to: tableView.rx.viewForHeaderInSection( identifier: ConfigSectionTableViewHeader.identifier, viewType: ConfigSectionTableViewHeader.self )) { section, element, view in view.setup(data: element.model) } .disposed(by: disposeBag)

Aquí está el código que hace posible lo anterior:

 extension Reactive where Base: UITableView { func viewForHeaderInSection<Sequence: Swift.Sequence, View: UITableViewHeaderFooterView, Source: ObservableType> (identifier: String, viewType: View.Type = View.self) -> (_ source: Source) -> (_ configure: @escaping (Int, Sequence.Element, View) -> Void) -> Disposable where Source.Element == Sequence { { source in { builder in let delegate = RxTableViewDelegate<Sequence, View>(identifier: identifier, builder: builder) base.rx.delegate.setForwardToDelegate(delegate, retainDelegate: false) return source .concat(Observable.never()) .subscribe(onNext: { [weak base] elements in delegate.pushElements(elements) base?.reloadData() }) } } } } final class RxTableViewDelegate<Sequence, View: UITableViewHeaderFooterView>: NSObject, UITableViewDelegate where Sequence: Swift.Sequence { let build: (Int, Sequence.Element, View) -> Void let identifier: String private var elements: [Sequence.Element] = [] init(identifier: String, builder: @escaping (Int, Sequence.Element, View) -> Void) { self.identifier = identifier self.build = builder } func pushElements(_ elements: Sequence) { self.elements = Array(elements) } func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { guard let view = tableView.dequeueReusableHeaderFooterView(withIdentifier: identifier) as? View else { return nil } build(section, elements[section], view) return view } }
over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda