web-dev-qa-db-ja.com

reloadDataの後で、選択した行をUITableViewに保存します。

IphoneでカスタムJabberクライアントを作成します。

xmppframework をエンジンとして使用しています。

そして、私は代表的な連絡先リストのためのNSMutableArrayを備えたUITableViewControllerを持っています。

名簿(別名連絡先リスト)を受け取った(または誰かが内容を変更した)とき、UITableViewアイテムを変更(追加/削除/変更)したいと思います。したがって、ユーザーがリストの更新時にlistViewを操作すると、

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

ユーザーは現在の選択項目を失いました。

だから、私の質問は、reloadDataの後に現在の選択項目を保存する方法です(可能な場合、つまり選択された項目が削除されない場合)。

どうも。

34
vinnitu

簡単な方法は次のようなものです:

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

マルコの答えに少し追加:

まず、multiple selectionを使用している場合、このメソッドを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

25
marmor

Swift 4.2テスト済み

テーブルビューの再読み込み後に選択した行を更新する正しい方法は次のとおりです。

let selectedRows = tableView.indexPathsForSelectedRows

tableView.reloadData()

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

遅延を追加してもうまくいきませんでした(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

回避策は、reloadDataの代わりにreloadSections:を使用することです。何らかの理由でreloadDataは現在の選択を削除します。

4
Greg

IOS 9.3およびSwift 2.xでは、メインスレッド :)で関数を呼び出すだけでした。

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

これは私にとってはうまくいきます:

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

編集:

テスト後、常に機能するとは限りません!、

その理由は、インデックスが変更される可能性があるためです。

だから正しい方法は
新しい変数を作成

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

これは、テーブルの更新を行い、選択を維持したい場合の解決策です。

    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

これらの回答の多くは、基本的にはハックを使用して、以前に選択された行がテーブルビューから何であるかを見つけることによって、以前にハイライトされた行を再選択しています。テーブルビューに入力しているデータに変更があります。

したがって、データに基づいて行の再選択をベースにしてください

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
Fonix

私の2セントICollectionView:(バジルへのクレジット..)

バックグラウンドタスクからリロードするときにメインスレッドで実行します。

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
ingconti

Swift

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

保存する配列を宣言して(たとえば、選択したセルの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
}
0
Jose Tapizquent