UITableView diatur ke sel statis. Apakah mungkin untuk menyembunyikan beberapa sel secara terprogram?

132

UITableView setel ke sel statis.

Apakah mungkin untuk menyembunyikan beberapa sel secara terprogram?

Shmidt
sumber

Jawaban:

48

Anda mencari solusi ini:

StaticDataTableViewController 2.0

https://github.com/xelvenone/StaticDataTableViewController

yang dapat menampilkan / menyembunyikan / memuat ulang sel statis apa pun dengan atau tanpa animasi!

[self cell:self.outletToMyStaticCell1 setHidden:hide]; 
[self cell:self.outletToMyStaticCell2 setHidden:hide]; 
[self reloadDataAnimated:YES];

Catatan untuk selalu menggunakan saja (reloadDataAnimated: YES / NO) (jangan panggil [self.tableView reloadData] secara langsung)

Ini tidak menggunakan solusi peretasan dengan menetapkan tinggi ke 0 dan memungkinkan Anda untuk menghidupkan perubahan dan menyembunyikan seluruh bagian

Peter Lapisu
sumber
6
Salah satu masalah dengan solusi itu adalah ia meninggalkan celah di mana sel-sel tersembunyi berada.
Jack
apa maksudmu kesenjangan? bisakah kamu menggambarkan situasinya dengan lebih baik, mungkin langsung di github? apakah Anda menjalankan sampel?
Peter Lapisu
1
Maksud saya jika Anda memiliki misalnya tiga bagian dan Anda menyembunyikan sel-sel dari bagian tengah ruang di mana bagian itu tetap. Saya tidak mencoba proyek sampel, tetapi saya memang mencoba kodenya. Saya akan mencoba sampelnya.
Jack
1
lihat contohnya, ada pembaruan yang lebih besar, mungkin Anda memiliki beberapa kode lama ... berfungsi sempurna untuk saya
Peter Lapisu
Saya mencoba sampel dan tampaknya bekerja di sana, satu-satunya hal yang saya lakukan berbeda adalah menggunakan IBOutletCollectiontetapi saya tidak melihat bagaimana itu akan membuat perbedaan. Saya hanya mengunduh kode kemarin jadi saya rasa ini bukan versi lama.
Jack
164

Untuk menyembunyikan sel statis di UITable:

  1. Tambahkan metode ini :

Di kelas delegasi kontroler UITableView Anda:

Tujuan-C:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell* cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];

    if(cell == self.cellYouWantToHide)
        return 0; //set the hidden cell's height to 0

    return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}

Cepat:

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    var cell = super.tableView(tableView, cellForRowAtIndexPath: indexPath)

    if cell == self.cellYouWantToHide {
        return 0
    }

    return super.tableView(tableView, heightForRowAtIndexPath: indexPath)
}

Metode ini akan dipanggil untuk setiap sel dalam UITable. Setelah ia memanggilnya untuk sel yang ingin Anda sembunyikan, kami mengatur ketinggiannya ke 0. Kami mengidentifikasi sel target dengan membuat outlet untuknya:

  1. Di perancang, buat saluran keluar untuk sel yang ingin Anda sembunyikan. Outlet untuk satu sel seperti itu disebut "cellYouWantToHide" di atas.
  2. Periksa "Tinjau Klip" di IB untuk sel yang ingin Anda sembunyikan. Sel-sel yang Anda sembunyikan harus memiliki ClipToBounds = YA. Kalau tidak, teks akan menumpuk di UITableView.
Justas
sumber
10
Solusi bagus Untuk menghindari ClipToBoundsmasalah ini, Anda juga dapat mengatur sel ke tersembunyi. Bagi saya ini tampak lebih bersih. ;-)
MonsieurDart
13
+1 untuk ClipToBounds = YA. Solusi Numeorus di utas lain telah melewatkannya.
Jeff
2
Ide yang hebat. Ini adalah solusi termudah yang saya temukan. Solusi lain memiliki kode di dua lokasi atau lebih. BTW, dalam IB, ClipToBounds terdaftar sebagai "Klip Subview".
VaporwareWolf
1
Hanya sedikit koreksi, gunakan self .cellYouWantToHide alih-alih .cellYouWantToHide ini .
Zoltan Vinkler
2
tanpa membuat objek sel, kita juga bisa menggunakan "index.row" untuk menyembunyikan "uitableviewcell"
g212gs
38

Cara terbaik adalah seperti yang dijelaskan dalam blog berikut ini http://ali-reynolds.com/2013/06/29/hide-cells-in-static-table-view/

Rancang tampilan tabel statis Anda seperti biasa di pembuat antarmuka - lengkap dengan semua sel yang berpotensi tersembunyi. Tetapi ada satu hal yang harus Anda lakukan untuk setiap sel potensial yang ingin Anda sembunyikan - periksa properti “Klip tayangan balik” sel, jika tidak, isi sel tidak hilang ketika Anda mencoba dan menyembunyikannya (dengan mengecilkan tingginya) - nanti lagi).

SO - Anda memiliki sakelar di sel dan sakelar itu seharusnya menyembunyikan dan menampilkan beberapa sel statis. Menghubungkannya ke IBAction dan di sana lakukan ini:

[self.tableView beginUpdates];
[self.tableView endUpdates];

Itu memberi Anda animasi yang bagus untuk sel yang muncul dan menghilang. Sekarang terapkan metode delegasi tampilan tabel berikut:

- (float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.section == 1 && indexPath.row == 1) { // This is the cell to hide - change as you need
    // Show or hide cell
        if (self.mySwitch.on) {
            return 44; // Show the cell - adjust the height as you need
        } else {
            return 0; // Hide the cell
        }
   }
   return 44;
}

Dan itu saja. Balik saklar dan selnya bersembunyi dan muncul kembali dengan animasi yang bagus dan halus.

Mohamed Saleh
sumber
Pembaruan: Anda juga perlu mengatur Label Sel menjadi Sembunyikan / Tampilkan dengan Anda Sembunyikan / Tampilkan Sel, jika tidak, Label akan membuat kekacauan.
Mohamed Saleh
1
Anda harus mencatat bahwa jika ada UIView dalam konten sel statis Anda memiliki kendala terhadap sel. Isi Anda mungkin mendapatkan kesalahan runtime jika kendala itu tidak valid untuk tinggi sel baru Anda.
Pedro Borges
1
Jawaban Terbaik. Terima kasih.
Eric Chen
1
Saya tahu trik ini bekerja dengan konten dinamis. Bekerja dengan sangat baik dengan statis juga. Begitu sederhana juga.
Semut
2
Ini benar-benar berfungsi, tetapi untuk menutupi titik yang hilang: jika baris yang akan disembunyikan / ditampilkan berisi pemilih tanggal, hanya melakukan [self.tableView beginUpdates]; [self.tableView endUpdates]; masih akan meninggalkan kesalahan saat menyembunyikannya. Untuk menghilangkan kesalahan, Anda harus memanggil [self.tableView reloadRowsAtIndexPaths: @ [indexPathOfTargetRow] denganRowAnimation: UITableViewRowAnimationNone]; Juga memperhatikan bahwa animasi baris entah bagaimana "dinonaktifkan" di sini.
Chris
34

Solusi saya menuju ke arah yang sama seperti Gareth, meskipun saya melakukan beberapa hal secara berbeda.

Ini dia:

1. Sembunyikan sel

Tidak ada cara untuk menyembunyikan sel secara langsung. UITableViewControlleradalah sumber data yang menyediakan sel statis, dan saat ini tidak ada cara untuk mengatakannya "tidak menyediakan sel x". Jadi kita harus menyediakan sumber data kita sendiri, yang didelegasikan kepada UITableViewControlleruntuk mendapatkan sel statis.

Paling mudah adalah dengan subkelas UITableViewController, dan menimpa semua metode yang perlu berperilaku berbeda saat menyembunyikan sel .

Dalam kasus paling sederhana (tabel satu bagian, semua sel memiliki ketinggian yang sama), ini akan seperti ini:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section    
{
    return [super tableView:tableView numberOfRowsInSection:section] - numberOfCellsHidden;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Recalculate indexPath based on hidden cells
    indexPath = [self offsetIndexPath:indexPath];

    return [super tableView:tableView cellForRowAtIndexPath:indexPath];
}

- (NSIndexPath*)offsetIndexPath:(NSIndexPath*)indexPath
{
    int offsetSection = indexPath.section; // Also offset section if you intend to hide whole sections
    int numberOfCellsHiddenAbove = ... // Calculate how many cells are hidden above the given indexPath.row
    int offsetRow = indexPath.row + numberOfCellsHiddenAbove;

    return [NSIndexPath indexPathForRow:offsetRow inSection:offsetSection];
}

Jika tabel Anda memiliki beberapa bagian, atau sel memiliki ketinggian yang berbeda, Anda perlu mengganti metode lainnya. Prinsip yang sama berlaku di sini: Anda perlu mengimbangi indexPath, bagian dan baris sebelum mendelegasikan ke super.

Juga perlu diingat bahwa parameter indexPath untuk metode seperti didSelectRowAtIndexPath:akan berbeda untuk sel yang sama, tergantung pada keadaan (yaitu jumlah sel yang disembunyikan). Jadi mungkin ide yang bagus untuk selalu mengimbangi parameter indexPath dan bekerja dengan nilai-nilai ini.

2. Buat animasi perubahan

Seperti yang sudah dinyatakan Gareth, Anda mendapatkan gangguan besar jika Anda menghidupkan perubahan menggunakan reloadSections:withRowAnimation: metode.

Saya menemukan bahwa jika Anda menelepon reloadData: segera setelah itu, animasinya jauh lebih baik (hanya gangguan kecil yang tersisa). Tabel ditampilkan dengan benar setelah animasi.

Jadi yang saya lakukan adalah:

- (void)changeState
{
     // Change state so cells are hidden/unhidden
     ...

    // Reload all sections
    NSIndexSet* reloadSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [self numberOfSectionsInTableView:tableView])];

    [tableView reloadSections:reloadSet withRowAnimation:UITableViewRowAnimationAutomatic];
    [tableView reloadData];
}
henning77
sumber
2
Diberkatilah Anda, Anda orang yang manis dan manis.
guptron
apakah Anda sudah menemukan solusi untuk gangguan animasi minor? bagi saya garis pemisah antara sel tidak akan bernyawa dengan benar dan id lebih suka tidak menggunakan animasi selain yang gliched. solusi hebat sekalipun!
Maximilian Körner
Masalah saya adalah bahwa dengan sel numberOfRowsInSection:- sel statis dipanggil hanya ketika tabel memuat pertama kali. Ketika saya memanggil [self.tableView reloadData] - numberOfRowsInSection:tidak pernah dipanggil lagi. Hanya cellForRowAtIndexPath:dipanggil. Apa yang saya lewatkan?
Roman
13
  1. Di perancang, buat saluran keluar untuk sel yang ingin Anda sembunyikan. Misalnya Anda ingin menyembunyikan 'cellOne', jadi di viewDidLoad () lakukan ini

cellOneOutlet.hidden = true

sekarang ganti metode di bawah ini, periksa status sel mana yang disembunyikan dan kembalikan tinggi 0 untuk sel-sel itu. Ini adalah salah satu dari banyak cara Anda dapat menyembunyikan sel apa pun di tabel statis dengan cepat.

override func tableView(tableView: UITableView, heightForRowAtIndexPathindexPath: NSIndexPath) -> CGFloat 
{

let tableViewCell = super.tableView(tableView,cellForRowAtIndexPath: indexPath)

        if tableViewCell.hidden == true
        {
            return 0
        }
        else{
             return super.tableView(tableView, heightForRowAtIndexPath: indexPath)
        }

}
Saleh Masum
sumber
Solusi terbaik sejauh ini!
derdida
tambahkan tableView.reloadData () setelah melakukan perubahan dan itu sempurna. Menghemat banyak upaya untuk mengubah solusi! terima kasih
Shayan C
1
Swift 4 tidak membiarkan saya menggunakan let tableViewCell = super.tableView(tableView,cellForRowAtIndexPath: indexPath). Saya menganggap itu diganti oleh let tableViewCell = tableView.cellForRow(at: indexPath as IndexPath).
Clifton Labrum
Karena saya menggunakan sel statis pada a UITableViewController, saya tidak punya UITableViewmetode delegasi. Untuk dapat menelepon heightForRow, apakah saya perlu memiliki metode lain juga?
Clifton Labrum
@CliftonLabrum tidak, Anda hanya dapat mengganti metode ini.
Alexander Ershov
11

Saya datang dengan alternatif yang sebenarnya menyembunyikan bagian dan tidak menghapusnya. Saya mencoba pendekatan @ henning77, tetapi saya terus mengalami masalah ketika saya mengubah jumlah bagian dari UITableView statis. Metode ini telah bekerja dengan sangat baik untuk saya, tetapi saya terutama berusaha menyembunyikan bagian daripada baris. Saya berhasil menghapus beberapa baris dengan cepat, tetapi jauh lebih berantakan, jadi saya sudah mencoba untuk mengelompokkan beberapa hal menjadi bagian yang perlu saya perlihatkan atau sembunyikan. Berikut adalah contoh bagaimana saya menyembunyikan bagian:

Pertama saya mendeklarasikan properti NSMutableArray

@property (nonatomic, strong) NSMutableArray *hiddenSections;

Di viewDidLoad (atau setelah Anda menanyakan data Anda), Anda bisa menambahkan bagian yang ingin Anda sembunyikan ke array.

- (void)viewDidLoad
{
    hiddenSections = [NSMutableArray new];

    if(some piece of data is empty){
        // Add index of section that should be hidden
        [self.hiddenSections addObject:[NSNumber numberWithInt:1]];
    }

    ... add as many sections to the array as needed

    [self.tableView reloadData];
}

Kemudian mengimplementasikan metode delegasi TableView berikut

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    if([self.hiddenSections containsObject:[NSNumber numberWithInt:section]]){
        return nil;
    }

    return [super tableView:tableView titleForHeaderInSection:section];
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if([self.hiddenSections containsObject:[NSNumber numberWithInt:indexPath.section]]){
        return 0;
    }

    return [super tableView:tableView heightForRowAtIndexPath:[self offsetIndexPath:indexPath]];
}

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if([self.hiddenSections containsObject:[NSNumber numberWithInt:indexPath.section]]){
        [cell setHidden:YES];
    }
}

Kemudian atur tinggi header dan footer ke 1 untuk bagian tersembunyi karena Anda tidak dapat mengatur tinggi ke 0. Ini menyebabkan ruang 2 pixel tambahan, tetapi kita bisa menebusnya dengan menyesuaikan ketinggian header yang terlihat berikutnya.

-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section 
{
    CGFloat height = [super tableView:tableView heightForHeaderInSection:section];

    if([self.hiddenSections containsObject:[NSNumber numberWithInt:section]]){
        height = 1; // Can't be zero
    }
    else if([self tableView:tableView titleForHeaderInSection:section] == nil){ // Only adjust if title is nil
        // Adjust height for previous hidden sections
        CGFloat adjust = 0;

        for(int i = (section - 1); i >= 0; i--){
            if([self.hiddenSections containsObject:[NSNumber numberWithInt:i]]){
                adjust = adjust + 2;
            }
            else {
                break;
            }
        }

        if(adjust > 0)
        {                
            if(height == -1){
                height = self.tableView.sectionHeaderHeight;
            }

            height = height - adjust;

            if(height < 1){
                height = 1;
            }
        }
    }

    return height;
}

-(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section 
{   
    if([self.hiddenSections containsObject:[NSNumber numberWithInt:section]]){
        return 1;
    }
    return [super tableView:tableView heightForFooterInSection:section];
}

Kemudian, jika Anda memiliki baris tertentu untuk disembunyikan Anda dapat menyesuaikan numberOfRowsInSection dan baris mana yang dikembalikan di cellForRowAtIndexPath. Dalam contoh ini di sini saya memiliki bagian yang memiliki tiga baris di mana tiga bisa kosong dan perlu dihapus.

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    NSInteger rows = [super tableView:tableView numberOfRowsInSection:section];

    if(self.organization != nil){
        if(section == 5){ // Contact
            if([self.organization objectForKey:@"Phone"] == [NSNull null]){     
                rows--;
            }

            if([self.organization objectForKey:@"Email"] == [NSNull null]){     
                rows--;
            }

            if([self.organization objectForKey:@"City"] == [NSNull null]){     
                rows--;
            }
        }
    }

    return rows;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{    
    return [super tableView:tableView cellForRowAtIndexPath:[self offsetIndexPath:indexPath]];
}

Gunakan offsetIndexPath ini untuk menghitung indexPath untuk baris tempat Anda menghapus baris secara kondisional. Tidak diperlukan jika Anda hanya menyembunyikan bagian

- (NSIndexPath *)offsetIndexPath:(NSIndexPath*)indexPath
{
    int row = indexPath.row;

    if(self.organization != nil){
        if(indexPath.section == 5){
            // Adjust row to return based on which rows before are hidden
            if(indexPath.row == 0 && [self.organization objectForKey:@"Phone"] == [NSNull null] && [self.organization objectForKey:@"Email"] != [NSNull null]){     
                row++;
            }
            else if(indexPath.row == 0 && [self.organization objectForKey:@"Phone"] == [NSNull null] && [self.organization objectForKey:@"Address"] != [NSNull null]){     
                row = row + 2;
            }
            else if(indexPath.row == 1 && [self.organization objectForKey:@"Phone"] != [NSNull null] && [self.organization objectForKey:@"Email"] == [NSNull null]){     
                row++;
            }
            else if(indexPath.row == 1 && [self.organization objectForKey:@"Phone"] == [NSNull null] && [self.organization objectForKey:@"Email"] != [NSNull null]){     
                row++;
            }
        }
    }

    NSIndexPath *offsetPath = [NSIndexPath indexPathForRow:row inSection:indexPath.section];

    return offsetPath;
}

Ada banyak metode untuk ditimpa, tetapi apa yang saya sukai dari pendekatan ini adalah bahwa itu dapat digunakan kembali. Atur array hiddenSections, tambahkan padanya, dan itu akan menyembunyikan bagian yang benar. Menyembunyikan barisnya sedikit lebih sulit, tapi mungkin. Kami tidak bisa hanya mengatur ketinggian baris yang ingin kami sembunyikan menjadi 0 jika kami menggunakan UITableView yang dikelompokkan karena batas tidak akan dapat digambarkan dengan benar.

Austin
sumber
1
Saya mungkin akan menggunakan NSMutableSetuntuk hiddenSectionsgantinya. Ini jauh lebih cepat karena Anda kebanyakan menguji keanggotaan.
pixelfreak
Jawaban yang bagus, Austin. Saya memilih jawaban itu dan akan menggunakan ini sebagai referensi untuk proyek saya di masa depan. pixelfreak juga membuat poin yang baik tentang menggunakan NSMutableSetuntuk hiddenSections, meskipun saya mengerti bahwa titik jawaban Anda lebih konseptual daripada rewel tentang jenis struktur data yang harus Anda gunakan.
BigSauce
10

Ternyata, Anda dapat menyembunyikan dan menampilkan sel dalam UITableView statis - dan dengan animasi. Dan itu tidak terlalu sulit untuk dicapai.

Proyek demo

Video proyek demo

Intinya:

  1. Use tableView:heightForRowAtIndexPath: untuk menentukan ketinggian sel secara dinamis berdasarkan pada beberapa keadaan.
  2. Ketika negara mengubah sel-sel bernyawa menunjukkan / bersembunyi dengan memanggil tableView.beginUpdates();tableView.endUpdates()
  3. Jangan panggil ke tableView.cellForRowAtIndexPath:dalam tableView:heightForRowAtIndexPath:. Gunakan indexPath yang di-cache untuk membedakan sel.
  4. Jangan sembunyikan sel. Tetapkan properti "Klip Subview" di Xcode sebagai gantinya.
  5. Gunakan sel Kustom (bukan Plain dll) untuk mendapatkan animasi persembunyian yang bagus. Juga, menangani Tata Letak Otomatis dengan benar untuk kasing ketika tinggi sel == 0.

Info lebih lanjut di blog saya (bahasa Rusia)

Sergey Skoblikov
sumber
1
Poin ini penting bagi saya: "Jangan sembunyikan sel. Setel properti" Klip Subview "di Xcode sebagai gantinya."
balkoth
8

Ya, itu pasti mungkin, meskipun saya sedang berjuang dengan masalah yang sama saat ini. Saya telah berhasil membuat sel-selnya disembunyikan dan semuanya berfungsi dengan baik, tetapi saat ini saya tidak dapat membuat benda itu hidup dengan rapi. Inilah yang saya temukan:

Saya menyembunyikan baris berdasarkan status sakelar HIDUP / MATI di baris pertama bagian pertama. Jika sakelar HIDUP ada 1 baris di bawahnya di bagian yang sama, jika tidak ada 2 baris yang berbeda.

Saya memiliki pemilih yang dipanggil saat sakelar diaktifkan, dan saya menetapkan variabel untuk menunjukkan keadaan saya saat ini. Lalu saya menelepon:

[[self tableView] reloadData];

Saya mengganti fungsi tableView: willDisplayCell: forRowAtIndexPath: dan jika sel seharusnya disembunyikan saya melakukan ini:

[cell setHidden:YES];

Itu menyembunyikan sel dan isinya, tetapi tidak menghilangkan ruang yang didudukinya.

Untuk menghapus spasi, timpa fungsi tableView: heightForRowAtIndexPath: dan kembalikan 0 untuk baris yang harus disembunyikan.

Anda juga perlu mengganti tableView: numberOfRowsInSection: dan mengembalikan jumlah baris di bagian itu. Anda harus melakukan sesuatu yang aneh di sini sehingga jika meja Anda adalah gaya yang dikelompokkan sudut-sudut bulat terjadi pada sel yang benar. Dalam tabel statis saya ada set lengkap sel untuk bagian tersebut, jadi ada sel pertama yang berisi opsi, lalu 1 sel untuk opsi status ON dan 2 sel lagi untuk opsi status MATI, total 4 sel. Ketika opsi ON, saya harus mengembalikan 4, ini termasuk opsi tersembunyi sehingga opsi terakhir yang ditampilkan memiliki kotak bulat. Ketika opsi mati, dua opsi terakhir tidak ditampilkan jadi saya kembali 2. Ini semua terasa kikuk. Maaf jika ini tidak terlalu jelas, sulit dijelaskan. Hanya untuk mengilustrasikan pengaturan, ini adalah konstruksi bagian tabel di IB:

  • Baris 0: Opsi dengan sakelar ON / OFF
  • Baris 1: Ditampilkan ketika opsi HIDUP
  • Baris 2: Ditampilkan ketika opsi MATI
  • Baris 3: Ditampilkan ketika opsi MATI

Jadi ketika opsi ON tabel melaporkan dua baris yaitu:

  • Baris 0: Opsi dengan sakelar ON / OFF
  • Baris 1: Ditampilkan ketika opsi HIDUP

Ketika opsi MATI, tabel melaporkan empat baris yaitu:

  • Baris 0: Opsi dengan sakelar ON / OFF
  • Baris 1: Ditampilkan ketika opsi HIDUP
  • Baris 2: Ditampilkan ketika opsi MATI
  • Baris 3: Ditampilkan ketika opsi MATI

Pendekatan ini tidak terasa benar karena beberapa alasan, sejauh yang saya dapatkan dengan eksperimen saya sejauh ini, jadi tolong beri tahu saya jika Anda menemukan cara yang lebih baik. Masalah yang saya amati sejauh ini adalah:

  • Rasanya salah mengatakan tabel jumlah baris berbeda dengan apa yang mungkin terkandung dalam data yang mendasarinya.

  • Sepertinya saya tidak bisa menghidupkan perubahan. Saya sudah mencoba menggunakan tableView: reloadSections: withRowAnimation: alih-alih reloadData dan hasilnya sepertinya tidak masuk akal, saya masih mencoba membuatnya berfungsi. Saat ini yang tampaknya terjadi adalah tableView tidak memperbarui baris yang benar sehingga satu tetap tersembunyi yang harus ditampilkan dan kekosongan ditinggalkan di bawah baris pertama. Saya pikir ini mungkin terkait dengan poin pertama tentang data yang mendasarinya.

Semoga seseorang akan dapat menyarankan metode alternatif atau mungkin cara memperluas dengan animasi, tetapi mungkin ini akan membantu Anda memulai. Saya minta maaf karena kurangnya hyperlink ke fungsi, saya masukkan tetapi mereka ditolak oleh filter spam karena saya adalah pengguna yang cukup baru.

Gareth Clarke
sumber
Saya cukup yakin Anda harus menelepon [[self tableView] reloadData];sekali lagi setelah menyembunyikan sel
Shmidt
Maaf untuk menghidupkan kembali ini, tetapi bagaimana Anda bisa subkelas UITableViewController dan menggunakannya dengan sel statis? Xcode tidak akan membiarkan saya.
Dany Joumaa
Nessup, Anda tidak perlu subkelas UITableView. Di storyboard pilih TableViewController Anda, lalu klik TableView. Sekarang Anda dapat memilih antara sel dinamis / statis.
Shmidt
1
Saya menemukan solusinya cara menghidupkan / menyembunyikan sel statis. Hanya panggilan return [super tableView:tableView cellForRowAtIndexPath:indexPath];di UITableViewControllersubclass untuk menciptakan sel statis. Jalur indeks diindeks statis - tidak dinamis ...
k06a
8

Sesuai jawaban Justas, tetapi untuk Swift 4:

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    let cell = super.tableView(tableView, cellForRowAt: indexPath)

    if cell == self.cellYouWantToHide {
        return 0
    }

    return super.tableView(tableView, heightForRowAt: indexPath)
}
Chris Herbst
sumber
1
Anda mungkin perlu tableView.reloadRows(at:, with:)memperbarui sel jika Anda mengubah ketinggian saat baris sudah terlihat.
Frost-Lee
5

Oke, setelah mencoba, saya punya jawaban yang tidak umum. Saya menggunakan variabel "isHidden" atau "hidden" untuk memeriksa apakah sel ini harus disembunyikan.

  1. buat IBOutlet ke pengontrol tampilan Anda. @IBOutlet weak var myCell: UITableViewCell!

  2. Perbarui myCellfungsi kustom Anda, misalnya Anda dapat menambahkannya di viewDidLoad:

override func viewDidLoad() { super.viewDidLoad() self.myCell.isHidden = true }

  1. dalam metode delegasi Anda:

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { let cell = super.tableView(tableView, cellForRowAt: indexPath) guard !cell.isHidden else { return 0 } return super.tableView(tableView, heightForRowAt: indexPath) }

Ini akan mengurangi logika Anda dalam metode delegasi, dan Anda hanya perlu fokus pada kebutuhan bisnis Anda.

BananZ
sumber
4

Jawaban di atas yang menyembunyikan / menampilkan sel, mengubah rowHeight, atau mengacaukan dengan batasan tata letak otomatis tidak berfungsi untuk saya karena masalah tata letak otomatis. Kode menjadi tidak tertahankan.

Untuk tabel statis sederhana, yang paling berhasil bagi saya adalah:

  1. Buat outlet untuk setiap sel di tabel statis
  2. Buat array hanya dengan outlet sel untuk ditampilkan
  3. Override cellForRowAtIndexPath untuk mengembalikan sel dari array
  4. Override numberOfRowsInSection untuk mengembalikan hitungan array
  5. Menerapkan metode untuk menentukan sel apa yang harus ada dalam array itu, dan memanggil metode itu kapan pun diperlukan, dan kemudian reloadData.

Ini adalah contoh dari pengontrol tampilan tabel saya:

@IBOutlet weak var titleCell: UITableViewCell!
@IBOutlet weak var nagCell: UITableViewCell!
@IBOutlet weak var categoryCell: UITableViewCell!

var cellsToShow: [UITableViewCell] = []

override func viewDidLoad() {
    super.viewDidLoad()
    determinCellsToShow()
}

func determinCellsToShow() {
    if detail!.duration.type != nil {
        cellsToShow = [titleCell, nagCell, categoryCell]
    }
    else {
        cellsToShow = [titleCell,  categoryCell]
    }
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    return cellsToShow[indexPath.row]
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return cellsToShow.count
}
David Barta
sumber
Ini bekerja dengan baik, bahkan 5 tahun kemudian! Terima kasih banyak.
Schrockwell
2020 dan ini adalah solusi terhebat untuk ini. Tidak perlu meretas.
mdonati
3

Metode Kompatibel iOS 11 & IB / Storyboard Sederhana

Untuk iOS 11, saya menemukan bahwa versi modifikasi dari jawaban Mohamed Saleh bekerja paling baik, dengan beberapa perbaikan berdasarkan dokumentasi Apple. Ia menjiwai dengan baik, menghindari peretasan yang jelek atau nilai yang di-hardcoded, dan menggunakan ketinggian baris yang telah ditetapkan dalam Interface Builder .

Konsep dasarnya adalah mengatur tinggi baris ke 0 untuk setiap baris tersembunyi. Kemudian gunakan tableView.performBatchUpdatesuntuk memicu animasi yang bekerja secara konsisten.

Atur ketinggian sel

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    if indexPath == indexPathOfHiddenCell {
        if cellIsHidden {
            return 0
        }
    }
    // Calling super will use the height set in your storyboard, avoiding hardcoded values
    return super.tableView(tableView, heightForRowAt: indexPath)
}

Anda akan ingin memastikan cellIsHiddendan indexPathOfHiddenCelldiatur sesuai dengan kasus penggunaan Anda. Untuk kode saya mereka adalah properti pada pengontrol tampilan tabel saya.

Beralih sel

Dalam metode apa pun yang mengontrol visibilitas (kemungkinan aksi tombol atau didSelectRow), alihkan keadaan cellIsHidden, di dalam performBatchUpdatesblok:

tableView.performBatchUpdates({
                // Use self to capture for block
                self.cellIsHidden = !self.cellIsHidden 
            }, completion: nil)

Apple merekomendasikan performBatchUpdateslebih dari beginUpdates/endUpdates kapan pun memungkinkan.

perampok
sumber
1

Saya menemukan solusi untuk menghidupkan sel bersembunyi di tabel statis.

// Class for wrapping Objective-C block
typedef BOOL (^HidableCellVisibilityFunctor)();
@interface BlockExecutor : NSObject
@property (strong,nonatomic) HidableCellVisibilityFunctor block;
+ (BlockExecutor*)executorWithBlock:(HidableCellVisibilityFunctor)block;
@end
@implementation BlockExecutor
@synthesize block = _block;
+ (BlockExecutor*)executorWithBlock:(HidableCellVisibilityFunctor)block
{
    BlockExecutor * executor = [[BlockExecutor alloc] init];
    executor.block = block;
    return executor;
}
@end

Hanya satu kamus tambahan yang dibutuhkan:

@interface MyTableViewController ()
@property (nonatomic) NSMutableDictionary * hidableCellsDict;
@property (weak, nonatomic) IBOutlet UISwitch * birthdaySwitch;
@end

Dan lihat implementasi MyTableViewController. Kami membutuhkan dua metode untuk mengonversi indexPath antara indeks yang terlihat dan tidak terlihat ...

- (NSIndexPath*)recoverIndexPath:(NSIndexPath *)indexPath
{
    int rowDelta = 0;
    for (NSIndexPath * ip in [[self.hidableCellsDict allKeys] sortedArrayUsingSelector:@selector(compare:)])
    {
        BlockExecutor * executor = [self.hidableCellsDict objectForKey:ip];
        if (ip.section == indexPath.section
            && ip.row <= indexPath.row + rowDelta
            && !executor.block())
        {
            rowDelta++;
        }
    }
    return [NSIndexPath indexPathForRow:indexPath.row+rowDelta inSection:indexPath.section];
}

- (NSIndexPath*)mapToNewIndexPath:(NSIndexPath *)indexPath
{
    int rowDelta = 0;
    for (NSIndexPath * ip in [[self.hidableCellsDict allKeys] sortedArrayUsingSelector:@selector(compare:)])
    {
        BlockExecutor * executor = [self.hidableCellsDict objectForKey:ip];
        if (ip.section == indexPath.section
            && ip.row < indexPath.row - rowDelta
            && !executor.block())
        {
            rowDelta++;
        }
    }
    return [NSIndexPath indexPathForRow:indexPath.row-rowDelta inSection:indexPath.section];
}

Satu IBAction pada perubahan nilai UISwitch:

- (IBAction)birthdaySwitchChanged:(id)sender
{
    NSIndexPath * indexPath = [self mapToNewIndexPath:[NSIndexPath indexPathForRow:1 inSection:1]];
    if (self.birthdaySwitch.on)
        [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
    else
        [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}

Beberapa metode UITableViewDataSource dan UITableViewDelegate:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    int numberOfRows = [super tableView:tableView numberOfRowsInSection:section];
    for (NSIndexPath * indexPath in [self.hidableCellsDict allKeys])
        if (indexPath.section == section)
        {
            BlockExecutor * executor = [self.hidableCellsDict objectForKey:indexPath];
            numberOfRows -= (executor.block()?0:1);
        }
    return numberOfRows;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    indexPath = [self recoverIndexPath:indexPath];
    return [super tableView:tableView cellForRowAtIndexPath:indexPath];
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    indexPath = [self recoverIndexPath:indexPath];
    return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    // initializing dictionary
    self.hidableCellsDict = [NSMutableDictionary dictionary];
    [self.hidableCellsDict setObject:[BlockExecutor executorWithBlock:^(){return self.birthdaySwitch.on;}] forKey:[NSIndexPath indexPathForRow:1 inSection:1]];
}

- (void)viewDidUnload
{
    [self setBirthdaySwitch:nil];
    [super viewDidUnload];
}

@end
k06a
sumber
1

Jawab dengan cepat :

Tambahkan metode berikut di TableViewController Anda:

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return indexPathOfCellYouWantToHide == indexPath ? 0 : super.tableView(tableView, heightForRowAtIndexPath: indexPath)
}

jika tableView mencoba menggambar sel yang ingin Anda sembunyikan, maka ia tidak akan menampilkannya karena tingginya akan diatur ke 0pt berkat metode di atas, semua yang lain tetap tidak berubah.

Harap dicatat bahwa indexPathOfCellYouWantToHidedapat diubah kapan saja :)

Federico Zanetello
sumber
1

Di> Swift 2.2, saya telah menggabungkan beberapa jawaban di sini.

Buat saluran keluar dari storyboard untuk menautkan ke staticCell Anda.

@IBOutlet weak var updateStaticCell: UITableViewCell!

override func viewDidLoad() {
    ...
    updateStaticCell.hidden = true
}

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    if indexPath.row == 0 {
        return 0
    } else {
        return super.tableView(tableView, heightForRowAtIndexPath: indexPath)
    }
}

Saya ingin menyembunyikan sel pertama saya sehingga saya mengatur ketinggian ke 0 seperti dijelaskan di atas.

CodeOverRide
sumber
1

Swift 4:

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    var height = super.tableView(tableView, heightForRowAt: indexPath)
    if (indexPath.row == HIDDENROW) {
        height = 0.0
    }
    return height
}
pizzamonster
sumber
0

Untuk skenario termudah ketika Anda menyembunyikan sel di bagian paling bawah tampilan tabel, Anda bisa menyesuaikan contentInset tableView setelah Anda menyembunyikan sel:

- (void)adjustBottomInsetForHiddenSections:(NSInteger)numberOfHiddenSections
{
    CGFloat bottomInset = numberOfHiddenSections * 44.0; // or any other 'magic number
    self.tableView.contentInset = UIEdgeInsetsMake(self.tableView.contentInset.top, self.tableView.contentInset.left, -bottomInset, self.tableView.contentInset.right);
}
Vladimir Shutyuk
sumber
0

Ini adalah cara baru untuk melakukan ini menggunakan https://github.com/k06a/ABStaticTableViewController

NSIndexPath *ip = [NSIndexPath indexPathForRow:1 section:1];
[self deleteRowsAtIndexPaths:@[ip] withRowAnimation:UITableViewRowAnimationFade]
k06a
sumber
0

Solusi dari k06a ( https://github.com/k06a/ABStaticTableViewController ) lebih baik karena menyembunyikan seluruh bagian termasuk header dan footer sel, di mana solusi ini ( https://github.com/peterpaulis/StaticDataTableViewController ) menyembunyikan semuanya kecuali footer.

EDIT

Saya baru saja menemukan solusi jika Anda ingin menyembunyikan catatan kaki StaticDataTableViewController. Ini yang perlu Anda salin dalam file StaticTableViewController.m:

- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
    if ([tableView.dataSource tableView:tableView numberOfRowsInSection:section] == 0) {
        return nil;
    } else {
        return [super tableView:tableView titleForFooterInSection:section];
    }
}

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {

    CGFloat height = [super tableView:tableView heightForFooterInSection:section];

    if (self.originalTable == nil) {
        return height;
    }

    if (!self.hideSectionsWithHiddenRows) {
        return height;
    }

    OriginalSection * os = self.originalTable.sections[section];
    if ([os numberOfVissibleRows] == 0) {
       //return 0;
        return CGFLOAT_MIN;
    } else {
        return height;
    }

    //return 0;
    return CGFLOAT_MIN;
}
pawel221
sumber
0

Tentunya kamu bisa. Pertama, kembalilah ke tableView Anda jumlah sel yang ingin Anda tampilkan lalu panggil superuntuk mencapai sel tertentu dari storyboard Anda dan kembalikan untuk tableView:

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return self.mode.numberOfCells()
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = super.tableView(tableView, cellForRowAtIndexPath: self.mode.indexPathForIndexPath(indexPath))

    return cell
}

Jika sel Anda memiliki hieght yang berbeda, kembalikan juga:

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return super.tableView(tableView, heightForRowAtIndexPath: self.mode.indexPathForIndexPath(indexPath))
}
Petr Syrov
sumber
0

Selain solusi @Saleh Masum:

Jika Anda mendapatkan kesalahan tata letak otomatis , Anda bisa menghapus batasan daritableViewCell.contentView

Swift 3:

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    let tableViewCell = super.tableView(tableView, cellForRowAt: indexPath)

    if tableViewCell.isHidden == true
    {
        tableViewCell.contentView.removeConstraints(tableViewCell.contentView.constraints)
        return 0
    }
    else{
        return super.tableView(tableView, heightForRowAt: indexPath)
    }

}

Solusi ini tergantung pada aliran aplikasi Anda . Jika Anda ingin menampilkan / menyembunyikan sel dalam instance controller tampilan yang sama, ini mungkin bukan pilihan terbaik, karena menghilangkan kendala .

Luca
sumber
0

Saya mendapatkan cara yang lebih baik untuk menyembunyikan sel statis dan bahkan bagian secara dinamis tanpa ada peretasan.

Mengatur tinggi baris ke 0 dapat menyembunyikan baris, tetapi itu tidak berfungsi jika Anda ingin menyembunyikan seluruh bagian yang akan menampung beberapa spasi bahkan Anda menyembunyikan semua baris.

Pendekatan saya adalah untuk membangun bagian array sel statis. Maka isi tampilan tabel akan didorong oleh array bagian.

Berikut ini beberapa contoh kode:

var tableSections = [[UITableViewCell]]()

private func configTableSections() {
    // seciton A
    tableSections.append([self.cell1InSectionA, self.cell2InSectionA])

    // section B
    if shouldShowSectionB {
        tableSections.append([self.cell1InSectionB, self.cell2InSectionB])
    }

    // section C
    if shouldShowCell1InSectionC {
        tableSections.append([self.cell1InSectionC, self.cell2InSectionC, self.cell3InSectionC])
    } else {
        tableSections.append([self.cell2InSectionC, self.cell3InSectionC])
    }
}

func numberOfSections(in tableView: UITableView) -> Int {
    return tableSections.count
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return tableSections[section].count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    return tableSections[indexPath.section][indexPath.row]
}

Dengan cara ini, Anda dapat menyatukan semua kode konfigurasi tanpa harus menulis kode jahat untuk menghitung jumlah baris dan bagian. Dan tentu saja tidak0 ketinggian lagi.

Kode ini juga sangat mudah dipelihara. Misalnya, jika Anda ingin menambah / menghapus lebih banyak sel atau bagian.

Demikian pula, Anda dapat membuat larik judul tajuk bagian dan larik judul tajuk bagian untuk mengonfigurasi judul bagian Anda secara dinamis.

Simon Wang
sumber