surToTheW
surToTheW

Reputation: 832

UITableView scrolls up on reloadData

I have a UITableView that gets reloaded if a button in some of its cells gets tapped. The issue appears if the following steps are made:

  1. Tap a button on a cell so that another cells appear below the tapped cell on reloadData.
  2. Scroll up the table view so that it hides some of the upper content.
  3. Tap the button again to hide the cells that were just shown making another call to reloadData.

Then the table view goes up and hides the upper content (the whole first cell and part of the second one). Here is some of the code:

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    if shouldShowImageResolutionOptions && (indexPath.row == 2 || indexPath.row == 3 || indexPath.row == 4) {
        return isLastKnownDeviceOrientationLandscape ? 60 : 80
    }
    if shouldShowImageDisplayOptions && (indexPath.row == 3 || indexPath.row == 4) {
        return isLastKnownDeviceOrientationLandscape ? 60 : 80
    }
    return isLastKnownDeviceOrientationLandscape ? tableView.frame.size.height / 2.5 + 40 : tableView.frame.size.height / 4.5 + 40
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if shouldShowImageResolutionOptions {
        return 6
    }
    if shouldShowImageDisplayOptions {
        return 5
    }
    return 3
}

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

    switch indexPath.row {
    case 0:
        let cell = tableView.dequeueReusableCell(withIdentifier: CellIdentifiers.IntervalCell) as! IntervalCell

        cell.selectionStyle = .none
        cell.dottedSliderView.contentMode = .redraw
        cell.adjustThumbPosition()

        return cell
    case 1:
        let cell = tableView.dequeueReusableCell(withIdentifier: CellIdentifiers.SettingsCell) as! SettingsCell
        cell.selectionStyle = .none

        cell.titleLabel.text = LabelTitles.ImageResolution
        cell.choiseLabel.text = LabelTitles.HDResolutioin
        cell.onButtonTap = {
            self.shouldShowImageResolutionOptions = !self.shouldShowImageResolutionOptions
            self.shouldShowImageDisplayOptions = false
            self.menuTableView.reloadData()
        }

        return cell
    case 2:
        if(shouldShowImageResolutionOptions) {
            let cell = tableView.dequeueReusableCell(withIdentifier: CellIdentifiers.SingleSettingCell, for: indexPath) as! SingleSettingCell
            cell.selectionStyle = .none
            cell.mainSettingLabel.text = Settings.HDResolution

            return cell
        }

        let cell = tableView.dequeueReusableCell(withIdentifier: CellIdentifiers.SettingsCell) as! SettingsCell
        cell.selectionStyle = .none

        cell.titleLabel.text = LabelTitles.ImageDisplay
        cell.choiseLabel.text = LabelTitles.EnlargeImage
        cell.onButtonTap = {
            self.shouldShowImageDisplayOptions = !self.shouldShowImageDisplayOptions
            self.shouldShowImageResolutionOptions = false
            self.menuTableView.reloadData()
        }

        return cell

    case 3, 4:

        if(shouldShowImageResolutionOptions) {
            let cell = tableView.dequeueReusableCell(withIdentifier: CellIdentifiers.SingleSettingCell, for: indexPath)  as! SingleSettingCell
            cell.selectionStyle = .none
            cell.mainSettingLabel.text = indexPath.row == 3 ? Settings.HighResolution : Settings.MediumResolution

            return cell
        } else {
            let cell = tableView.dequeueReusableCell(withIdentifier: CellIdentifiers.SingleSettingCell, for: indexPath)  as! SingleSettingCell
            cell.selectionStyle = .none
            cell.mainSettingLabel.text = indexPath.row == 3 ? Settings.ShowFullImage : Settings.EnlargeImage

            return cell
        }

    case 5:

        let cell = tableView.dequeueReusableCell(withIdentifier: CellIdentifiers.SettingsCell) as! SettingsCell
        cell.selectionStyle = .none

        cell.titleLabel.text = LabelTitles.ImageDisplay
        cell.choiseLabel.text = LabelTitles.EnlargeImage
        cell.onButtonTap = {
            self.shouldShowImageDisplayOptions = !self.shouldShowImageDisplayOptions
            self.shouldShowImageResolutionOptions = false
            self.menuTableView.reloadData()
        }

        return cell

    default:
        return UITableViewCell()
    }

}

Upvotes: 0

Views: 54

Answers (1)

user3581248
user3581248

Reputation: 1014

From the UITableView's reloadData method documentation (https://developer.apple.com/documentation/uikit/uitableview/1614862-reloaddata):

The table view’s delegate or data source calls this method when it wants the table view to completely reload its data. It should not be called in the methods that insert or delete rows, especially within an animation block implemented with calls to beginUpdates and endUpdates.

There are dedicated insert/delete rows methods for inserting and deleting:

So when you refactor your code to use those it should work smoothly and as expected.

Upvotes: 1

Related Questions