save selected row in UITableView after reloadData

后端 未结 14 935
后悔当初
后悔当初 2020-12-24 11:20

I write custom jabber client in iphone.

I use xmppframework as engine.

And I have UITableViewController with NSMutableArray for repesent contact list.

<
相关标签:
14条回答
  • 2020-12-24 12:09

    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];
        }
    
    0 讨论(0)
  • 2020-12-24 12:09

    A lot of these answers are basically using hacks to re-select the row that was previously highlighted by finding out what the previously selected row was from the table view which seems like a bad way to go about it, because usually when your tableview reloads, there is a change in the data that is populating the tableview.

    So rather base you re-selection of the row based on your data

    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
    }
    
    0 讨论(0)
  • 2020-12-24 12:10

    Edit:

    After testing, it doesn't always work!,

    the reason is the index may change !

    so the correct way is
    make new variable

    var currentIndex : IndexPath?
    

    and on didSelectRow

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

    then change the function to

     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 Answer worked

    this is a Swift version of his code

    Swift 4.2.3

    func reloadTableView() {
            let indexPaths = tableView.indexPathsForSelectedRows
            tableView.reloadData()
            for path in indexPaths ?? [] {
                tableView.selectRow(at: path, animated: false, scrollPosition: .none)
            }
        }
    
    0 讨论(0)
  • 2020-12-24 12:13

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

    0 讨论(0)
  • 2020-12-24 12:16

    my two cents for UICollectionView: (credits to Basil..)

    I do run in main thread as I reload from a background task:

    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: [])
                    }
                }
        } 
    
    0 讨论(0)
  • 2020-12-24 12:24

    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:.

    NSIndexPath *selectedIndexPath = [self.tableView indexPathForSelectedRow];
    [self.tableView reloadData];
    [self.tableView selectRowAtIndexPath:selectedIndexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
    [[self.tableView cellForRowAtIndexPath:selectedIndexPath] layoutIfNeeded];
    
    0 讨论(0)
提交回复
热议问题