1

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)
}
Karl Mcgeough
  • 469
  • 2
  • 7
  • 13
  • `workoutsTableView.cellForRow(at: indexPath) == FutureSessionCell()` that's should return `false` each time... Don't you want to test the class instead? `is FutureSessionCell` ? But shouldn't you know by the indexPath isntead? – Larme Sep 27 '21 at 10:02
  • How did you connect the delegate? I don't see anything here that would tell the table view where to go to find out the cell heights. – Daniel T. Sep 27 '21 at 12:19
  • Might you be seeing this in the console? `[Assert] Attempted to call -cellForRowAtIndexPath: on the table view while it was in the process of updating its visible cells, which is not allowed.` – Daniel T. Sep 27 '21 at 12:36

2 Answers2

0

Try

if let _ = workoutsTableView.cellForRow(at: indexPath) as? FutureSessionCell {
    return 190
}else {
    return 390
}
Shehata Gamal
  • 98,760
  • 8
  • 65
  • 87
0

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: [:])
}
Daniel T.
  • 32,821
  • 6
  • 50
  • 72