it-swarm.com.ru

сохранить выбранную строку в UITableView после reloadData

Я пишу пользовательский клиент Jabber в iphone.

Я использую xmppframework в качестве движка.

И у меня есть UITableViewController с NSMutableArray для повторного списка контактов.

Когда я получаю (или кто-то изменяет его содержимое) список (он же список контактов), я хочу изменить элементы UITableView (добавить/удалить/изменить). Так что, если пользователь работает с listView во время обновления списка 

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

пользователь потерял текущий элемент выбора.

Итак, мой вопрос, как сохранить (если возможно, я имею в виду, если данный выбранный элемент не удален) текущий элемент выбора после reloadData?

Спасибо.

27
vinnitu

Простой способ - что-то вроде этого:

NSIndexPath *ipath = [self.tableView indexPathForSelectedRow];
[self.tableView reloadData];
[self.tableView selectRowAtIndexPath:ipath animated:NO scrollPosition:UITableViewScrollPositionNone];
66
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

22
marmor

Добавление задержки для меня не сработало (протестировано на 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
antonjn

В iOS 9.3 и Swift 2.x мне просто нужно было вызвать функцию в главном потоке :)

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

Обходной путь должен использовать reloadSections: вместо reloadData. По какой-то причине reloadData удаляет текущий выбор.

3
Greg

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
muhasturk

Это работает для меня:

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.

1
Adam Wallner

Это решение для случая, если вы хотите обновить таблицу и сохранить выбор:

    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];
    }
1
Ezeki

Swift 3 :

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

Я решил эту проблему лучше, объявив массив для хранения, скажем, идентификатора или строкового текста выбранной ячейки и добавив его в функцию 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
}
0
Jose Tapizquent