Home > Net >  Two different cells in the same tableview with different heights RXSwift
Two different cells in the same tableview with different heights RXSwift

Time:09-29

I am working on a project and I am using RXSwift. I have a tableview and I have two different cells. Both cells are two different sizes. I tried putting in the heightForRow delegate func with an if else checking the two different cells and with a switch statement checking the two but it still displays the larger cell height for both cells only.

extension CalendarVC: UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    if workoutsTableView.cellForRow(at: indexPath) == FutureSessionCell() {
        return 190
    }else {
        return 390
    }
}
}

 func bindTableViewWorkouts() {
    vm.workoutForOneDay.asObservable()
        .bind(to: workoutsTableView.rx.items) { (tv, row, workout) -> UITableViewCell in
            if workout.createdByCoach {
                let cellIdentifer = FutureSessionCell.identifier
                let cell = tv.dequeueReusableCell(withIdentifier: cellIdentifer, for: IndexPath.init(row: row, section: 0)) as! FutureSessionCell
                cell.initCell(userSettings: UserHandler.shared.user.settings, workout: workout, name: UserHandler.shared.user.name)
                return cell
            }else {
                let cellIdentifer = WorkoutsCardCell.identifier
                let cell = tv.dequeueReusableCell(withIdentifier: cellIdentifer, for: IndexPath.init(row: row, section: 0)) as! WorkoutsCardCell
                cell.initCell(userSettings: UserHandler.shared.user.settings, workout: workout, name: UserHandler.shared.user.name)
                cell.openWorkout = { [unowned self] workout in
                    workout.presentDetailsVC(self, homeTapBarController: self.tapBarController, retrieveWorkout: { [unowned self] newWorkout in
                        UserHandler.shared.user.updateWorkoutData(newWorkout: newWorkout)
                        self.vm.updateWorkoutsForSelectedDay(self.calendar.selectedDate ?? Date()) // need to reload tableView because we updated one existing element from inside array
                    }, backVC: 1)
                }
                return cell
            }
        }.disposed(by: disposeBag)
    
    vm.workoutForOneDay.asObservable()
        .bind(onNext: { newWorkouts in
            self.noWorkoutsView.isHidden = !newWorkouts.isEmpty
        }).disposed(by: disposeBag)
}

CodePudding user response:

Try

if let _ = workoutsTableView.cellForRow(at: indexPath) as? FutureSessionCell {
    return 190
}else {
    return 390
}

CodePudding user response:

I suggest you setup your cell constraints so the cells autoresize. If you must manually tell the table view the height of each cell, then I would do it this way:

workoutForOneDay
    .map { Dictionary(uniqueKeysWithValues: $0.enumerated().map { (IndexPath(row: $0.offset, section: 0), $0.element.createdByCoach ? 190 : 390) }) }
    .bind(to: tableView.rx.heightForRowAt)
    .disposed(by: disposeBag)

In order for the above to work, you would need to follow my article on how to make an Rx Delegate Proxy. Which will produce this class (put the code here in its own file.)

extension Reactive where Base: UITableView {
    var delegate: UITableViewDelegateProxy {
        return UITableViewDelegateProxy.proxy(for: base)
    }

    var heightForRowAt: Binder<[IndexPath: CGFloat]> {
        Binder(delegate) { del, value in
            del.heightForRowAtRelay.accept(value)
        }
    }
}

class UITableViewDelegateProxy
: DelegateProxy<UITableView, UITableViewDelegate>
, DelegateProxyType
, UITableViewDelegate {
    static func currentDelegate(for object: UITableView) -> UITableViewDelegate? {
        object.delegate
    }

    static func setCurrentDelegate(_ delegate: UITableViewDelegate?, to object: UITableView) {
        object.delegate = delegate
    }

    public static func registerKnownImplementations() {
        self.register { UITableViewDelegateProxy(parentObject: $0) }
    }

    init(parentObject: UITableView) {
        super.init(
            parentObject: parentObject,
            delegateProxy: UITableViewDelegateProxy.self
        )
    }

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        heightForRowAtRelay.value[indexPath] ?? 44
    }

    fileprivate let heightForRowAtRelay = BehaviorRelay<[IndexPath: CGFloat]>(value: [:])
}
  • Related