Mengapa UITableViewCell tetap disorot?


145

Apa yang menyebabkan sel tampilan tabel tetap disorot setelah disentuh? Saya mengklik sel dan dapat melihatnya tetap disorot saat tampilan detail didorong. Setelah tampilan detail muncul, sel masih disorot.

Jawaban:


262

Di Anda, didSelectRowAtIndexPathAnda perlu menelepon deselectRowAtIndexPathuntuk membatalkan pilihan sel.

Jadi, apa pun yang Anda lakukan di dalam diri didSelectRowAtIndexPathAnda, panggil saja deselectRowAtIndexPathjuga.

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
 // Do some stuff when the row is selected
 [tableView deselectRowAtIndexPath:indexPath animated:YES];
}

11
Saya lebih suka memanggil deselectRowAtIndexPathdi viewDidAppear saya, jika pilih baris menampilkan tampilan baru.
notnoop

5
Sebenarnya itu bukan tempat yang tepat untuk menyebutnya, sungguh ... coba gunakan aplikasi Apple dengan tabel (Kontak adalah yang baik) dan Anda akan melihat setelah Anda mendorong ke layar baru, saat kembali sel masih disorot sebentar sebelum terpilih. Secara teori saya pikir Anda tidak harus melakukan kerja ekstra untuk memilikinya hapus segera sendiri, sehingga kode di viewDidAppear seharusnya tidak diperlukan ...
Kendall Helmstetter Gelner

6
@ Kendall, @ 4thSpace: Mungkin komentar terakhir saya membingungkan siapa yang saya maksudkan, permintaan maaf untuk itu. UITableViewController memanggil -deselectRowAtIndexPath:animated:metode dari properti tableView-nya -viewDidAppear. Namun, jika Anda memiliki tampilan tabel dalam subclass UIViewController, Anda harus menghubungi -deselectRowAtIndexPath:animated:dari -viewDidAppeardiri sendiri. :)
Daniel Tull

5
Dalam subkelas saya dari UITableViewController itu sebenarnya menimpanya -viewWillAppear:. Menambahkan panggilan untuk [super viewWillAppear:animated]membuatnya berfungsi kembali.
Ben Challenor

5
Sejak 3.2, perilaku deselection otomatis terjadi jika Anda UITableViewController's clearsSelectionOnViewWillAppearproperti diatur ke YES(yang merupakan default), dan Anda tidak dicegah [super viewWillAppear]dari yang disebut.
Defragged

62

Cara paling bersih untuk melakukannya adalah pada viewWillAppear:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    // Unselect the selected row if any
    NSIndexPath*    selection = [self.tableView indexPathForSelectedRow];
    if (selection) {
        [self.tableView deselectRowAtIndexPath:selection animated:YES];
    }
}

Dengan cara ini Anda memiliki animasi memudar pemilihan ketika Anda kembali ke controller, sebagaimana mestinya.

Diambil dari http://forums.macrumors.com/showthread.php?t=577677

Versi cepat

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    // deselect the selected row if any
    let selectedRow: IndexPath? = tableView.indexPathForSelectedRow
    if let selectedRowNotNill = selectedRow {
        tableView.deselectRow(at: selectedRowNotNill, animated: true)
    }
}

1
Ini adalah salah satu yang saya harapkan kebanyakan orang inginkan jika mereka tidak menggunakan UITableViewController. +1
MikeB

3
Saya ingin tahu apa yang dilakukan orang sekarang karena iOS 7 memungkinkan pengguna untuk 'menarik' kembali. Menyeret sebagian tetapi tidak menyelesaikan tindakan akan memunculkan viewWillAppear. Ketika pengguna kembali nyata, baris tidak akan dipilih.
Ben Packard

1
@BenPackard panggil viewDidAppearsaja.
squarefrog

@ Jeanica indexPathForSelectedRowPanggilan dapat mengembalikan nol sehingga harus diperiksa. Dokumentasi menyatakan : Jalur indeks yang mengidentifikasi baris dan indeks bagian dari baris yang dipilih, atau nihil jika jalur indeks tidak valid.
Gordonium

ini harus menyatakan sebagai jawaban yang diterima, ini lebih ramah UI sehingga pengguna dapat mencapai pilihan setelah kembali, sempurna 👌
Yahya Alshaar

20

Apakah Anda subkelas -(void)viewWillAppear:(BOOL)animated? UITableViewCell yang dipilih tidak akan membatalkan pilihan ketika Anda tidak memanggil [super viewWillAppear:animated];metode kustom Anda.


19

Untuk pengguna Swift, tambahkan ini ke kode Anda:

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    tableView.deselectRowAtIndexPath(indexPath, animated: true)
}

Ini jawaban paulthenerd kecuali di Swift bukan Obj-C.


1
bukankah itu tidak dipilih sendiri, maksud saya saat Anda melepaskannya?
Sayang

@ Madu Mungkin jadi di versi iOS sebelumnya, atau setelah tampilan menghilang, tetapi tentu saja tidak sekarang di iOS 10 (mungkin bahkan lebih awal) dan di atas.
Jamie Birch

9

Solusi Swift 3

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
      tableView.deselectRow(at: indexPath as IndexPath, animated: true)
}

7

Jika Anda menggunakan UITableViewCell, berikan komentar pada baris berikut

- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{

 // [super setSelected:selected animated:animated];

}

Semoga ini membantu.


4

Diperbarui dengan Swift 4

Setelah beberapa percobaan, juga berdasarkan jawaban sebelumnya, saya mendapat kesimpulan bahwa perilaku terbaik dapat dicapai dalam 2 cara: (hampir identik dalam praktik)

// First Solution: delegate of the table View
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    tableView.deselectRow(at: indexPath, animated: false)
}

// Second Solution: With the life cycle of the view.
override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(animated)

    let selectedRow: IndexPath? = tableView.indexPathForSelectedRow
    if let selectedRow = selectedRow {
        tableView.deselectRow(at: selectedRow, animated: false)
    }
}

Saya pribadi mengadopsi solusi pertama, karena itu lebih ringkas. Kemungkinan lain, jika Anda memerlukan sedikit animasi saat kembali ke tableView, adalah menggunakan viewWillAppear:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    let selectedRow: IndexPath? = _view.tableView.indexPathForSelectedRow
    if let selectedRow = selectedRow {
        _view.tableView.deselectRow(at: selectedRow, animated: true)
    }
}

Terakhir tetapi tidak kalah pentingnya, jika Anda menggunakan UITableViewController, Anda juga dapat memanfaatkan properti ini untuk menghapusSelectionOnViewWillAppear .


3

Untuk mendapatkan perilaku yang dijelaskan oleh Kendall Helmstetter Gelner dalam komentarnya, Anda mungkin tidak ingin membatalkan pilihanRowAtIndexPath melainkan properti clearsSelectionOnViewWillAppear pada pengontrol Anda. Mungkin ini diatur ke YA karena kecelakaan?

Lihat komentar di template Apple default untuk subclass UITableViewController baru:

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Uncomment the following line to preserve selection between presentations.
    // self.clearsSelectionOnViewWillAppear = NO;
}

2

Saya mendapatkan masalah ini juga untuk aplikasi drill-down saya. Setelah viewcontroller, yang saya sebut VC, kembali setelah mendorong ViewController lain, sel yang dipilih dalam VC tetap disorot. Dalam aplikasi saya, saya telah membuat VC untuk menangani level kedua (dari tiga level) dari drill-down saya.

Masalah dalam kasus saya adalah bahwa VC adalah UIViewController (yang berisi tampilan yang berisi TableView). Saya malah membuat VC sebagai UITableViewController (yang berisi TableView). Kelas UITableViewController secara otomatis menangani penonaktifanan sel tabel setelah kembali dari push. Jawaban kedua untuk posting " Masalah dengan deselectRowAtIndexPath di tableView " memberikan jawaban yang lebih lengkap untuk masalah ini.

Masalahnya tidak terjadi untuk root viewcontroller karena ketika saya membuat aplikasi sebagai "Aplikasi berbasis Navigasi" di XCode, viewcontroller root yang dihasilkan sudah dibuat untuk subkelas UITableViewController.


1

Jika tidak ada yang cocok untuk Anda, pertimbangkan ini:

Gunakan segue bersantai untuk menelepon:

@IBAction func unwind_ToTableVC (segue: UIStoryboardSegue) {
    if let index = tableView.indexPathForSelectedRow {
        tableView.deselectRowAtIndexPath(index, animated: true)
    }
}

Kenapa melakukan ini? Terutama jika Anda mengalami masalah dalam menjalankan kode yang tidak dipilih untuk dijalankan pada waktu yang tepat. Saya mengalami masalah dengan itu tidak bekerja pada viewWillAppear sehingga bersantai bekerja jauh lebih baik.

Langkah:

  1. Tuliskan segue rileks (atau tempel dari atas) ke VC 1 Anda (yang berisi tabel)

  2. Pergi ke VC ke-2. Seret kontrol dari tombol Batal / Selesai / Dll yang Anda gunakan untuk mengabaikan VC itu dan seret ke Ikon Keluar di bagian atas.

  3. Pilih segmen bersantai yang Anda buat di langkah 1

    Semoga berhasil.


Ini adalah solusi terbaik untuk saat-saat ketika viewDidAppear tidak menyala (yaitu jika tampilan anak disajikan secara modular sebagai lembar formulir dan tidak mencakup seluruh layar).
pheedsta

1

Saya menggunakan CoreData sehingga kode yang bekerja untuk saya adalah kombinasi ide dari berbagai jawaban, di Swift:

override func viewDidAppear(_ animated: Bool) {
    if let testSelected = yourTable.indexPathForSelectedRow {
        yourTable.deselectRow(at: testSelected, animated: true)
    }
    super.viewDidAppear(true)
}

1
 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    tableView.deselectRow(at: indexPath as IndexPath, animated: true)
}

0

Saya sudah memiliki masalah yang sama sejak lama sehingga kalau-kalau ada orang lain yang berjuang:

Lihatlah Anda -tableView: cellForRowAtIndexPath:dan lihat apakah Anda membuat sel atau menggunakan 'reuse identifier'. Jika yang terakhir, pastikan bahwa tabel Anda di IB memiliki sel dengan pengenal itu. Jika Anda tidak menggunakan Pengidentifikasi Penggunaan Kembali cukup buat sel baru untuk setiap baris.

Ini kemudian akan memberi meja Anda 'garis memudar yang diharapkan' diharapkan muncul.


0

Gunakan metode ini di kelas UITableViewCell

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {

   // Just comment This line of code
   // [super setSelected:selected animated:animated];        
}

0

Untuk Swift 3: Saya lebih suka menggunakannya di viewDidDisappear

Menetapkan:-

    var selectedIndexPath = IndexPath()

Di viewDidDisappear: -

    override func viewDidDisappear(_ animated: Bool) {
    yourTableView.deselectRow(at: selectedIndexPath, animated: true)
}

Di didSelectRowAtIndexPath: -

    func tableView(_ tableView: UITableView, didSelectRowAtIndexPath indexPath: IndexPath) {
    selectedIndexPath = indexPath
}

0

jika sel tetap disorot setelah menyentuhnya, Anda dapat memanggil metode UITabelView,

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{

`[tableView deselectRowAtIndexPath:indexPath animated:YES];`   

}

Atau, Anda dapat menggunakan metode berikut dan memodifikasinya sesuai dengan kebutuhan Anda,

// MARK: UITableViewDelegate

func tableView(tableView: UITableView, didHighlightRowAtIndexPath indexPath: NSIndexPath) {
  if let cell = tableView.cellForRowAtIndexPath(indexPath) {
     cell.backgroundColor = UIColor.greenColor()
  }
}

func tableView(tableView: UITableView, didUnhighlightRowAtIndexPath indexPath: NSIndexPath) {
  if let cell = tableView.cellForRowAtIndexPath(indexPath) {
     cell.backgroundColor = UIColor.blackColor()
  }
} 

0

Xcode 10, Swift 4

Saya memiliki masalah yang sama dan menemukan saya meninggalkan panggilan kosong ke viewWillAppear di bagian bawah tableViewController saya. Setelah saya menghapus fungsi override kosong baris tidak lagi disorot setelah kembali ke tampilan tableView.

masalah func

override func viewWillAppear(_ animated: Bool) {
  // need to remove this function if not being used.
}

menghapus fungsi kosong memecahkan masalah saya.


0

Solusi Swift 5:

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    tableView.deselectRow(at: indexPath as IndexPath, animated: true)
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.