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

时间:2009-12-01 16:06:19

标签: iphone user-interface

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

我使用xmppframework作为引擎。

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

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

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

用户丢失了当前选择项目。

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

THX。

14 个答案:

答案 0 :(得分:67)

简单的方法就是这样:

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

答案 1 :(得分:23)

在Marco的回答中添加一点:

首先,如果您使用的是多项选择,则可以将此方法添加到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];
    }
}

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

见这里:http://developer.apple.com/library/ios/#documentation/uikit/reference/UITableViewController_Class/Reference/Reference.html

答案 2 :(得分:5)

Swift 4.2已测试

重新加载表视图后更新选定行的正确方法是:

let selectredRows = tableView.indexPathsForSelectedRows

tableView.reloadData()

DispatchQueue.main.async {
    selectredRows?.forEach({ (selectedRow) in
        tableView.selectRow(at: selectedRow, animated: false, scrollPosition: .none)
    })
}

答案 3 :(得分:4)

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

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

答案 4 :(得分:3)

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

答案 5 :(得分:3)

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

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

答案 6 :(得分:1)

这对我有用:

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

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

答案 7 :(得分:1)

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

    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 :(得分:1)

编辑:

经过测试, 它并不总是有效!,

原因是索引可能会改变!

所以正确的方法是
制作新变量

var currentIndex : IndexPath?

以及didSelectRow

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

        currentIndex = indexPath
}

然后将功能更改为

 func reloadTableView() {
        let indexPaths = tableview.indexPathsForSelectedRows
        if let currentIndex = self.currentIndex {
        self.tableview.reloadRows(at: [currentIndex], with: .fade)
        for path in indexPaths ?? [] {
            tableview.selectRow(at: path, animated: false, scrollPosition: .none)
            }}
    }

==========

@marmor答案有效

这是他代码的Swift版本

Swift 4.2.3

func reloadTableView() {
        let indexPaths = tableView.indexPathsForSelectedRows
        tableView.reloadData()
        for path in indexPaths ?? [] {
            tableView.selectRow(at: path, animated: false, scrollPosition: .none)
        }
    }

答案 9 :(得分:0)

SWIFT 3

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

答案 10 :(得分:0)

我通过声明一个要存储的数组(例如,所选单元格的ID或字符串文本)并将其添加到didSelectItemAtIndexPath函数上来更好地解决了这个问题。 这样,即使行数发生变化,所选行也不会改变。 例如:

var selectedItems: [String] = [] // This array type really depends on your preference and what property you're using to store
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    guard let cell = collectionView.cellForItem(at: indexPath) else { return }
    selectedItems.append(cell.textField.text)
}

在您的初始cellForItemAtIndexPath上

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionCell", for: indexPath)
    if let text = cell.textField.text {
        if selectedItems.contains(text) {
            collectionView.selectItem(at: indexPath, animated: true, scrollPosition: [])
        }
    }
    return cell
}

答案 11 :(得分:0)

我的2美分用于 UICollectionView :(归功于Basil ..)

我从后台任务重新加载时确实在主线程中运行:

final override func safeReloadData(){

            DispatchQueue.main.async { [weak self] in

                guard let self = self else {
                    return
                }

                let indexPaths = self.collectionView.indexPathsForSelectedItems
                self.collectionView.reloadData()
                for path in indexPaths ?? [] {
                    self.collectionView.selectItem(at: path, animated: false, scrollPosition: [])
                }
            }
    } 

答案 12 :(得分:0)

这些答案中的许多基本上都是通过黑客手段来重新选择以前突出显示的行,方法是从表格视图中找出先前选择的行,这似乎是一个不好的方法,因为通常在您重新加载tableview时,填充tableview的数据发生了变化。

因此,您根据您的数据重新选择行

let data = ["some", "array", "of", "data"]
let selected = "of" // this should be populated from didSelectRowAt indexPath:

tableView.reloadData()

if let index = data.firstIndex(of: selected) {
  tableView.selectRow(at: IndexPath(row: index, section: 0), animated: false, scrollPosition: .none) // the "of" row should now be highlighted, regardless if the data changed order
}

答案 13 :(得分:-4)

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

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

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