在reloadData之后保存UITableView中的选定行

时间:2022-09-17 10:49:58

I write custom jabber client in iphone.

我在iphone中编写自定义jabber客户端。

I use xmppframework as engine.

我使用xmppframework作为引擎。

And I have UITableViewController with NSMutableArray for repesent contact list.

我有UITableViewController和NSMutableArray用于重复联系人列表。

When i receive(or somebody change it contents) roster (aka contact list) i wanna change UITableView items (add/remove/modify). So if User work with listView at time when list updates by

当我收到(或有人更改其内容)名单(又名联系人列表)时,我想更改UITableView项目(添加/删除/修改)。因此,如果用户在列表更新时使用listView

[items addObject:newItem];
[self.tableView reloadData];

user lost current selection item.

用户丢失当前选择项目。

So, my question is howto save (if possible, i mean if given selected item not removed) current select item after reloadData?

所以,我的问题是如何保存(如果可能的话,我的意思是如果给定的选项没有删除)reloadData之后的当前选择项目?

Thx.

谢谢。

9 个解决方案

#1


64  

The easy way is something like this:

简单的方法是这样的:

NSIndexPath *ipath = [self.tableView indexPathForSelectedRow];
[self.tableView reloadData];
[self.tableView selectRowAtIndexPath:ipath animated:NO scrollPosition:UITableViewScrollPositionNone];

#2


21  

Adding a bit to Marco's answer:

在Marco的回答中添加一点:

First, if you're using multiple selection, you can add this method to your ViewController and call it whenever you need to call [tableView reloadData]:

首先,如果您正在使用多个选择,则可以将此方法添加到ViewController并在需要调用[tableView reloadData]时调用它:

- (void)reloadTableView
{
    NSArray *indexPaths = [self.tableView indexPathsForSelectedRows];
    [self.tableView reloadData];
    for (NSIndexPath *path in indexPaths) {
        [self.tableView selectRowAtIndexPath:path animated:NO scrollPosition:UITableViewScrollPositionNone];
    }
}

Second, if you're in a UITableViewController and you want to preserve selection after tableView appears there's a feature in UITableViewController: clearsSelectionOnViewWillAppear you can turn on or off.

其次,如果您在UITableViewController中,并且想要在tableView出现之后保留选择,那么UITableViewController中有一个功能:clearsSelectionOnViewWillAppear可以打开或关闭。

See here: http://developer.apple.com/library/ios/#documentation/uikit/reference/UITableViewController_Class/Reference/Reference.html

请看:http://developer.apple.com/library/ios/#documentation/uikit/reference/UITableViewController_Class/Reference/Reference.html

#3


4  

Adding a delay didn't work for me (tested on iOS 8.4 and iOS 9). What did work was adding a call to -layoutIfNeeded on the selected cell, after calling -selectRowAtIndexPath:animated:scrollPosition:.

添加延迟对我不起作用(在iOS 8.4和iOS 9上测试)。在调用-selectRowAtIndexPath:animated:scrollPosition:之后,所做的工作是在所选单元格上添加对-layoutIfNeeded的调用。

NSIndexPath *selectedIndexPath = [self.tableView indexPathForSelectedRow];
[self.tableView reloadData];
[self.tableView selectRowAtIndexPath:selectedIndexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
[[self.tableView cellForRowAtIndexPath:selectedIndexPath] layoutIfNeeded];

#4


3  

The workaround is to use reloadSections: instead of reloadData. For some reason reloadData removes the current selection.

解决方法是使用reloadSections:而不是reloadData。由于某种原因,reloadData删除当前选择。

#5


3  

On iOS 9.3 and Swift 2.x, I simply had to call the function on the main thread :)

在iOS 9.3和Swift 2.x上,我只需要在主线程上调用该函数:)

self.tableView?.selectRowAtIndexPath(indexPath, animated: false, scrollPosition: .None)

#6


1  

This works for me:

这对我有用:

NSIndexPath *indexPath = [table indexPathForSelectedRow];
[table reloadData];
double delayInSeconds = 0.01;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    [self.table selectRowAtIndexPath:indexPath animated:YES
                              scrollPosition:UITableViewScrollPositionNone];
});

The trick is to make selectRowAtIndexpath run later a bit. The code above is an Xcode template you can select when you start writing dispatch_after.

诀窍是让selectRowAtIndexpath稍后运行。上面的代码是一个Xcode模板,您可以在开始编写dispatch_after时选择该模板。

#7


1  

This is a solution for the case if you want to do table updates and keep the selection:

如果您想要进行表更新并保留选择,这是一个解决方案:

    NSIndexPath* pathToSelect = [self.tableView indexPathForSelectedRow];
    if (pathToSelect && newRows) {
        int row = pathToSelect.row;
        for (NSIndexPath* path in newRows) {
            if (path.section == pathToSelect.section && path.row <= pathToSelect.row) {
                row++;
            }
        }
        pathToSelect = [NSIndexPath indexPathForRow:row inSection:pathToSelect.section];
    }

    [self.tableView beginUpdates];
    if (reloadRows) [self.tableView reloadRowsAtIndexPaths:reloadRows withRowAnimation:UITableViewRowAnimationFade];
    if (newSections) [self.tableView insertSections:newSections withRowAnimation:UITableViewRowAnimationFade];
    if (newRows) [self.tableView insertRowsAtIndexPaths:newRows withRowAnimation:UITableViewRowAnimationFade];
    [self.tableView endUpdates];

    if (pathToSelect) {
        [self.tableView selectRowAtIndexPath:pathToSelect animated:NO scrollPosition:UITableViewScrollPositionNone];
    }

#8


0  

SWIFT 3:

SWIFT 3:

self.collectionView.reloadData()
self.collectionView.selectItem(at: indexPath, animated: false, scrollPosition: [])

#9


-5  

It sounds like you are not using a 'model' for the data - rather simply updating the 'view' (user interface), and thus is probably a bad design.

听起来你没有使用数据的“模型” - 而只是简单地更新'视图'(用户界面),因此可能是一个糟糕的设计。

reloadData should cause the view to be updated with data from the model, which should contain the most current data to be displayed.

reloadData应该使用模型中的数据更新视图,该数据应包含要显示的最新数据。

search for resources on the 'model view controller pattern'

在'模型视图控制器模式'上搜索资源

#1


64  

The easy way is something like this:

简单的方法是这样的:

NSIndexPath *ipath = [self.tableView indexPathForSelectedRow];
[self.tableView reloadData];
[self.tableView selectRowAtIndexPath:ipath animated:NO scrollPosition:UITableViewScrollPositionNone];

#2


21  

Adding a bit to Marco's answer:

在Marco的回答中添加一点:

First, if you're using multiple selection, you can add this method to your ViewController and call it whenever you need to call [tableView reloadData]:

首先,如果您正在使用多个选择,则可以将此方法添加到ViewController并在需要调用[tableView reloadData]时调用它:

- (void)reloadTableView
{
    NSArray *indexPaths = [self.tableView indexPathsForSelectedRows];
    [self.tableView reloadData];
    for (NSIndexPath *path in indexPaths) {
        [self.tableView selectRowAtIndexPath:path animated:NO scrollPosition:UITableViewScrollPositionNone];
    }
}

Second, if you're in a UITableViewController and you want to preserve selection after tableView appears there's a feature in UITableViewController: clearsSelectionOnViewWillAppear you can turn on or off.

其次,如果您在UITableViewController中,并且想要在tableView出现之后保留选择,那么UITableViewController中有一个功能:clearsSelectionOnViewWillAppear可以打开或关闭。

See here: http://developer.apple.com/library/ios/#documentation/uikit/reference/UITableViewController_Class/Reference/Reference.html

请看:http://developer.apple.com/library/ios/#documentation/uikit/reference/UITableViewController_Class/Reference/Reference.html

#3


4  

Adding a delay didn't work for me (tested on iOS 8.4 and iOS 9). What did work was adding a call to -layoutIfNeeded on the selected cell, after calling -selectRowAtIndexPath:animated:scrollPosition:.

添加延迟对我不起作用(在iOS 8.4和iOS 9上测试)。在调用-selectRowAtIndexPath:animated:scrollPosition:之后,所做的工作是在所选单元格上添加对-layoutIfNeeded的调用。

NSIndexPath *selectedIndexPath = [self.tableView indexPathForSelectedRow];
[self.tableView reloadData];
[self.tableView selectRowAtIndexPath:selectedIndexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
[[self.tableView cellForRowAtIndexPath:selectedIndexPath] layoutIfNeeded];

#4


3  

The workaround is to use reloadSections: instead of reloadData. For some reason reloadData removes the current selection.

解决方法是使用reloadSections:而不是reloadData。由于某种原因,reloadData删除当前选择。

#5


3  

On iOS 9.3 and Swift 2.x, I simply had to call the function on the main thread :)

在iOS 9.3和Swift 2.x上,我只需要在主线程上调用该函数:)

self.tableView?.selectRowAtIndexPath(indexPath, animated: false, scrollPosition: .None)

#6


1  

This works for me:

这对我有用:

NSIndexPath *indexPath = [table indexPathForSelectedRow];
[table reloadData];
double delayInSeconds = 0.01;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    [self.table selectRowAtIndexPath:indexPath animated:YES
                              scrollPosition:UITableViewScrollPositionNone];
});

The trick is to make selectRowAtIndexpath run later a bit. The code above is an Xcode template you can select when you start writing dispatch_after.

诀窍是让selectRowAtIndexpath稍后运行。上面的代码是一个Xcode模板,您可以在开始编写dispatch_after时选择该模板。

#7


1  

This is a solution for the case if you want to do table updates and keep the selection:

如果您想要进行表更新并保留选择,这是一个解决方案:

    NSIndexPath* pathToSelect = [self.tableView indexPathForSelectedRow];
    if (pathToSelect && newRows) {
        int row = pathToSelect.row;
        for (NSIndexPath* path in newRows) {
            if (path.section == pathToSelect.section && path.row <= pathToSelect.row) {
                row++;
            }
        }
        pathToSelect = [NSIndexPath indexPathForRow:row inSection:pathToSelect.section];
    }

    [self.tableView beginUpdates];
    if (reloadRows) [self.tableView reloadRowsAtIndexPaths:reloadRows withRowAnimation:UITableViewRowAnimationFade];
    if (newSections) [self.tableView insertSections:newSections withRowAnimation:UITableViewRowAnimationFade];
    if (newRows) [self.tableView insertRowsAtIndexPaths:newRows withRowAnimation:UITableViewRowAnimationFade];
    [self.tableView endUpdates];

    if (pathToSelect) {
        [self.tableView selectRowAtIndexPath:pathToSelect animated:NO scrollPosition:UITableViewScrollPositionNone];
    }

#8


0  

SWIFT 3:

SWIFT 3:

self.collectionView.reloadData()
self.collectionView.selectItem(at: indexPath, animated: false, scrollPosition: [])

#9


-5  

It sounds like you are not using a 'model' for the data - rather simply updating the 'view' (user interface), and thus is probably a bad design.

听起来你没有使用数据的“模型” - 而只是简单地更新'视图'(用户界面),因此可能是一个糟糕的设计。

reloadData should cause the view to be updated with data from the model, which should contain the most current data to be displayed.

reloadData应该使用模型中的数据更新视图,该数据应包含要显示的最新数据。

search for resources on the 'model view controller pattern'

在'模型视图控制器模式'上搜索资源