【问题标题】:How to get a UITableview to go to the top of page on reload?如何让 UITableview 在重新加载时转到页面顶部?
【发布时间】:2011-07-29 09:34:36
【问题描述】:

当我从

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {

    // A bunch of code...

    [TableView reloadData];
}

按照同样的思路,当我重新加载表格数据时,我还希望能够转到特定部分。

我尝试在重新加载之前和之后放置以下内容,这似乎仅适用于该行,但没有任何反应:

[TableView scrollToRowAtIndexPath:0 atScrollPosition:UITableViewScrollPositionTop  animated:YES];

【问题讨论】:

    标签: iphone cocoa-touch tableview


    【解决方案1】:

    重新加载时完美到页面顶部,通过两次重新加载

    dataForSource = nil
    tableView.reloadData()
    
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.4) {
        self.dataForSource = realData
        self.tableView.reloadData()
    }
    

    【讨论】:

      【解决方案2】:

      由于解释不完整,我对这个问题的一些答案感到有些困惑。根据我收集到的信息,有两条路线可以完成 OP 的要求,它们如下:

      1. 如果不需要动画,我建议在加载数据之前使用其中一种偏移方法重置滚动位置。您应该在 reloadData 之前运行 offset 的原因是 reloadData 异步运行。如果您在重新加载后运行偏移,您的滚动位置可能会从顶部向下几行。

        tableView.setContentOffset(.zero, animated: false)
        tableView.reloadData()
        
      2. 如果需要动画,请在使用 scrollToRow 运行 reloadData 后将滚动条定位到顶行。 scrollToRow 在这里起作用的原因是它将您定位在表格的顶部,而不是相对于已加载的数据定位您的偏移方法。

        tableView.reloadData()
        tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: true)
        

      【讨论】:

        【解决方案3】:

        这对我有用。

        tableView.scrollToRow(at: IndexPath.init(row: 0, section: 0), at: .top, animated: true)
        

        【讨论】:

          【解决方案4】:

          这是另一种方法:

          Objective-C

          [tableView setContentOffset:CGPointZero animated:YES];
          

          Swift 3 及更高版本

          tableView.setContentOffset(.zero, animated: true)
          

          这可能是最简单、最直接的方法。

          【讨论】:

          • 谢谢。这让我回到了页面顶部,这是我的迫切需要。
          • 有时这应该在 0.1 秒的延迟后执行。例如DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: { tableView.setContentOffset(.zero, animated: false) })
          【解决方案5】:

          在考虑了上面讨论的选项后,我的解决方案版本如下。它在 iOS 11 和 12 中始终适用于 UICollectionView 和 UITableView。

          UICollectionView:

          DispatchQueue.main.async { [weak self] in
              guard self?.<your model object>.first != nil else { return }
          
              self?.collectionView.scrollToItem(at: IndexPath(row: 0, section: 0),
                                         at: .top,
                                               animated: false)
          }
          

          UITableView:

          DispatchQueue.main.async { [weak self] in
              guard self?.<your model object>.first != nil else { return }
          
              self?.collectionView.scrollToRow(at: IndexPath(row: 0, section: 0),
                                         at: .top,
                                               animated: false)
          }
          

          【讨论】:

            【解决方案6】:

            对于那些仍在寻找解决方案的人,您可以使用UITableView的以下扩展名。

            包括检查第一部分是否有行。它一直到有行的部分出现,然后滚动到那个部分。

            extension UITableView {
            
                func scrollToFirst() {
            
                    self.reloadData() // if you don't want to reload data, remove this one.
                    for i in 0..<self.numberOfSections {
            
                        if self.numberOfRows(inSection: i) != 0 {
            
                            self.scrollToRow(at: IndexPath(row: 0, section: i), at: .top, animated: true) 
                            break 
                        }
                    }
                }
            }
            

            希望对你有所帮助。

            【讨论】:

              【解决方案7】:

              您必须使用这行代码在表格视图的第一行滚动 UITableView:

              self.yourTableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: true)
              

              【讨论】:

                【解决方案8】:

                没有动画

                我在 iOS11 上,使用带有粘性标题的普通 tableview 样式,不知何故,我让它正常工作以在重新加载后没有任何奇怪的闪烁/动画行为的情况下真正让 tableview 处于顶部的唯一方法是使用这些方法按照这个顺序,所有这些都是必要的:

                [self.tableView setContentOffset:CGPointZero animated:NO];
                [self.tableView reloadData];
                [self.tableView layoutIfNeeded];
                [self.tableView setContentOffset:CGPointZero animated:NO];
                

                我是认真的,所有这些都是必要的,尽管第一行似乎根本不相关。哦,是的,也非常重要,不要使用这个:

                self.tableView.contentOffset = CGPointZero;
                

                您会认为它与“setContentOffset animated:FALSE”相同,但显然不是! Apple 以不同的方式处理此方法,在我的情况下,这仅在使用带有动画:FALSE 的完整方法时才有效。

                有动画

                我还想尝试使用一个漂亮的滚动动画到顶部。那里的内容偏移方法似乎仍然会导致一些奇怪的动画行为。经过一些试验和错误后,我得到一个漂亮的动画的唯一方法是这些方法按照这个确切的顺序:

                [self.tableView reloadData];
                [self.tableView layoutIfNeeded];
                [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:TRUE];
                

                警告,请确保在运行最后一行代码之前至少有 1 行以避免崩溃:)

                我希望有一天这对某人有所帮助!

                【讨论】:

                • 非常适合平行标题表视图。谢谢!
                • 适用于动态单元格
                • 我有一个带有 tableView 的屏幕 X 和另一个带有 X 的所有用户可以选择的列表的屏幕 Y。我想从 Y 列表中选择一个新行,以便屏幕 X 上的我的 tableView 将重新加载其数据并滚动到屏幕 X 上 tableView 的标题顶部。仅在 reloadData 工作之前和之后调用 setContentOffset 动画代码。
                • 当我使用scrollToRowAtIndexPath时,它并没有一直滚动到显示tableView的标题
                【解决方案9】:

                要滚动到特定部分,您需要指定它的索引路径:

                NSIndexPath *topPath = [NSIndexPath indexPathForRow:0 inSection:0];
                [TableView scrollToRowAtIndexPath:topPath
                                 atScrollPosition:UITableViewScrollPositionTop
                                         animated:YES];
                

                如果您不确定 tableView 中的行数。使用以下内容:

                NSIndexPath *topPath = [NSIndexPath indexPathForRow:NSNotFound inSection:0];
                [TableView scrollToRowAtIndexPath:topPath
                                 atScrollPosition:UITableViewScrollPositionTop
                                         animated:YES];
                

                【讨论】:

                • 您可能应该确保该行存在于表中,否则会抛出异常。
                • 感谢此代码。我已经发布了我的应用程序,但我想在我的第一次更新中使用它。
                • @CameronSpickert 查看该条件的更新。
                • 谢谢。设置 contentoffset 对我不起作用。用了这个,效果很好。
                【解决方案10】:

                在 Swift 3.1 中

                DispatchQueue.main.async(execute: {
                
                        self.TableView.reloadData()
                        self.TableView.contentOffset = .zero
                
                    })
                

                【讨论】:

                  【解决方案11】:

                  在这里和其他地方阅读了所有答案后,我终于找到了一个可靠的解决方案,并且在加载数据后不显示滚动。我的回答基于post 和我的观察,如果您使用内容插入,则需要负偏移:

                  func reloadAndScrollToTop() {
                      tableView.reloadData()
                      tableView.layoutIfNeeded()
                      tableView.contentOffset = CGPoint(x: 0, y: -tableView.contentInset.top)
                  }
                  

                  【讨论】:

                  • 这应该被标记为正确答案,因为它尊重之前设置的任何插图
                  • 这个组合和将tableView.estimatedRowHeight 更改为我的顶部分隔符的高度为我完成了这项工作。
                  • tableView.layoutIfNeeded() 在 1-2 小时的挣扎后帮助了我!
                  • 如果您要使用 contentOffset,您应该在 reloadData 之前运行它,因为 reloadData 异步运行,因此 reloadData 可能在 contentOffset 完成之前不会完成,因此您的偏移量将不准确
                  • 尝试了几次调整。我得到的最好结果是在将其设置为零后偏移量为 0、-25。好奇的。但使用 scrollToRow 的解决方案有效:tableView.scrollToRow(at: IndexPath.init(row: 0, section: 0), at: .top, animated: true) - 检查行数和节数 > 0。
                  【解决方案12】:

                  如果在重新加载之前滚动并且行数减少,则可能会出现一些奇怪的动画行为。为确保在重新加载后发生滚动,请使用如下方法:

                  - (void)reloadTableViewAndScrollToTop:(BOOL)scrollToTop {
                      [self.tableView reloadData];
                      if (scrollToTop) {
                          [self.tableView setContentOffset:CGPointZero animated:YES];
                      }
                  }
                  

                  【讨论】:

                    【解决方案13】:

                    UITableView 是 UIScrollView 的子类,所以你也可以使用:

                    [mainTableView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES];
                    

                    【讨论】:

                    • 谢谢。我试过了,效果很好,但我选择了下面的例子。
                    猜你喜欢
                    • 2016-10-03
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2021-03-12
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多