UITableview: Cara Menonaktifkan Seleksi untuk Beberapa Baris tetapi Tidak Lainnya


298

Saya menampilkan tableviewkonten grup yang diuraikan dari XML. Saya ingin menonaktifkan acara klik di atasnya (saya seharusnya tidak dapat mengkliknya sama sekali) Tabel ini berisi dua grup. Saya ingin menonaktifkan pilihan untuk grup pertama saja tetapi tidak untuk grup kedua. Mengklik baris pertama grup kedua navigateske tabung saya player view.

Bagaimana saya bisa membuat grup atau baris tertentu saja yang bisa dipilih?

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
{
    if(indexPath.section!=0)
    if(indexPath.row==0)    

    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:tubeUrl]];   
}

Terima kasih.

Jawaban:


499

Anda hanya perlu memasukkan kode ini ke dalam cellForRowAtIndexPath

Untuk menonaktifkan properti pemilihan sel: (sambil mengetuk sel)

cell.selectionStyle = UITableViewCellSelectionStyleNone;

Untuk mengaktifkan kemampuan memilih (ketuk) sel: (mengetuk sel)

// Default style
cell.selectionStyle = UITableViewCellSelectionStyleBlue;

// Gray style
cell.selectionStyle = UITableViewCellSelectionStyleGray;

Perhatikan bahwa sel dengan selectionStyle = UITableViewCellSelectionStyleNone;masih akan menyebabkan UI memanggil didSelectRowAtIndexPathketika disentuh oleh pengguna. Untuk menghindari ini, lakukan seperti yang disarankan di bawah ini dan atur.

cell.userInteractionEnabled = NO;

sebagai gantinya. Perhatikan juga bahwa Anda mungkin ingin cell.textLabel.enabled = NO;mengubah item menjadi abu-abu.


1
Metode ini akan menghasilkan bug jika Anda mencoba menggesek untuk menghapus.
Vive

116
Ini adalah retas! Lakukan itu, gunakan jawaban di bawah ini - menggunakan willSelectRowAtIndexPath dengan mengembalikan nihil!
Peter Stajger

4
Hal-hal yang userInteractionEnabled tidak benar, kait akanSelectRowAtIndexPath sebagai gantinya sebagai catatan orang.
Jonny

23
Di iOS 6.0 dan yang lebih baru, tableView:shouldHighlightRowAtIndexPath:adalah UITableViewDelegatemetode baru yang mengembalikan BOOLberdasarkan apakah yang disahkan indexPathharus disorot atau tidak . Jika Anda membangun untuk 6.0 dan yang lebih baru, saya sangat merekomendasikan API baru ini.
cbowns

3
Jika Anda melakukan ini di Swift dan Anda mengalami masalah tetapi berakhir di sini, Anda harus mengatur cell!.selectionStyle = .None kekuatan yang membuka bungkusan sel, memungkinkan Anda untuk mengakses propertinya.
Marcos

371

Jika Anda ingin membuat baris (atau bagian dari baris) tidak dapat dipilih , terapkan UITableViewDelegatemetode tersebut -tableView:willSelectRowAtIndexPath:(juga disebutkan oleh TechZen). Jika indexPathtidak dapat dipilih , kembali nil, jika tidak, kembalikan indexPath. Untuk mendapatkan perilaku pemilihan default, Anda hanya mengembalikan yang indexPathditeruskan ke delegatemetode Anda , tetapi Anda juga dapat mengubah pemilihan baris dengan mengembalikan yang berbeda indexPath.

contoh:

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    // rows in section 0 should not be selectable
    if ( indexPath.section == 0 ) return nil;

    // first 3 rows in any section should not be selectable
    if ( indexPath.row <= 2 ) return nil;

    // By default, allow row to be selected
    return indexPath;
}

2
Detail kecil: Anda <= 2, bukan = <2. Senyum buruk! :)
Jonas Byström

23
Saya juga ingin menambahkan bahwa ini adalah jawaban yang benar, tetapi Anda juga harus mengatur selectionStyle ke UITableViewCellSelectionStyleNone di cellForRowAtIndexPath. Mengapa? karena tanpa gaya pemilihan ini sel tidak dapat dipilih tetapi masih akan menampilkan "seperti yang dipilih" ketika ditekan (sehingga berubah ke warna yang dipilih, jika ada satu untuk sel lainnya)
TooManyEduardos

4
ini seharusnya memiliki lebih banyak suara positif daripada jawaban yang diterima
user1244109

2
Saya pikir alasan utama ini bukan jawaban yang diterima adalah karena jawaban yang diterima lebih mudah. Meskipun ini bukan 'cara terbaik' untuk melakukannya karena meja Anda masih akan memanggil setSelected: pada sel Anda, itu masih berfungsi, secara visual. Jawaban ini di sini membutuhkan lebih banyak pekerjaan tetapi merupakan cara yang tepat untuk melakukannya (Anda harus menggabungkan saran @TooManyEduardos juga) untuk menghindari konsekuensi tak terduga dari panggilan tabel setSelected: pada sel Anda.
Brian Sachetta

Saya suka jawaban ini, tetapi jika Anda tidak ingin menduplikasi logika Anda di cellForRowAtIndexPath dan willSelectRowAtIndexPath, cukup periksa apakah cell.selectionStyle == tidak ada di willSelectRowAtIndexPath untuk mengembalikan nil (lihat jawaban saya di bawah)
Eric D'Souza

61

Mulai di iOS 6, Anda dapat menggunakan

-tableView:shouldHighlightRowAtIndexPath:

Jika Anda kembali NO, itu menonaktifkan sorotan pilihan dan storyboard memicu segues yang terhubung ke sel itu.

Metode ini dipanggil ketika sentuhan turun pada satu baris. Kembali NOke pesan itu menghentikan proses pemilihan dan tidak menyebabkan baris yang saat ini dipilih kehilangan tampilan yang dipilih saat sentuhannya turun.

Referensi Protokol UITableViewDelegate


3
Sepakat. Untuk iOS 7 & di atas ini harus menjadi metode yang disukai (pada kenyataannya di iOS 8 metode lain tidak bekerja untuk saya.)
race_carr

Ini harus menjadi jawaban teratas.
Cameron E

16

Tidak ada dari jawaban di atas yang benar-benar mengatasi masalah dengan benar. Alasannya adalah bahwa kami ingin menonaktifkan pemilihan sel tetapi tidak perlu subview di dalam sel.

Dalam kasus saya, saya sedang menghadirkan UISwitch di tengah baris dan saya ingin menonaktifkan pilihan untuk sisa baris (yang kosong) tetapi tidak untuk saklar! Cara yang tepat untuk melakukan itu karenanya dalam metode

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath

di mana pernyataan formulir

[cell setSelectionStyle:UITableViewCellSelectionStyleNone];

menonaktifkan pemilihan untuk sel tertentu sementara pada saat yang sama memungkinkan pengguna untuk memanipulasi sakelar dan karenanya menggunakan pemilih yang sesuai. Ini tidak benar jika seseorang menonaktifkan interaksi pengguna melalui

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

metode yang hanya menyiapkan sel dan tidak memungkinkan interaksi dengan UISwitch.

Apalagi menggunakan metode

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

untuk membatalkan pilihan sel dengan pernyataan formulir

[tableView deselectRowAtIndexPath:indexPath animated:NO];

masih menunjukkan baris yang dipilih saat pengguna menekan konten asliMelihat sel.

Hanya dua sen saya. Saya cukup yakin banyak orang akan menemukan ini berguna.


Setuju. Dan mengembalikan nol di willSelectRowAtIndexPathmemiliki masalah yang sama, subview tidak dapat dipilih.
jeffjv

Perhatikan juga bahwa jika Anda memiliki tabel statis, Anda bisa mengatur Seleksi ke Tidak Ada di Pembuat Antarmuka untuk sel yang tidak Anda inginkan seleksi muncul.
jeffjv

11

Anda menjebak pilihan dengan metode sumber data ini.

 tableView:willSelectRowAtIndexPath: 
 tableView:didSelectRowAtIndexPath: 
 tableView:willDeselectRowAtIndexPath: 
 tableView:didDeselectRowAtIndexPath:

Dalam metode ini, Anda memeriksa apakah baris yang dipilih adalah Anda ingin dipilih. Jika ya, ambil tindakan, jika tidak, jangan lakukan apa pun.

Sayangnya, Anda tidak dapat mematikan seleksi hanya untuk satu bagian. Seluruh meja atau tidak sama sekali.

Namun Anda dapat mengatur selectionStyleproperti sel tabelUITableViewCellSelectionStyleNone . Saya percaya itu akan membuat seleksi tidak terlihat. Dikombinasikan dengan metode di atas yang seharusnya membuat sel-sel terlihat benar-benar lembam dari perspektif pengguna.

Sunting01:

Jika Anda memiliki tabel di mana hanya beberapa baris yang dipilih, penting bahwa sel-sel dari baris yang dipilih secara visual berbeda dari baris yang tidak dapat dipilih. Tombol aksesori chevron adalah cara standar untuk melakukan ini.

Bagaimanapun Anda melakukannya, Anda tidak ingin pengguna Anda mencoba untuk memilih baris dan berpikir aplikasi telah malfed karena baris tidak melakukan apa-apa.


tolong uraikan cara menggunakan metode ini atau berikan beberapa tautan program contoh
Warrior

2
@ Prajurit: Jika Anda telah menginstal SDK, Anda dapat membuka Xcode, pergi ke Help -> Developer documentation, lalu salin nama-nama metode ke dalam bidang pencarian untuk melihat cara kerjanya. Dokumentasi Pengembang juga berisi kode sampel.
kennytm

10

Untuk Swift 4.0 misalnya:

cell.isUserInteractionEnabled = false
cell.contentView.alpha = 0.5

9

Anda perlu melakukan sesuatu seperti berikut ini untuk menonaktifkan pemilihan sel dalam cellForRowAtIndexPathmetode:

[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
[cell setUserInteractionEnabled:NO];

Untuk menampilkan sel yang berwarna abu-abu, masukkan yang berikut dalam tableView:WillDisplayCell:forRowAtIndexPathmetode:

[cell setAlpha:0.5];

Satu metode memungkinkan Anda untuk mengontrol interaktivitas, yang lain memungkinkan Anda untuk mengontrol tampilan UI.


5

Untuk menghentikan hanya beberapa sel yang dipilih gunakan:

cell.userInteractionEnabled = NO;

Selain mencegah seleksi, ini juga menghentikan tableView: didSelectRowAtIndexPath: dipanggil untuk sel yang telah disetel.


1
Suatu hal yang aneh terjadi sepanjang waktu: ketika saya mengatur userInteractionEnableduntuk TIDAK pada satu sel (lebih jelas, satu indexPath), interaksi pengguna dari beberapa sel LAIN dinonaktifkan. Saya tidak tahu mengapa ini terjadi setiap kali saya gunakan userInteractionEnabledpada sel tampilan tabel. Apakah itu bug yang diketahui atau saya melakukan sesuatu yang salah?
Philip007

3
@ Philip007 Apakah sel "TIDAK" digunakan kembali? Jika demikian, Anda mungkin perlu memastikan bahwa Anda mengaturnya ke "YA" ketika Anda mengeluarkan sel.
JosephH

1
Mengapa mengaturnya ke "YA"? Aku ingin menjadi NO (interaksi pengguna disallow) .. Sebuah contoh sederhana adalah bahwa saya mengatur interaksi pengguna dari baris pertama ( if [indexPath row] == 0) ke NOdalam tableView:cellForRowAtIndexPath:setelah dequeueing sel. Ini biasanya berfungsi OK pada awalnya. Kemudian setelah beberapa panggilan reloadData, tiba-tiba baris kelima tidak diijinkan interaksi, lalu baris keempat .. Saya tidak tahu kapan itu akan terjadi. Semuanya terlihat acak.
Philip007

6
@ Philip007 Jika Anda menggunakan kembali sel-sel, Anda akan perlu untuk me-reset ke "YES" untuk sel Anda DO ingin menjadi interaktif. Kalau tidak, jika sel "TIDAK" digunakan kembali dalam baris yang Anda inginkan untuk menjadi interaktif, itu akan tetap dinonaktifkan. yaitu:if [indexPath row] == 0) { set to NO } else { set to YES }
JosephH

5

Anda bisa menggunakan tableView:willDisplayCellmetode ini untuk melakukan semua jenis penyesuaian ke tableViewCell.

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
     [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
     [cell setUserInteractionEnabled:NO];

     if (indexPath.section == 1 && indexPath.row == 0)
     {
         [cell setSelectionStyle:UITableViewCellSelectionStyleGray];
         [cell setUserInteractionEnabled:YES];
     }
} 

Dalam kode di atas ini, pengguna hanya dapat memilih baris pertama di bagian kedua dari tableView. Selebihnya semua baris tidak dapat dipilih. Terima kasih!


5

Untuk cepat:

cell.selectionStyle = .None
cell.userInteractionEnabled = false

5

Solusi saya berdasarkan model data:

func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
    let rowDetails = viewModel.rowDetails(forIndexPath: indexPath)
    return rowDetails.enabled ? indexPath : nil
}

func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool {
    let rowDetails = viewModel.rowDetails(forIndexPath: indexPath)
    return rowDetails.enabled
}

5

Untuk swift 4.0 Ini akan membantu. Ini akan menonaktifkan Cell dalam metode didSelectRowAtIndexPath tetapi tetap membuat subview dapat diklik.

func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
         if (indexPath.row == clickableIndex ) { 
            return indexPath
         }else{
            return nil
        }
    }

Atau singkatnya return indexPath.row == clickableIndex ? indexPath : nil:, jaga kode Anda sedikit lebih bersih ;-)
Tandai

1

Gunakan ini untuk membuat sel tampak seperti dinonaktifkan dan tidak dapat dipilih:

cell.selectionStyle = UITableViewCellSelectionStyleNone;

Penting: perhatikan bahwa ini hanya properti penataan, dan tidak benar-benar menonaktifkan sel. Untuk melakukan itu, Anda harus memeriksa implementasi delegasi selectionStyleAnda didSelectRowAtIndexPath::

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    if(cell.selectionStyle == UITableViewCellSelectionStyleNone) {
        return;
    }

    // do your cell selection handling here
}

1

Saya suka jawaban Brian Chapados di atas. Namun, ini berarti Anda mungkin memiliki duplikat logika di kedua cellForRowAtIndexPath dan kemudian di willSelectRowAtIndexPath yang dapat dengan mudah keluar dari sinkronisasi. Alih-alih menduplikasi logika, cukup periksa selectionStyle:

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    if (cell.selectionStyle == UITableViewCellSelectionStyleNone)
        return nil;

    else
        return indexPath;
}

1

Saya menemukan ini berguna karena berfungsi dengan tabel statis dan dinamis. Saya hanya mengatur indikator pengungkapan pada sel-sel yang saya ingin izinkan seleksi.

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    if (cell.accessoryType != UITableViewCellAccessoryDisclosureIndicator) {
        return nil;
    }
    return indexPath;
}

1

pada Xcode 7 tanpa coding Anda cukup melakukan hal berikut:

Pada tampilan kerangka, pilih Tampilan Tabel Sel. (Sel bersarang di bawah Scene Pengontrol Tampilan Tabel> Pengontrol Tampilan Tabel> Tampilan Tabel. Anda mungkin harus mengungkapkan objek tersebut untuk melihat sel tampilan tabel)

Di inspektur Atribut, temukan bidang berlabel Pilihan dan pilih Tidak Ada. atribute inspector Dengan opsi ini, sel tidak akan mendapatkan sorotan visual ketika pengguna mengetuknya.


0

SEDERHANA

Cukup gunakan cell.userInteractionEnabled = YES;ke sel jika dapat menavigasi dan cell.userInteractionEnabled = NO;sebaliknya


1
Ini juga mencegah interaksi dengan tampilan aksesori di dalam sel, yang mungkin bukan perilaku yang diinginkan.
Greg Brown

0

Terapkan metode yang tepat tableView:willSelectRowAtIndexPath: di sumber data untuk tabel Anda. Jika Anda ingin baris di jalur disorot, kembalikan indexPath yang diberikan. Jika tidak, kembalikan nihil.

Contoh dari aplikasi saya:

- (NSIndexPath *)tableView:(UITableView *)tableView
    willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    MySelectableObj* obj = [self objectAtPath:indexPath];
    if(obj==nil) return nil;
    return indexPath;
}

Yang menyenangkan tentang ini adalah bahwa shouldPerformSegueWithIdentifier:sender:tidak akan dipanggil jika metode di atas mengembalikan nol, meskipun saya ulangi tes di atas hanya untuk kelengkapan.



0

Saya setuju dengan jawaban Bryan

jika aku melakukan

cell.isUserInteractionEnabled = false 

maka subview dalam sel tidak akan berinteraksi dengan pengguna.

Di situs lain, pengaturan

cell.selectionStyle = .none

akan memicu metode didSelect meskipun tidak memperbarui warna pemilihan.

Menggunakan willSelectRowAt adalah cara saya memecahkan masalah saya. Contoh:

func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {

    if indexPath.section == 0{

        if indexPath.row == 0{
            return nil
        }

    }
    else if indexPath.section == 1{

        if indexPath.row == 0{
            return nil
        }

    }

    return indexPath

}

0

mulai dari tableView.allowsMultipleSelection = trueAnda harus membatalkan pilihan sel-sel bagian saat memilih:

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    if indexPath.section does not support multiple selection {
        // deselect the rest of cells
        tableView
            .indexPathsForSelectedRows?.compactMap { $0 }
            .filter { $0.section == indexPath.section && $0.row != indexPath.row }
            .forEach { tableView.deselectRow(at: $0, animated: true) }
    }
}

-1

untuk swift 3.0 Anda dapat menggunakan kode di bawah ini untuk menonaktifkan interaksi pengguna ke sel UITableView

 cell.isUserInteractionEnabled = false
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.