【问题标题】:UITableView Refresh without scrollingUITableView 刷新不滚动
【发布时间】:2014-08-31 06:36:02
【问题描述】:

我有一个带有项目的_TableView,我想设置自动刷新,我不希望它在刷新时滚动,假设用户向下滚动了 2 页,并且触发了刷新 -> 所以我想将刷新后的内容放在表格顶部,而不影响用户的滚动

假设用户在第 18 行 现在 _dataSource 已刷新,因此它获取了 4 个项目,所以我希望用户留在他原来的项目上。

实现它的最佳方法是什么??

【问题讨论】:

  • 希望这些答案对您有所帮助:stackoverflow.com/questions/5872759/…
  • 您的表格视图单元格有静态高度还是动态高度?因为如果您的表格视图具有动态单元格高度,则无法在不滚动的情况下重新加载,表格视图必须在具有动态单元格时从头开始重新创建所有单元格。

标签: ios objective-c uitableview


【解决方案1】:

对于 Swift 3+

您需要保存UITableView 的当前偏移量,然后重新加载,然后将偏移量设置回UITableView

我为此目的创建了这个函数:

func reload(tableView: UITableView) {

    let contentOffset = tableView.contentOffset
    tableView.reloadData()
    tableView.layoutIfNeeded()
    tableView.setContentOffset(contentOffset, animated: false)

}

只需调用它:reload(tableView: self.tableView)

【讨论】:

  • 如果tableview不改变偏移量仍然加载新单元格怎么办?
  • @RockBalbao - 我不明白你的问题,兄弟
  • 我正在使用 NSFetchedResultsControllerDelegate。现在我正在使用 UIRefreshControl 在 scrollDown 上加载旧单元格。在 performFetch 加载数据时,我只需要重新加载数据。但我不想显示重新加载的单元格。让它们在上面加载。当我在上面滚动时,只有它们变得可见。因此,为了实现这一点,我尝试使用这种 contentOffset 方式。但是在 reloadData 之前和 reloadData 之后 contentOffset 是相同的,尽管它在上面添加了几行
  • 我觉得您的实现与此没有太大关系。因为在 reloadData 之前和之后让 contentOffset 相同正是关键所在。例如,如果您有一个“喜欢按钮”并且您正在使用实时数据库,这在这里很有用。防止tableView晃动。我建议在堆栈上打开一个线程并尽可能准确地描述您的问题。
【解决方案2】:

SWIFT 3

let contentOffset = self.tableView.contentOffset
self.tableView.reloadData()
self.tableView.layoutIfNeeded()
self.tableView.setContentOffset(contentOffset, animated: false)

这是 iOS8 在使用 UITableViewAutomatic Dimension 时的错误。我们需要存储表格的内容偏移量,重新加载表格,强制布局并设置 contenOffset。

CGPoint contentOffset = self.tableView.contentOffset;
[self.tableView reloadData];
[self.tableView layoutIfNeeded];
[self.tableView setContentOffset:contentOffset];

【讨论】:

  • 关于 iOS 8 的第一句话拯救了我的一天。
  • 感谢分享代码。
  • 拯救了我的一天。谢谢。
  • 如果您有 50 行,每行首先高 30 点,然后是 3 行,每行高 3 点,我不确定这个答案是否有意义。想象一下,您滚动到底部并重新加载数据 - 之后您无法保持相同的滚动偏移量。
【解决方案3】:

我正在显示是否只添加了一行。您可以将其扩展到多行。

    // dataArray is your data Source object
    [dataArray insertObject:name atIndex:0];
    CGPoint contentOffset = self.tableView.contentOffset;
    contentOffset.y += [self tableView:self.tableView heightForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
    [self.tableView reloadData];
    [self.tableView setContentOffset:contentOffset];

但要使其工作,您需要定义 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 方法。否则,如果它是恒定的,您可以直接给您的 tableview 行高。

【讨论】:

  • 不是固定的,谢谢你的回答我会试试的,
  • 是的,那么您肯定已经定义了- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 的方法。如果对您有帮助,请接受我的回答。
【解决方案4】:

只需将estimatedRowHeight 设置为最大可能值。

 self.tableView.estimatedRowHeight = 1000
 self.tableView.estimatedSectionFooterHeight = 100.0
 self.tableView.estimatedSectionHeaderHeight = 500.0

就是这样!!

注意:

请不要使用FLT_MAX, DBL_MAX 值。可能会导致您的应用崩溃。

【讨论】:

  • 完美地为我工作
  • 完美地为我工作
  • 这对我也很有效,tx!我将这个答案与关于同一主题的另一个问题联系起来。
【解决方案5】:

我是这样做的:

messages.insertContentsOf(incomingMsgs.reverse(), at: 0)
table.reloadData()

// This is for the first load, first 20 messages, scroll to bottom
if (messages.count <= 20) {
      let indexToScroll = NSIndexPath(forRow: saferSelf.messages.count - 1, inSection: 0)
      table.scrollToRowAtIndexPath(indexToScroll, atScrollPosition: .Top , animated: false)
}
// This is to reload older messages on top of tableview
else {
      let indexToScroll = NSIndexPath(forRow: incomingMsgs.count, inSection: 0)
      table.scrollToRowAtIndexPath(indexToScroll, atScrollPosition: .Top , animated: false)
      // Remove the refreshControl.height + tableHeader.height from the offset so the content remain where it was before reload
      let theRightOffset = CGPointMake(0, table.contentOffset.y - refreshControl.frame.height - table.headeView.frame.height)
      table.setContentOffset(theRightOffset, animated: false)
}

...另外,由于我使用动态单元格高度,为了避免一些奇怪,估计被缓存:

var heightAtIndexPath = [NSIndexPath: CGFloat]()
func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return heightAtIndexPath[indexPath] ?? UITableViewAutomaticDimension
}
func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
    heightAtIndexPath[indexPath] = cell.frame.height
}

【讨论】:

  • 在我的情况下,单元缓存是唯一有效的方法,谢谢! :)
  • 感谢关于缓存高度估计的好建议! @马可
【解决方案6】:

使用扩展

创建UITableViewExtensions.swift 并添加以下内容:

extension UITableView {

    func reloadDataWithoutScroll() {
        let offset = contentOffset
        reloadData()
        layoutIfNeeded()
        setContentOffset(offset, animated: false)
    }
}

【讨论】:

    【解决方案7】:

    iOS 12.x 中,使用Xcode 10.2.1 是一个更简单的选择。

    UIView.performWithoutAnimation { 
        let loc = tableView.contentOffset
        tableView.reloadRows(at: [indexPath], with: .none)
        tableView.contentOffset = loc
    }
    

    这比跟随更好;当行不完全可见时,它有时会晃动。

    let contentOffset = self.tableView.contentOffset
    self.tableView.reloadData()
    self.tableView.layoutIfNeeded()
    self.tableView.setContentOffset(contentOffset, animated: false)
    

    【讨论】:

      【解决方案8】:

      此代码将防止不必要的动画并保持滚动视图的内容偏移,对我来说效果很好。

      let lastScrollOffset = tableView.contentOffset
      tableView.beginUpdates()
      tableView.reloadData()
      tableView.endUpdates()
      tableView.layer.removeAllAnimations()
      tableView.setContentOffset(lastScrollOffset, animated: false)
      

      【讨论】:

        【解决方案9】:

        当你想重新加载时,你必须

        self.tableView.reloadData()
        
        self.tableView.layoutIfNeeded()
        

        也可以使用这个UITableViewDelegate

        func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
                return 'your maximum cell's height'
        }
        

        并且您的 tableView 将保持在先前的滚动位置而不滚动

        【讨论】:

          【解决方案10】:

          Swift 4.2:简单的解决方案

          override func viewDidLoad() {
           super.viewDidLoad()
          
           self.tableView.estimatedRowHeight = 0
           self.tableView.estimatedSectionHeaderHeight = 0
           self.tableView.estimatedSectionFooterHeight = 0
          }
          
          //And then simply update(insert, reloadSections, delete etc) your tableView or reload
          
          tableView.reloadData()
          
          //or
          
          UIView.performWithoutAnimation {
          
            tableView.beginUpdates()
            .....
            tableView.endUpdates()
          }
          

          【讨论】:

            【解决方案11】:

            尝试替换

            reloadData

            tableView.reloadRows(at: tableView!.indexPathsForVisibleRows!, with: .none),

            但是你应该关心no cells,如果no cells,这个方法应该会导致崩溃。

            【讨论】:

              【解决方案12】:

              我写了一些适合我的东西:

              extension UIScrollView {
                  func reloadDataAndKeepContentOffsetInPlace(reloadData:(() -> Void)) {
                  let currentContentHeight = contentSize.height
                  if currentContentHeight == .zero {
                     reloadData()
                     return
                  }
                  reloadData()
                  layoutIfNeeded()
                  let newContentHeight = self.contentSize.height
                  DispatchQueue.main.async {
                      var contentOffset = self.contentOffset
                      contentOffset.y += newContentHeight - currentContentHeight
                      self.setContentOffset(contentOffset, animated: false)
                  }
                }
              }
              

              这样使用:

                 self.reloadSomeData()
                 collectionView.reloadDataAndKeepContentOffsetInPlace { [weak self] in
                                              guard let self = self else { return }
                                              self.collectionView.reloadData()
                                          }
              

              【讨论】:

                【解决方案13】:

                试试下面的。

                tableView.estimatedRowHeight = 0
                tableView.estimatedSectionHeaderHeight = 0
                tableView.estimatedSectionFooterHeight = 0
                

                来源:https://developer.apple.com/forums/thread/86703

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2020-03-22
                  • 1970-01-01
                  • 1970-01-01
                  • 2015-07-18
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多