webentwicklung-frage-antwort-db.com.de

UITableView auf statische Zellen gesetzt. Kann man einige Zellen programmatisch ausblenden?

UITableView ist auf statische Zellen gesetzt. 

Kann man einige Zellen programmatisch ausblenden?

124
Shmidt

Sie suchen nach dieser Lösung:

StaticDataTableViewController 2.0

https://github.com/xelvenone/StaticDataTableViewController

die statische Zellen mit oder ohne Animation anzeigen/verbergen/laden kann!

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

Hinweis: Verwenden Sie immer nur (reloadDataAnimated: YES/NO) (Ruft [self.tableView reloadData] nicht direkt auf).

Die Hacky-Lösung wird nicht mit der Einstellung der Höhe auf 0 verwendet. Sie können die Änderung animieren und ganze Abschnitte ausblenden.

48
Peter Lapisu

So blenden Sie statische Zellen in UITable aus:

  1. Diese Methode hinzufügen :

In Ihrer UITableView-Controller-Delegatklasse:

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

Diese Methode wird für jede Zelle in der UITable aufgerufen. Sobald es für die Zelle aufgerufen wird, die Sie ausblenden möchten, legen wir die Höhe auf 0 fest.

  1. Erstellen Sie im Designer einen Auslass für die Zellen, die Sie ausblenden möchten. Der Ausgang für eine solche Zelle wird oben als "cellYouWantToHide" bezeichnet.
  2. Markieren Sie in der IB "Clip Subviews" für die Zellen, die Sie ausblenden möchten. Die Zellen, die Sie verstecken, müssen ClipToBounds = YES haben. Andernfalls wird der Text in der UITableView angehäuft.
159
Justas

Der beste Weg ist wie im folgenden Blog beschrieben http://ALi-reynolds.com/2013/06/29/hide-cells-in-static-table-view/

Entwerfen Sie Ihre statische Tabellenansicht wie üblich im Interface Builder – komplett mit allen potenziell verborgenen Zellen. Aber es gibt eine Sache, die Sie haben. Muss für jede potenzielle Zelle, die Sie verstecken möchten, tun - überprüfen Sie das Eigenschaft "Clip-Subviews" der Zelle, ansonsten der Inhalt von Zelle verschwindet nicht, wenn Sie versuchen, sie auszublenden (durch Verkleinern der Höhe - später).

SO - Sie haben einen Schalter in einer Zelle und der Schalter soll verbergen und zeigen einige statische Zellen. Schließen Sie es an eine IBAction an und tun Sie dort diese:

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

Das gibt Ihnen schöne Animationen für die erscheinenden Zellen und verschwinden Implementieren Sie nun die folgende Delegatmethode für die Tabellensicht:

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

Und das ist es. Klappen Sie den Schalter um, und die Zelle wird ausgeblendet und mit einem .__ angezeigt. Schöne, reibungslose Animation.

35
Mohamed Saleh

Meine Lösung geht in eine ähnliche Richtung wie Gareth, obwohl ich einige Dinge anders mache.

Hier geht:

1. Verstecke die Zellen

Es gibt keine Möglichkeit, die Zellen direkt auszublenden. UITableViewController ist die Datenquelle, die die statischen Zellen bereitstellt, und derzeit gibt es keine Möglichkeit, "keine Zelle x angeben" zu sagen . Daher müssen wir unsere eigene Datenquelle bereitstellen, die an UITableViewController delegiert Holen Sie sich die statischen Zellen.

Am einfachsten ist es, UITableViewController zu subklassen und alle Methoden zu überschreiben, die sich beim Ausblenden von Zellen unterschiedlich verhalten müssen.

Im einfachsten Fall (Einzelabschnitts-Tabelle haben alle Zellen die gleiche Höhe), würde dies folgendermaßen aussehen:

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

Wenn Ihre Tabelle mehrere Abschnitte hat oder die Zellen unterschiedliche Höhen haben, müssen Sie weitere Methoden überschreiben. Hier gilt das gleiche Prinzip: Sie müssen indexPath, section und row vor dem Delegieren an super versetzen.

Beachten Sie auch, dass der indexPath-Parameter für Methoden wie didSelectRowAtIndexPath: für dieselbe Zelle unterschiedlich ist, je nach Status (d. H. Die Anzahl der ausgeblendeten Zellen). Daher ist es wahrscheinlich eine gute Idee, jeden indexPath-Parameter immer zu versetzen und mit diesen Werten zu arbeiten.

2. Animation animieren

Wie Gareth bereits angedeutet hat, kommt es zu größeren Störungen, wenn Sie Änderungen mit der reloadSections:withRowAnimation:-Methode animieren.

Ich habe herausgefunden, dass, wenn Sie sofort reloadData: aufrufen, die Animation stark verbessert wird (nur noch kleinere Pannen). Die Tabelle wird nach der Animation korrekt angezeigt. 

Was ich also mache ist:

- (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];
}
34
henning77
  1. Erstellen Sie im Designer einen Auslass für die Zellen, die Sie ausblenden möchten. Sie möchten beispielsweise 'cellOne' ausblenden, so dass dies in viewDidLoad () der Fall ist 

cellOneOutlet.hidden = true 

jetzt überschreiben Sie die untenstehende Methode, prüfen Sie, welcher Zellenstatus ausgeblendet ist, und geben Sie die Höhe 0 für diese Zelle (n) zurück. Dies ist eine von vielen Möglichkeiten, um beliebige Zellen in statischen tableView in Swift auszublenden. 

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

}
13
Saleh Masum

Ich habe mir eine Alternative ausgedacht, die Abschnitte tatsächlich versteckt und nicht löscht. Ich habe @ henning77s Ansatz ausprobiert, stieß jedoch auf Probleme, als ich die Anzahl der Abschnitte der statischen UITableView änderte. Diese Methode hat sehr gut für mich funktioniert, aber ich versuche hauptsächlich, Abschnitte statt Zeilen zu verbergen. Ich entferne einige Zeilen erfolgreich, aber es ist viel chaotischer. Ich habe versucht, die Dinge in Abschnitten zu gruppieren, die ich anzeigen oder ausblenden muss. Hier ist ein Beispiel, wie ich Abschnitte verstecke:

Zuerst erkläre ich eine NSMutableArray-Eigenschaft

@property (nonatomic, strong) NSMutableArray *hiddenSections;

In viewDidLoad (oder nachdem Sie Ihre Daten abgefragt haben) können Sie Abschnitte hinzufügen, die Sie im Array ausblenden möchten.

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

Implementieren Sie anschließend die folgenden TableView-Delegatmethoden

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

Setzen Sie dann die Kopf- und Fußzeilenhöhe für ausgeblendete Abschnitte auf 1, da Sie die Höhe nicht auf 0 festlegen können. Dies verursacht einen zusätzlichen Abstand von 2 Pixeln. Wir können dies jedoch durch Anpassen der Höhe der nächsten sichtbaren Kopfzeile ausgleichen.

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

Wenn Sie über bestimmte Zeilen verfügen, die ausgeblendet werden sollen, können Sie numberOfRowsInSection anpassen und festlegen, welche Zeilen in cellForRowAtIndexPath zurückgegeben werden. In diesem Beispiel hier habe ich einen Abschnitt, der drei Zeilen hat, in denen drei leer sein könnten und entfernt werden müssen.

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

Verwenden Sie diesen offsetIndexPath, um den indexPath für Zeilen zu berechnen, in denen Sie Zeilen bedingt entfernen. Nicht erforderlich, wenn Sie nur Abschnitte ausblenden

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

Es gibt viele Methoden zum Überschreiben, aber ich mag an diesem Ansatz, dass er wiederverwendbar ist. Richten Sie das hiddenSections-Array ein, fügen Sie es hinzu, und die korrekten Abschnitte werden ausgeblendet. Das Ausblenden der Reihen ist etwas komplizierter, aber möglich. Wir können nicht einfach die Höhe der Zeilen, die wir ausblenden möchten, auf 0 setzen, wenn wir eine gruppierte UITableView verwenden, da die Rahmen nicht korrekt gezeichnet werden.

11
Austin

Es stellt sich heraus, dass Sie Zellen in einer statischen UITableView - und mit Animation - ein- und ausblenden können. Und es ist nicht so schwer zu erreichen.

Demo-Projekt

Demo-Projektvideo

Der Gist:

  1. Use tableView:heightForRowAtIndexPath:, um die Zellenhöhe dynamisch basierend auf einem bestimmten Status festzulegen.
  2. Wenn sich der Status ändert, animieren Sie Zellen, die durch Aufruf von tableView.beginUpdates();tableView.endUpdates() angezeigt oder ausgeblendet werden.
  3. Rufen Sie nicht tableView.cellForRowAtIndexPath: in tableView:heightForRowAtIndexPath: auf. Verwenden Sie zwischengespeicherte Indexpfade, um die Zellen zu unterscheiden.
  4. Zellen nicht verstecken Legen Sie stattdessen in Xcode die Eigenschaft "Clip Subviews" fest.
  5. Verwenden Sie benutzerdefinierte Zellen (nicht einfach usw.), um eine schöne versteckende Animation zu erhalten. Behandeln Sie das automatische Layout für den Fall korrekt, wenn die Zellenhöhe == 0 ist.

Weitere Informationen in meinem Blog (russische Sprache)

10

Ja, das ist definitiv möglich, obwohl ich im Moment mit dem gleichen Thema zu kämpfen habe. Ich habe es geschafft, dass sich die Zellen verstecken, und alles funktioniert gut, aber ich kann das Ding derzeit nicht ordentlich animieren. Folgendes habe ich gefunden:

Ich verstecke Zeilen basierend auf dem Status eines EIN/AUS-Schalters in der ersten Zeile des ersten Abschnitts. Wenn der Schalter auf ON steht, befindet sich 1 Zeile darunter im selben Abschnitt, ansonsten gibt es 2 verschiedene Zeilen.

Ich habe einen Selektor aufgerufen, wenn der Schalter umgeschaltet wird, und ich setze eine Variable, um anzuzeigen, in welchem ​​Zustand ich bin. Dann rufe ich an:

[[self tableView] reloadData];

Ich überschreibe die tableView: willDisplayCell: forRowAtIndexPath: -Funktion und wenn die Zelle versteckt sein soll, mache ich folgendes:

[cell setHidden:YES];

Das verbirgt die Zelle und ihren Inhalt, entfernt jedoch nicht den von ihr belegten Raum. 

Um das Leerzeichen zu entfernen, überschreiben Sie die tableView: heightForRowAtIndexPath: -Funktion und geben Sie 0 für Zeilen zurück, die ausgeblendet werden sollen. 

Sie müssen auch tableView: numberOfRowsInSection: überschreiben und die Anzahl der Zeilen in diesem Abschnitt zurückgeben. Sie müssen hier etwas seltsames tun, damit die abgerundeten Ecken in den richtigen Zellen erscheinen, wenn Ihre Tabelle ein gruppierter Stil ist. In meiner statischen Tabelle gibt es den vollständigen Satz von Zellen für den Abschnitt, also gibt es die erste Zelle mit der Option, dann 1 Zelle für die EIN-Zustand-Optionen und 2 weitere Zellen für die AUS-Zustand-Optionen, insgesamt 4 Zellen. Wenn die Option aktiviert ist, muss ich 4 zurückgeben. Dazu gehört die ausgeblendete Option, sodass die zuletzt angezeigte Option ein abgerundetes Kästchen enthält. Wenn die Option deaktiviert ist, werden die letzten beiden Optionen nicht angezeigt. Ich gebe 2 zurück. Das fühlt sich alles unbeholfen an. Entschuldigung, wenn dies nicht sehr klar ist, ist es schwierig zu beschreiben. Um den Aufbau zu veranschaulichen, ist dies der Aufbau des Tabellenabschnitts in IB:

  • Zeile 0: Option mit EIN/AUS-Schalter
  • Zeile 1: Wird angezeigt, wenn die Option aktiviert ist
  • Zeile 2: Wird angezeigt, wenn die Option AUS ist
  • Zeile 3: Wird angezeigt, wenn die Option deaktiviert ist

Wenn die Option auf ON gesetzt ist, werden in der Tabelle zwei Zeilen angezeigt.

  • Zeile 0: Option mit EIN/AUS-Schalter
  • Zeile 1: Wird angezeigt, wenn die Option aktiviert ist

Wenn die Option deaktiviert ist, werden in der Tabelle vier Zeilen angezeigt.

  • Zeile 0: Option mit EIN/AUS-Schalter
  • Zeile 1: Wird angezeigt, wenn die Option aktiviert ist 
  • Zeile 2: Wird angezeigt, wenn die Option AUS ist
  • Zeile 3: Wird angezeigt, wenn die Option deaktiviert ist

Dieser Ansatz fühlt sich aus verschiedenen Gründen nicht richtig an, er ist so weit, wie ich mit meinen bisherigen Experimenten gekommen bin. Lass es mich wissen, wenn Sie einen besseren Weg finden. Die Probleme, die ich bisher beobachtet habe, sind:

  • Es fühlt sich falsch an, der Tabelle mitzuteilen, dass die Anzahl der Zeilen anders ist als wahrscheinlich in den zugrunde liegenden Daten enthalten ist.

  • Ich kann die Veränderung nicht animieren. Ich habe versucht, tableView: reloadSections: withRowAnimation: anstelle von reloadData zu verwenden, und die Ergebnisse scheinen nicht sinnvoll zu sein, ich versuche immer noch, dass dies funktioniert. Derzeit scheint es so zu sein, dass tableView die korrekten Zeilen nicht aktualisiert, sodass eine ausgeblendet bleibt, die angezeigt werden soll, und eine Leere unter der ersten Zeile bleibt. Ich denke, das hängt möglicherweise mit dem ersten Punkt der zugrunde liegenden Daten zusammen.

Ich hoffe, dass jemand alternative Methoden vorschlagen kann oder vielleicht, wie Sie die Animation erweitern können, aber vielleicht werden Sie damit beginnen. Ich entschuldige mich für das Fehlen von Hyperlinks zu Funktionen. Ich habe sie eingefügt, sie wurden jedoch vom Spam-Filter zurückgewiesen, da ich ein recht neuer Benutzer bin.

8
Gareth Clarke

Wie in der Antwort von Justas, aber für 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)
}
7
Chris Herbst

Die obigen Antworten zum Ausblenden/Anzeigen von Zellen, Ändern von rowHeight oder Verwirrung mit automatischen Layouteinschränkungen funktionierten für mich aufgrund von Problemen mit dem automatischen Layout nicht. Der Code wurde unerträglich.

Für eine einfache statische Tabelle funktionierte für mich am besten:

  1. Erstellen Sie einen Auslass für jede Zelle in der statischen Tabelle
  2. Erstellen Sie ein Array nur mit den Zellauslässen, die angezeigt werden sollen
  3. Überschreiben Sie cellForRowAtIndexPath, um die Zelle aus dem Array zurückzugeben
  4. Überschreiben Sie numberOfRowsInSection, um die Anzahl des Arrays zurückzugeben
  5. Implementieren Sie eine Methode, um festzustellen, welche Zellen sich in diesem Array befinden müssen, und rufen Sie diese Methode bei Bedarf auf, und anschließend reloadData.

Hier ist ein Beispiel aus meinem Table View Controller:

@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
}
3
David Barta

In> Swift 2.2 habe ich hier einige Antworten zusammengefasst. 

Machen Sie aus dem Storyboard einen Auslass, um eine Verknüpfung zu Ihrer staticCell herzustellen.

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

Ich möchte meine erste Zelle ausblenden, so dass ich die Höhe wie oben beschrieben auf 0 setze.

1
CodeOverRide

Ich habe eine Lösung gefunden, um Zellen in statischen Tabellen zu verbergen.

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

Nur ein zusätzliches Wörterbuch erforderlich:

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

Und schauen Sie sich die Implementierung von MyTableViewController an. Wir benötigen zwei Methoden, um indexPath zwischen sichtbaren und unsichtbaren Indizes zu konvertieren ...

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

Eine IBAction auf UISwitch-Wertänderung:

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

Einige UITableViewDataSource- und UITableViewDelegate-Methoden:

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

Einfache, mit iOS 11 und IB/Storyboard kompatible Methode

Für iOS 11 habe ich festgestellt, dass eine modifizierte Version von Mohamed Salehs Antwort am besten funktioniert, wobei einige Verbesserungen auf der Apple-Dokumentation basieren. Es wird schön animiert, hässliche Hacks oder hartcodierte Werte vermieden und verwendet Zeilenhöhen, die bereits im Interface Builder festgelegt wurden.

Das grundlegende Konzept besteht darin, die Zeilenhöhe für alle ausgeblendeten Zeilen auf 0 zu setzen. Verwenden Sie dann tableView.performBatchUpdates , um eine Animation auszulösen, die konsistent funktioniert.

Stellen Sie die Zellenhöhen ein

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

Sie sollten sicherstellen, dass cellIsHidden und indexPathOfHiddenCell Ihrem Anwendungsfall entsprechend eingestellt sind. Für meinen Code sind sie Eigenschaften in meinem Table View Controller.

Zelle umschalten

In welcher Methode auch immer die Sichtbarkeit (wahrscheinlich eine Tastenaktion oder didSelectRow) gesteuert wird, können Sie den cellIsHidden-Status innerhalb eines performBatchUpdates-Blocks umschalten:

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

Apple empfiehlt performBatchUpdates über beginUpdates/endUpdates wenn immer möglich.

1
robmathers

Antwort in Swift :

Fügen Sie Ihrem TableViewController die folgende Methode hinzu:

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

wenn die tableView versucht, die Zelle, die Sie ausblenden möchten, zu zeichnen, wird sie nicht angezeigt, da ihre Höhe dank der obigen Methode auf 0pt gesetzt wird.

Bitte beachten Sie, dass indexPathOfCellYouWantToHide jederzeit geändert werden kann :)

1

Okay, nach einigen Versuchen habe ich eine nicht allgemeine Antwort ... Ich benutze die "isHidden" - oder "hidden" -Variable, um zu prüfen, ob diese Zelle versteckt werden soll.

  1. erstellen Sie ein IBOutlet in Ihrem Ansichtscontroller .@IBOutlet weak var myCell: UITableViewCell!

  2. Aktualisieren Sie die Variable myCell in Ihrer benutzerdefinierten Funktion. Sie können sie beispielsweise in viewDidLoad hinzufügen:

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

  1. in Ihrer Delegiertenmethode:

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

Dadurch wird Ihre Logik in der Delegat-Methode reduziert, und Sie müssen sich nur noch auf Ihre Geschäftsanforderungen konzentrieren. 

1
Jun Jie Gan

Schnell 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
}
1
pizzamonster

Sicher kannst du. Kehren Sie zunächst zu Ihrer tableView-Anzahl der Zellen zurück, die Sie anzeigen möchten, und rufen Sie super auf, um bestimmte Zellen aus Ihrem Storyboard zu erhalten, und geben Sie sie für tableView zurück:

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
}

Wenn Ihre Zellen unterschiedliche Werte haben, geben Sie sie auch zurück:

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

Die Lösung von k06a ( https://github.com/k06a/ABStaticTableViewController ) ist besser, da der gesamte Abschnitt einschließlich der Zellenkopfzeilen und -fußzeilen ausgeblendet wird ( https://github.com/peterpaulis/StaticDataTableViewController.) ) verbirgt alles außer Fußzeile.

BEARBEITEN

Ich habe gerade eine Lösung gefunden, wenn Sie die Fußzeile in StaticDataTableViewController ausblenden möchten. Folgendes müssen Sie in die Datei StaticTableViewController.m kopieren:

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

Im einfachsten Fall, wenn Sie Zellen ganz unten in der Tabellenansicht ausblenden, können Sie tableView contentInset nach dem Ausblenden der Zelle anpassen:

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

Zusätzlich zur @Saleh Masum-Lösung: 

Wenn Sie Auto-Layout-Fehler erhalten, können Sie einfach die Einschränkungen aus dem tableViewCell.contentView entfernen.

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

}

Diese Lösung hängt vom Fluss Ihrer App ab . Wenn Sie die Zelle in derselben View Controller-Instanz anzeigen/ausblenden möchten, ist dies möglicherweise nicht die beste Wahl, da sie die Einschränkungen entfernt.

0
Luca

Dies ist eine neue Möglichkeit, dies mithilfe von https://github.com/k06a/ABStaticTableViewController auszuführen.

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

Ich habe eine bessere Möglichkeit, statische Zellen und sogar Abschnitte ohne Hacks dynamisch auszublenden.

Wenn Sie die Zeilenhöhe auf 0 setzen, kann eine Zeile ausgeblendet werden. Dies funktioniert jedoch nicht, wenn Sie einen gesamten Abschnitt ausblenden möchten, der einige Leerzeichen enthält, auch wenn Sie alle Zeilen ausblenden.

Mein Ansatz ist es, ein Abschnittsarray aus statischen Zellen zu erstellen. Der Inhalt der Tabellenansicht wird dann vom Abschnittsarray gesteuert.

Hier ist ein Beispielcode:

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

Auf diese Weise können Sie den gesamten Konfigurationscode zusammenstellen, ohne den bösen Code schreiben zu müssen, um die Anzahl der Zeilen und Abschnitte zu berechnen. Und natürlich keine _0_ Höhen mehr.

Dieser Code ist auch sehr einfach zu pflegen. Zum Beispiel, wenn Sie weitere Zellen oder Abschnitte hinzufügen/entfernen möchten.

Auf ähnliche Weise können Sie ein Titel-Array für Abschnittsüberschriften und ein Titel-Array für Abschnittsfußzeilen erstellen, um Ihre Abschnittsüberschriften dynamisch zu konfigurieren.

0
Simon Wang