UITableView 在 reloadData 上向上滚动

Posted

技术标签:

【中文标题】UITableView 在 reloadData 上向上滚动【英文标题】:UITableView scrolls up on reloadData 【发布时间】:2018-07-25 14:31:25 【问题描述】:

我有一个UITableView,如果它的某些单元格中的一个按钮被点击,它就会重新加载。如果执行以下步骤,则会出现此问题:

    点击单元格上的按钮,以便在reloadData 上点击的单元格下方显示另一个单元格。 向上滚动表格视图,使其隐藏一些上部内容。 再次点击该按钮可隐藏刚刚显示的单元格再次调用reloadData

然后表格视图向上并隐藏上部内容(整个第一个单元格和第二个单元格的一部分)。以下是部分代码:

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()
    


【问题讨论】:

你应该使用developer.apple.com/documentation/uikit/uitableview/…而不是重新加载表格视图 @user3581248 感谢您的想法,我稍后会尝试并告诉它是否修复它。 @user3581248 我用insertRowsAtIndexPaths:withRowAnimation:deleteRowsAtIndexPaths:withRowAnimation: 更新了我的代码,它解决了这个问题。你知道为什么这对reloadData有效吗?如果您将您的建议作为答案发布,我会接受。 【参考方案1】:

来自UITableViewreloadData 方法文档(https://developer.apple.com/documentation/uikit/uitableview/1614862-reloaddata):

表视图的委托或数据源在它希望表视图完全重新加载其数据时调用此方法。 不应在插入或删除行的方法中调用它,尤其是在通过调用 beginUpdates 和 endUpdates 实现的动画块中。

有专门的插入/删除行方法用于插入和删除:

insertRowsAtIndexPaths:withRowAnimation:(https://developer.apple.com/documentation/uikit/uitableview/1614879-insertrowsatindexpaths)

deleteRowsAtIndexPaths:withRowAnimation: (https://developer.apple.com/documentation/uikit/uitableview/1614960-deleterowsatindexpaths)

因此,当您重构代码以使用这些代码时,它应该可以顺利且按预期工作。

【讨论】:

以上是关于UITableView 在 reloadData 上向上滚动的主要内容,如果未能解决你的问题,请参考以下文章

在 UITableView 上延迟 reloadData

iOS UITableView reloadData 刷新结束后执行后续操作

UITableView 没有在 reloadData 上重新加载

ReloadData (UITableView) 不起作用

UITableView 在 reloadData 后自动向下滚动

UITableView 奇怪的 reloadData 问题