UITableView刷新而不滚动

时间:2014-08-31 06:36:03

标签: ios objective-c uitableview

我有一个_TableView项目,我想设置自动刷新,我不希望它滚动刷新,让我们说用户滚动2页,刷新三角形 - &gt ;所以我想把刷新的内容放到桌面的顶部而不会中断用户的滚动

假设用户在第18行 现在_dataSource被刷新所以它被提取让我们说4个项目,所以我希望用户留在他所在的项目上。

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

12 个答案:

答案 0 :(得分:30)

Swift 3 +

您需要保存\r的当前偏移量,然后重新加载,然后在UITableView上设置偏移量。

我已经为此创建了这个功能:

UITableView

只需拨打:func reload(tableView: UITableView) { let contentOffset = tableView.contentOffset tableView.reloadData() tableView.layoutIfNeeded() tableView.setContentOffset(contentOffset, animated: false) }

即可

答案 1 :(得分:22)

SWIFT 3

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

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

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

答案 2 :(得分:10)

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

    // 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行高。

答案 3 :(得分:3)

我这样做:

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
}

答案 4 :(得分:1)

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

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

答案 5 :(得分:1)

使用扩展名

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

extension UITableView {

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

答案 6 :(得分:0)

尝试替换

reloadData

tableView.reloadRowsat: tableView!.indexPathsForVisibleRows!, with: .none),

但您应该关注no cells,如果no cells,此方法应该导致崩溃。

答案 7 :(得分:0)

如果你想重新加载,你必须

self.tableView.reloadData()

self.tableView.layoutIfNeeded()

并使用此UITableViewDelegate

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

并且您的tableView将保留在上一个滚动位置而不滚动

答案 8 :(得分:0)

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

答案 9 :(得分:0)

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)

答案 10 :(得分:0)

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

 self.tableView.estimatedRowHeight = 1000

就是这样!

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

答案 11 :(得分:0)

我写了一些对我来说很完美的东西:

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