UITableView statik hücrelere ayarlandı. Bazı hücreleri programlı olarak gizlemek mümkün mü?


132

UITableView statik hücrelere ayarlanır.

Bazı hücreleri programlı olarak gizlemek mümkün mü?

Yanıtlar:


48

Bu çözümü arıyorsunuz:

StaticDataTableViewController 2.0

https://github.com/xelvenone/StaticDataTableViewController

Bu, herhangi bir statik hücreyi animasyonlu veya animasyonsuz gösterebilir / gizleyebilir / yeniden yükleyebilir!

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

Her zaman yalnızca kullanılmasını unutmayın (reloadDataAnimated: YES / NO) ([self.tableView reloadData] öğesini doğrudan çağırmayın)

Bu, yüksekliği 0 olarak ayarlayarak hacky çözümünü kullanmaz ve değişikliği canlandırmanıza ve tüm bölümleri gizlemenize olanak tanır


6
Bu çözümle ilgili bir sorun, gizli hücrelerin olduğu yerde boşluk bırakmasıdır.
Jack 13

boşlukları nasıl kastediyorsun? durumu daha iyi tanımlayabilir misin, belki doğrudan github'da? örneği çalıştırdın mı?
Peter Lapisu

1
Demek istediğim, örneğin üç bölümünüz varsa ve hücreleri orta bölümden gizlerseniz, o bölümün kaldığı boşluktur. Örnek projeyi denemedim ama kodu denedim. Örneği deneyeceğim.
Jack

1
örneğe göz
atın

Örneği denedim ve orada işe yarıyor gibi görünüyor, farklı yaptığım tek şey a kullanmak IBOutletCollectionama bunun nasıl bir fark yaratacağını anlamıyorum. Kodu daha dün indirdim, bu yüzden eski bir versiyon olduğunu düşünmüyorum.
Jack

164

Statik hücreleri UITable'da gizlemek için:

  1. Bu yöntemi ekleyin :

UITableView denetleyici temsilci sınıfınızda:

Objective-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];
}

Swift:

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

Bu yöntem, UITable'daki her hücre için çağrılacaktır. Gizlemek istediğiniz hücreyi çağırdığında, yüksekliğini 0 olarak ayarlıyoruz. Hedef hücreyi onun için bir çıkış oluşturarak belirliyoruz:

  1. Tasarımcıda, gizlemek istediğiniz hücre (ler) için bir çıkış oluşturun. Böyle bir hücrenin çıkışına yukarıda "cellYouWantToHide" adı verilmiştir.
  2. Gizlemek istediğiniz hücreler için IB'deki "Klip Alt Görünümlerini" kontrol edin. Sakladığınız hücrelerde ClipToBounds = YES olmalıdır. Aksi takdirde metin UITableView'da birikecektir.

10
Güzel çözüm. Sorunu önlemek için ClipToBoundshücreyi gizli olarak da ayarlayabilirsiniz. Bu bana daha temiz görünebilir. ;-)
MonsieurDart

13
ClipToBounds için +1 = EVET. Diğer konulardaki Numeorus çözümleri bunu kaçırdı.
Jeff

2
İyi fikir. Bulduğum en kolay çözüm bu. Diğer çözümlerin iki veya daha fazla konumda kodu vardı. BTW, IB'de ClipToBounds, "Klip Alt Görünümleri" olarak listelenir.
VaporwareWolf

1
Küçük bir düzeltme, bu .cellYouWantToHide yerine self .cellYouWantToHide kullanın .
Zoltan Vinkler

2
hücre nesnesi oluşturmadan, "uitableviewcell" i gizlemek için "index.row" u da kullanabiliriz
g212gs

38

En iyi yol, aşağıdaki blogda açıklandığı gibidir: http://ali-reynolds.com/2013/06/29/hide-cells-in-static-table-view/

Arayüz oluşturucuda statik tablo görünümünüzü normal şekilde tasarlayın - potansiyel olarak tüm gizli hücrelerle tamamlayın. Ancak, gizlemek istediğiniz her potansiyel hücre için yapmanız gereken bir şey var - hücrenin "Alt görünümleri kırp" özelliğini kontrol edin, aksi takdirde hücrenin içeriği, onu gizlemeye çalıştığınızda kaybolmaz (yüksekliğini küçülterek - daha sonra).

SO - hücrede bir anahtarınız var ve anahtarın bazı statik hücreleri gizlemesi ve göstermesi gerekiyor. Bir IBAction'a bağlayın ve orada şunu yapın:

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

Bu, görünen ve kaybolan hücreler için size güzel animasyonlar verir. Şimdi aşağıdaki tablo görünümü temsilci yöntemini uygulayın:

- (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;
}

Ve bu kadar. Düğmeyi çevirdiğinizde hücre gizlenir ve hoş, pürüzsüz bir animasyonla yeniden görünür.


Güncelleme: Ayrıca Hücre Etiketini Hücre Gizle / Göster ile birlikte Gizle / Göster olarak ayarlamanız gerekir, aksi takdirde Etiketler karışıklık yaratır.
Mohamed Saleh

1
Statik hücrenizin içeriğindeki herhangi bir UIView, cell.content ile ilgili herhangi bir kısıtlamaya sahipse, bu kısıtlamalar yeni hücre yüksekliğiniz için geçersiz hale gelirse bir çalışma zamanı hatası alabileceğinizi unutmayın.
Pedro Borges

1
En iyi cevap. Teşekkürler.
Eric Chen

1
Bu numaranın dinamik içerikle çalıştığını biliyordum. Statik ile de oldukça iyi çalışıyor. Çok da basit.
Karıncalar

2
Bu gerçekten işe yarıyor, ancak eksik bir noktayı kapatmak için: gizlenecek / gösterilecek satır bir tarih seçici içeriyorsa, yalnızca [self.tableView beginUpdates] yapıyor; [self.tableView endUpdates]; gizlerken de bir aksaklık bırakacaktır. Aksaklığı gidermek için, [self.tableView reloadRowsAtIndexPaths: @ [indexPathOfTargetRow] withRowAnimation: UITableViewRowAnimationNone] 'u çağırmalısınız; Ayrıca burada satır animasyonunun bir şekilde "devre dışı" olduğunu fark etmek için.
Chris

34

Bazı şeyleri farklı yapsam da çözümüm Gareth ile benzer bir yöne gidiyor.

İşte:

1. Hücreleri gizleyin

Hücreleri doğrudan saklamanın bir yolu yoktur. UITableViewControllerstatik hücreleri sağlayan veri kaynağıdır ve şu anda "x hücresini sağlamayın" demenin bir yolu yoktur. Bu nedenle UITableViewController, statik hücreleri almak için kendi veri kaynağımızı sağlamalıyız .

En kolayı, hücreleri gizlerken farklı davranması gereken tüm yöntemleri alt sınıfa ayırmak UITableViewControllerve geçersiz kılmaktır .

En basit durumda (tek bölüm tablosu, tüm hücreler aynı yüksekliğe sahiptir), bu şöyle olur:

- (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];
}

Tablonuzda birden çok bölüm varsa veya hücrelerin farklı yükseklikleri varsa, daha fazla yöntemi geçersiz kılmanız gerekir. Aynı ilke burada da geçerlidir: super'e devretmeden önce indexPath, bölüm ve satırı kaydırmanız gerekir.

Ayrıca, aşağıdaki gibi yöntemler için indexPath parametresinin didSelectRowAtIndexPath: duruma (yani, gizli hücre sayısına) bağlı olarak aynı hücre için farklı olacağını . Bu nedenle, herhangi bir indexPath parametresini daima kaydırmak ve bu değerlerle çalışmak muhtemelen iyi bir fikirdir.

2. Değişikliği canlandırın

Gareth'in daha önce de belirttiği gibi, değişiklikleri kullanarak büyük hatalar yaşarsınız. reloadSections:withRowAnimation: yöntemi .

Eğer ararsan reloadData:Hemen sonra , animasyonun çok daha iyi (sadece küçük aksaklıklar kaldı). Tablo, animasyondan sonra doğru bir şekilde görüntülenir.

Yani yaptığım şey:

- (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];
}

2
Tanrı seni, tatlı tatlı insan.
guptron

küçük animasyon hataları için bir çözüm buldunuz mu? benim için hücreler arasındaki ayırıcı çizgiler doğru şekilde hareket etmeyecek ve id, parlatılmış birinden daha fazla animasyon kullanmayacak. Yine de harika bir çözüm!
Maximilian Körner

Benim sorunum statik hücrelerde numberOfRowsInSection: yalnızca tablo ilk kez yüklendiğinde çağrılır. [Self.tableView reloadData] 'yı çağırdığımda - bir numberOfRowsInSection:daha asla çağrılmaz. Sadece cellForRowAtIndexPath:denir. Neyi kaçırıyorum?
Roman

13
  1. Tasarımcıda, gizlemek istediğiniz hücre (ler) için bir çıkış oluşturun. Örneğin, 'cellOne'ı gizlemek istiyorsunuz, bu yüzden viewDidLoad ()' da bunu yapın

cellOneOutlet.hidden = true

şimdi aşağıdaki yöntemi geçersiz kılın, hangi hücre durumunun gizli olduğunu kontrol edin ve bu hücreler için yüksekliği 0 döndür. Bu, statik tableView içindeki herhangi bir hücreyi hızlı bir şekilde gizlemenin birçok yolundan biridir.

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

}

Şimdiye kadarki en iyi çözüm!
derdida

değişiklikleri yaptıktan sonra tableView.reloadData () ekleyin ve mükemmel. Çözümü değiştirmek için çok çaba sarf ettim! teşekkürler
Shayan C

1
Swift 4 kullanmama izin vermiyor let tableViewCell = super.tableView(tableView,cellForRowAtIndexPath: indexPath). İle değiştirildiğini varsayıyorum let tableViewCell = tableView.cellForRow(at: indexPath as IndexPath).
Clifton Labrum

A üzerinde statik hücreler kullandığım için UITableViewController, herhangi bir UITableViewtemsilci yöntemim yok. Aramasını sağlamak için heightForRowbaşka yöntemlere de ihtiyacım var mı?
Clifton Labrum

@CliftonLabrum hayır, yalnızca bu yöntemi geçersiz kılabilirsiniz.
Alexander Ershov

11

Bölümleri gerçekten gizleyen ve silmeyen bir alternatif buldum. @ Henning77'nin yaklaşımını denedim, ancak statik UITableView'ün bölüm sayısını değiştirdiğimde sorunlarla karşılaşmaya devam ettim. Bu yöntem benim için gerçekten iyi çalıştı, ancak öncelikle satırlar yerine bölümleri gizlemeye çalışıyorum. Bazı satırları anında başarıyla kaldırıyorum, ancak bu çok daha karmaşık, bu yüzden şeyleri göstermem veya gizlemem gereken bölümler halinde gruplandırmaya çalıştım. İşte bölümleri nasıl gizlediğime dair bir örnek:

İlk önce bir NSMutableArray özelliği bildiriyorum

@property (nonatomic, strong) NSMutableArray *hiddenSections;

ViewDidLoad'da (veya verilerinizi sorguladıktan sonra) diziye gizlemek istediğiniz bölümleri ekleyebilirsiniz.

- (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];
}

Ardından aşağıdaki TableView temsilci yöntemlerini uygulayın

- (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];
    }
}

Ardından, yüksekliği 0 olarak ayarlayamayacağınız için gizli bölümler için üstbilgi ve altbilgi yüksekliğini 1 olarak ayarlayın. Bu, ek 2 piksel boşluğuna neden olur, ancak bir sonraki görünür başlığın yüksekliğini ayarlayarak bunu telafi edebiliriz.

-(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];
}

Ardından, gizlenecek belirli satırlarınız varsa numberOfRowsInSection değerini ve cellForRowAtIndexPath içinde hangi satırların döndürüleceğini ayarlayabilirsiniz. Buradaki örnekte, herhangi üçünün boş olabileceği ve kaldırılması gereken üç satırı olan bir bölümüm var.

- (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]];
}

Satırları koşullu olarak kaldırdığınız satırlar için indexPath'i hesaplamak için bu offsetIndexPath'i kullanın. Yalnızca bölümleri gizliyorsanız gerekli değildir

- (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;
}

Geçersiz kılmak için birçok yöntem var, ancak bu yaklaşımla ilgili sevdiğim şey, yeniden kullanılabilir olmasıdır. HiddenSections dizisini kurun, ona ekleyin ve doğru bölümleri gizleyecektir. Satırları gizlemek biraz daha zor ama mümkün. Gruplandırılmış bir UITableView kullanıyorsak, gizlemek istediğimiz satırların yüksekliğini 0 olarak ayarlayamayız çünkü sınırlar doğru çizilmez.


1
Muhtemelen kullanacağı NSMutableSetiçin hiddenSectionsyerine. Çoğunlukla üyelik için test yaptığınız için çok daha hızlı.
pixelfreak

Güzel cevap, Austin. Bu cevabı oyladım ve bunu ileride projelerim için referans olarak kullanacağım. pixelfreak , NSMutableSetfor kullanımı hakkında da iyi bir noktaya işaret ediyor hiddenSections, ancak cevabınızın amacının hangi tür veri yapısını kullanmanız gerektiği konusunda çok seçici olmaktan çok kavramsal olduğunu anlıyorum.
BigSauce

10

Hücreleri statik bir UITableView'da ve animasyonla gizleyebilir ve gösterebilirsiniz. Ve başarması o kadar da zor değil.

Demo projesi

Demo proje videosu

Ana fikir:

  1. Use tableView:heightForRowAtIndexPath: bazı durumlara göre hücre yüksekliklerini dinamik olarak belirlemek için.
  2. Durum değiştiğinde, arama yaparak hücrelere animasyon uygulayın / gizleyin tableView.beginUpdates();tableView.endUpdates()
  3. Deme tableView.cellForRowAtIndexPath:içeridetableView:heightForRowAtIndexPath: . Hücreleri farklılaştırmak için önbelleğe alınmış indexPaths kullanın.
  4. Hücreleri saklamayın. Bunun yerine Xcode'da "Klip Alt Görünümleri" özelliğini ayarlayın.
  5. Güzel bir gizleme animasyonu elde etmek için Özel hücreler (Düz değil vb.) Kullanın. Ayrıca, hücre yüksekliği == 0 olduğunda Otomatik Düzen'i doğru şekilde kullanın.

Blogumda daha fazla bilgi (Rusça)


1
Bu nokta benim için önemliydi: "Hücreleri gizlemeyin. Bunun yerine Xcode'da" Klip Alt Görünümleri "özelliğini ayarlayın."
balkoth

8

Evet, şu anda aynı sorunla mücadele etmeme rağmen kesinlikle mümkün. Hücrelerin saklanmasını sağladım ve her şey yolunda gidiyor, ancak şu anda bu şeyi düzgün bir şekilde canlandıramıyorum. İşte bulduğum şey:

İlk bölümün ilk satırındaki AÇIK / KAPALI anahtarının durumuna göre satırları gizliyorum. Switch ON ise aynı bölümde 1 sıra altta yoksa 2 farklı sıra vardır.

Anahtar değiştirildiğinde çağrılan bir seçici var ve hangi durumda olduğumu belirtmek için bir değişken ayarlıyorum. Sonra şunu ararım:

[[self tableView] reloadData];

TableView: willDisplayCell: forRowAtIndexPath: işlevini geçersiz kılıyorum ve hücrenin gizli olması gerekiyorsa bunu yapıyorum:

[cell setHidden:YES];

Bu, hücreyi ve içeriğini gizler, ancak kapladığı alanı kaldırmaz.

Alanı kaldırmak için tableView: heightForRowAtIndexPath öğesini geçersiz kılın: işlevini ve gizlenmesi gereken satırlar için 0 .

Ayrıca tableView: numberOfRowsInSection: öğesini geçersiz kılmanız ve bu bölümdeki satır sayısını döndürmeniz gerekir. Burada garip bir şey yapmalısınız, böylece masanız gruplanmış bir stilde ise yuvarlak köşeler doğru hücrelerde meydana gelir. Statik tablomda, bölüm için tam hücre kümesi var, bu nedenle seçeneği içeren ilk hücre var, ardından AÇIK durum seçenekleri için 1 hücre ve KAPALI durum seçenekleri için 2 hücre daha, toplam 4 hücre. Seçenek AÇIK olduğunda, 4 döndürmeliyim, bu gizli seçeneği içerir, böylece görüntülenen son seçenek yuvarlak bir kutuya sahip olur. Seçenek kapalıyken, son iki seçenek görüntülenmiyor, bu yüzden 2'ye dönüyorum. Tüm bunlar hantal geliyor. Üzgünüm, bu çok açık değilse, tarif etmesi zor. Sadece kurulumu göstermek için, IB'deki tablo bölümünün yapısı budur:

  • Satır 0: ON / OFF anahtarlı seçenek
  • Satır 1: Seçenek AÇIK olduğunda görüntülenir
  • Satır 2: Seçenek KAPALI olduğunda görüntülenir
  • Satır 3: Seçenek KAPALI olduğunda görüntülenir

Dolayısıyla, seçenek AÇIK olduğunda, tablo şu iki satırı rapor eder:

  • Satır 0: ON / OFF anahtarlı seçenek
  • Satır 1: Seçenek AÇIK olduğunda görüntülenir

Seçenek KAPALI olduğunda, tablo aşağıdaki dört satırı rapor eder:

  • Satır 0: ON / OFF anahtarlı seçenek
  • Satır 1: Seçenek AÇIK olduğunda görüntülenir
  • Satır 2: Seçenek KAPALI olduğunda görüntülenir
  • Satır 3: Seçenek KAPALI olduğunda görüntülenir

Bu yaklaşım birkaç nedenden ötürü doğru gelmiyor, şimdiye kadarki deneyime sahip olduğum kadarıyla, daha iyi bir yol bulursanız lütfen bana bildirin. Şimdiye kadar gözlemlediğim sorunlar:

  • Tabloya satır sayısının muhtemelen temel verilerde içerilenlerden farklı olduğunu söylemek yanlış geliyor.

  • Değişimi canlandıracak gibi görünmüyorum. TableView: reloadSections: withRowAnimation: reloadData yerine kullanmayı denedim ve sonuçlar mantıklı görünmüyor, hala bunu çalıştırmaya çalışıyorum. Şu anda, görünen şey, tableView doğru satırları güncellemiyor, bu nedenle görüntülenecek bir gizli kalır ve ilk satırın altında bir boşluk bırakılır. Bunun temeldeki verilerle ilgili ilk noktayla ilgili olabileceğini düşünüyorum.

Umarım birisi alternatif yöntemler önerebilir veya belki animasyonla nasıl genişletilebilir, ama belki bu size başlamanızı sağlar. İşlevlere köprüler olmamasından dolayı özür dilerim, onları ekledim ancak oldukça yeni bir kullanıcı olduğum için spam filtresi tarafından reddedildiler.


[[self tableView] reloadData];Hücreleri gizledikten sonra bir kez daha aramanız gerektiğine eminim
Shmidt

Bunu canlandırdığım için üzgünüm, ancak UITableViewController'ı nasıl alt sınıflara ayırıp onu statik hücrelerle kullanabildiniz? Xcode izin vermiyor.
Dany Joumaa

Nessup, UITableView alt sınıfına girmenize gerek yok. Film şeridinde TableViewController'ınızı seçin, ardından TableView'a tıklayın. Artık dinamik / statik hücreler arasında seçim yapabilirsiniz.
Shmidt

1
Statik hücrelerin nasıl gizleneceği / gösterileceği çözümünü buldum. Sadece çağrı return [super tableView:tableView cellForRowAtIndexPath:indexPath];içinde UITableViewControllerstatik hücrelerini oluşturmak için alt sınıf. Dizin yolları statik dizine
alınmış

8

Justas'ın cevabına göre, ancak Swift 4 için:

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

1
tableView.reloadRows(at:, with:)Satır zaten görünür durumdayken yüksekliği değiştirirseniz hücreleri güncellemeniz gerekebilir .
Frost-Lee

6

Tamam, biraz denedikten sonra, ortak olmayan bir cevabım var. Bu hücrenin gizlenmesi gerekip gerekmediğini kontrol etmek için "isHidden" veya "hidden" değişkenini kullanıyorum.

  1. görüntüleme denetleyicinize bir IBOutlet oluşturun. @IBOutlet weak var myCell: UITableViewCell!

  2. myCellÖzel işlevinizde güncelleyin , örneğin bunu viewDidLoad'a ekleyebilirsiniz:

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

  1. temsilci yönteminizde:

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

Bu, temsilci yöntemindeki mantığınızı azaltacaktır ve yalnızca iş gereksinimlerinize odaklanmanız gerekir.


4

Hücreleri gizleyen / gösteren, rowHeight'ı değiştiren veya Otomatik düzen kısıtlamalarıyla uğraşan yukarıdaki yanıtlar, Otomatik düzen sorunları nedeniyle benim için çalışmadı. Kod dayanılmaz hale geldi.

Basit bir statik tablo için benim için en iyi olan şey şuydu:

  1. Statik tablodaki her hücre için bir çıkış oluşturun
  2. Yalnızca gösterilecek hücre çıkışlarıyla bir dizi oluşturun
  3. Hücreyi diziden döndürmek için cellForRowAtIndexPath'i geçersiz kılın
  4. Dizi sayısını döndürmek için numberOfRowsInSection öğesini geçersiz kılın
  5. Bu dizide hangi hücrelerin olması gerektiğini belirlemek için bir yöntem uygulayın ve gerektiğinde bu yöntemi çağırın ve ardından reloadData.

İşte tablo görünümü denetleyicimden bir örnek:

@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
}

Bu, 5 yıl sonra bile harika çalıştı! Çok teşekkür ederim.
Schrockwell

2020 ve bu, bunun için en büyük çözüm. Kesmeye gerek yok.
mdonati

3

Basit iOS 11 ve IB / Storyboard Uyumlu Yöntem

İOS 11 için, Mohamed Saleh'in yanıtının değiştirilmiş bir sürümünün , Apple'ın belgelerine dayanan bazı iyileştirmelerle en iyi şekilde çalıştığını buldum . Güzel bir şekilde canlandırır, çirkin korsanlardan veya kodlanmış değerlerden kaçınır ve Interface Builder'da önceden ayarlanmış satır yüksekliklerini kullanır .

Temel kavram, herhangi bir gizli satır için satır yüksekliğini 0 olarak ayarlamaktır. Sonra kullantableView.performBatchUpdates tutarlı bir şekilde çalışan bir animasyonu tetiklemek için .

Hücre yüksekliklerini ayarlayın

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

Emin olmak isteyeceksiniz cellIsHiddenveindexPathOfHiddenCell kullanım durumunuza uygun şekilde ayarlanır. Kodum için bunlar tablo görünümü denetleyicimdeki özelliklerdir.

Hücreyi değiştirme

Görünürlüğü hangi yöntem kontrol didSelectRowederse etsin (muhtemelen bir düğme eylemi veya ), bir performBatchUpdatesblok içinde cellIsHidden durumunu değiştirin :

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

Apple,performBatchUpdatesbeginUpdatesendUpdates mümkün olduğunca fazla / her zaman önerir .


1

Hücreleri statik tabloda canlandırmak için bir çözüm buldum.

// 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

Yalnızca bir ek sözlük gerekli:

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

Ve MyTableViewController uygulamasına bakın. İndexPath'i görünür ve görünmez dizinler arasında dönüştürmek için iki yönteme ihtiyacımız var ...

- (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];
}

UISwitch değer değişiminde bir IBAction:

- (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];
}

Bazı UITableViewDataSource ve UITableViewDelegate yöntemleri:

- (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

1

Hızlı cevap :

TableViewController'ınıza aşağıdaki yöntemi ekleyin:

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

tableView gizlemek istediğiniz hücreyi çizmeye çalışırsa, yukarıdaki yöntem sayesinde yüksekliği 0pt olarak ayarlanacağından, diğer her şey değişmeden kalır.

Lütfen bunun indexPathOfCellYouWantToHideherhangi bir zamanda değiştirilebileceğini unutmayın :)


1

> Swift 2.2'de, burada birkaç cevabı birleştirdim.

StatikCell'inize bağlanmak için film şeridinden bir çıkış yapın.

@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)
    }
}

İlk hücremi gizlemek istiyorum, bu yüzden yukarıda açıklandığı gibi yüksekliği 0 olarak ayarlıyorum.


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
}

0

Tablo görünümünün en altındaki hücreleri gizlediğinizde en kolay senaryo için, hücreyi gizledikten sonra tableView'in contentInset değerini ayarlayabilirsiniz:

- (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);
}


0

K06a'dan ( https://github.com/k06a/ABStaticTableViewController ) çözüm daha iyidir çünkü bu çözümün ( https://github.com/peterpaulis/StaticDataTableViewController ) altbilgi dışındaki her şeyi gizlediği hücre üstbilgileri ve altbilgileri dahil tüm bölümü gizler.

DÜZENLE

Altbilgiyi gizlemek istiyorsanız bir çözüm buldum StaticDataTableViewController. StaticTableViewController.m dosyasında kopyalamanız gereken şey budur:

- (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;
}

0

Elbette yapabilirsin. İlk olarak, göstermek istediğiniz hücre sayısını görüntüleyin, ardından superfilm şeridinizden belirli bir hücreyi elde etmek için arayın ve tableView için geri döndürün:

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
}

Hücrelerinizin farklı yüksekliği varsa, onu da iade edin:

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

0

@ Saleh Masum çözümüne ek olarak:

Eğer alırsanız otomatik düzen hataları , sadece gelen kısıtlamaları kaldırabilirsiniztableViewCell.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)
    }

}

Bu çözüm, uygulamanızın akışına bağlıdır . Hücreyi aynı görünüm denetleyicisi örneğinde göstermek / gizlemek istiyorsanız, bu en iyi seçenek olmayabilir, çünkü kısıtlamaları ortadan kaldırır .


0

Statik hücreleri ve hatta bölümleri herhangi bir saldırı olmadan dinamik olarak gizlemenin daha iyi bir yolunu buldum.

Satır yüksekliğini 0 olarak ayarlamak bir satırı gizleyebilir, ancak tüm satırları gizleseniz bile bazı boşlukları tutacak bir bölümü gizlemek istiyorsanız bu işe yaramaz.

Benim yaklaşımım, statik hücrelerden oluşan bir bölüm dizisi oluşturmaktır. Daha sonra tablo görünümü içerikleri bölüm dizisi tarafından yönlendirilecektir.

İşte bazı örnek kodlar:

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]
}

Bu şekilde, satır ve bölüm sayısını hesaplamak için kötü kod yazmak zorunda kalmadan tüm konfigürasyon kodunuzu bir araya getirebilirsiniz. Ve tabii ki hayır0 yükseklik yok.

Bu kodun bakımı da çok kolaydır. Örneğin, daha fazla hücre veya bölüm eklemek / kaldırmak istiyorsanız.

Benzer şekilde, bölüm başlıklarınızı dinamik olarak yapılandırmak için bir bölüm başlığı başlık dizisi ve bölüm altbilgisi başlık dizisi oluşturabilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.