ios UITableView 刷新而不滚动

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25589540/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 02:07:10  来源:igfitidea点击:

UITableView Refresh without scrolling

iosobjective-cuitableview

提问by ColdSteel

I have a _TableViewwith items , and I want to set automatic refresh,and I don't want it to scroll on refresh , lets say user scrolled 2 pages down , and the refresh trigered -> so I want to put the refreshed content to the top of the table without interupting user's scrolling

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

Assume user was on row 18 and now the _dataSourceis refreshed so it fetched lets say 4 items , so I want user to stay on the item he was.

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

What would be the best approach to achieve it ??

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

采纳答案by Prasad

I am showing if only one row is being added. You can extend it to multiple rows.

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

    // 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];

But for this to work you need to have defined - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPaththe method. Or else, you can directly give your tableview row height if it is constant.

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

回答by David Seek

For Swift 3+:

对于Swift 3+

You need to save the current offset of the UITableView, then reload and then set the offset back on the UITableView.

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

I have created this function for this purpose:

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

func reload(tableView: UITableView) {

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

}

Simply call it with: reload(tableView: self.tableView)

简单地调用它: reload(tableView: self.tableView)

回答by Trung Phan

SWIFT 3

斯威夫特 3

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

This is error of iOS8 when using UITableViewAutomatic Dimension. We need store the content offset of table, reload table, force layout and set contenOffset back.

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

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

回答by COVID19

Just set estimatedRowHeightto maximum possible value.

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

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

That's it!!

就是这样!!

Note:

笔记:

Please do not use FLT_MAX, DBL_MAXvalue. May be it will crash your app.

请不要FLT_MAX, DBL_MAX使用价值。可能会使您的应用程序崩溃。

回答by Marco M

I'm doing it this way:

我是这样做的:

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

...also, since I use dynamic cell height, to avoid some weirdness, the estimation is cached:

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

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
}

回答by JhanviR

This code will prevent unnecessary animation and maintain the scroll view's content offset, it worked fine for me.

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

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

回答by Yifan

Use Extension

使用扩展

create UITableViewExtensions.swiftand add following:

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

extension UITableView {

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

回答by ZAFAR007

Swift 4.2 :Simple Solution

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

回答by Pankaj Kulkarni

In iOS 12.x, using Xcode 10.2.1, an easier option is.

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

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

This works better than following; it shakes at times when the row is not fully visible.

这比以下更有效;当行不完全可见时,它有时会震动。

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

回答by Hyman Chen

try to replace

尝试更换

reloadDatawith

reloadData

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

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

but you should be care about no cells, if no cells, this method should cause crash.

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