it-swarm.com.de

UITableViewCell erweitern Sie durch Klicken

Nehmen wir an, wir haben eine benutzerdefinierte UITableViewCell

Wenn ich also auf die benutzerdefinierte Schaltfläche in der Zelle klicke, sollte sie sich bis zu einem gewissen Grad ausdehnen (Sie können 40 Höhe mehr sagen ...) und wenn ich erneut auf dieselbe benutzerdefinierte Schaltfläche klicke, sollte sie auf die vorherige Höhe reduziert werden.

Entwickler bitte führen Sie mich .. wie kann ich diese Aufgabe erreichen

52
Tariq

Implementieren Sie heightForRowAtIndexPath, um die richtige Höhe zu berechnen. Erzwingen Sie dann im Code für Ihre Schaltfläche die Tabelle, um die Höhe jeder Zelle mit beginUpdates plus endUpdates neu zu bewerten:

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

Änderungen an den Höhen der Tableview-Zellen werden automatisch mit heightForRowAtIndexPath berechnet und die Änderungen werden auch animiert.

Anstelle einer Schaltfläche in Ihrer Zelle, die dies tut, können Sie sogar die Zelle in didSelectRowAtIndexPath auswählen.

67
kris

Ich werde hier nichts sagen, um der akzeptierten Antwort zu widersprechen, da sie vollkommen richtig ist. Ich werde jedoch detaillierter darauf eingehen, wie dies zu erreichen ist. Wenn Sie das alles nicht durchlesen möchten und mehr Interesse daran haben, mit dem Quellcode eines laufenden Projekts zu spielen, habe ich ein Beispielprojekt in GitHub hochgeladen.

Die grundlegende Idee ist, eine Bedingung innerhalb der Methode -tableView: heightForRowAtIndexPath: zu haben, die bestimmt, ob die aktuelle Zelle erweitert werden soll oder nicht. Dies wird durch den Aufruf von Anfangs- und Endupdates für die Tabelle aus -tableView: didSelectRowAtIndexPath: ausgelöst. In diesem Beispiel werde ich zeigen, wie eine Tabellensicht erstellt wird, mit der jeweils eine Zelle erweitert werden kann.

Als Erstes müssen Sie einen Verweis auf ein NSIndexPath -Objekt deklarieren. Sie können dies nach Belieben tun, aber ich empfehle die Verwendung einer Eigenschaftsdeklaration wie folgt:

@property (strong, nonatomic) NSIndexPath *expandedIndexPath;

NOTE: Sie müssen diesen Indexpfad nicht in viewDidLoad oder einer anderen ähnlichen Methode erstellen. Die Tatsache, dass der Index anfangs null ist, bedeutet nur, dass die Tabelle anfangs keine erweiterte Zeile hat. Wenn Sie die Tabelle lieber mit einer erweiterten Zeile Ihrer Wahl beginnen möchten, können Sie Ihrer viewDidLoad-Methode Folgendes hinzufügen:

NSInteger row = 1;
NSInteger section = 2;
self.expandedIndexPath = [NSIndexPath indexPathForRow:row inSection:section];

Im nächsten Schritt fahren Sie mit Ihrer UITableViewDelegate - Methode -tableView: didSelectRowAtIndexPath: fort, um die Logik hinzuzufügen, um den erweiterten Zellindex basierend auf der Benutzerauswahl zu ändern. Die Idee hierbei ist, den gerade ausgewählten Indexpfad mit dem in der Variablen expandedIndexPath gespeicherten Indexpfad zu vergleichen. Wenn die beiden übereinstimmen, wissen wir, dass der Benutzer versucht, die Auswahl der erweiterten Zelle aufzuheben. In diesem Fall setzen wir die Variable auf null. Ansonsten setzen wir die Variable expandedIndexPath auf den gerade ausgewählten Index. Dies geschieht alles zwischen Aufrufen von beginUpdates/endUpdates, damit die Tabellensicht die Übergangsanimation automatisch verarbeiten kann. 

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [tableView beginUpdates]; // tell the table you're about to start making changes

    // If the index path of the currently expanded cell is the same as the index that
    // has just been tapped set the expanded index to nil so that there aren't any
    // expanded cells, otherwise, set the expanded index to the index that has just
    // been selected.
    if ([indexPath compare:self.expandedIndexPath] == NSOrderedSame) {
        self.expandedIndexPath = nil;
    } else {
        self.expandedIndexPath = indexPath;
    }

    [tableView endUpdates]; // tell the table you're done making your changes
}

Der letzte Schritt ist dann in einer anderen UITableViewDelegate Methode -tableView: heightForRowAtIndexPath:. Diese Methode wird aufgerufen, nachdem Sie einmal beginUpdates für jeden Indexpfad ausgelöst haben, für den die Tabelle eine Aktualisierung benötigt. Hier vergleichen Sie die expandedIndexPath mit dem Indexpfad, der gerade neu bewertet wird.

Wenn die beiden Indexpfade gleich sind, ist dies die Zelle, die Sie erweitern möchten. Andernfalls sollte die Höhe normal sein. Ich habe die Werte 100 und 44 verwendet, aber Sie können das verwenden, was Ihren Bedürfnissen entspricht.

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Compares the index path for the current cell to the index path stored in the expanded
    // index path variable. If the two match, return a height of 100 points, otherwise return
    // a height of 44 points.
    if ([indexPath compare:self.expandedIndexPath] == NSOrderedSame) {
        return 100.0; // Expanded height
    }
    return 44.0; // Normal height
}
94
Mick MacCallum

Ich habe dafür eine Open Source-Bibliothek erstellt. Sie implementieren nur Collapse und erweitern Delegates in Ihrem Code und voilà! Sie können auch beliebige Zeichnungen und Animationen ausführen. check out this .

enter image description here

9
Hamid Vakilian

Ich habe eine wiederverwendbare Komponente erstellt, die genau das tut, worüber Sie sprechen. Es ist ziemlich einfach zu bedienen und es gibt ein Demo-Projekt.

GCRetractableSectionController auf GitHub.

8
gcamp

Anstelle von [tableView beginUpdates] und [tableView endUpdates] verwende ich die [tableView reloadRowsAtIndexPath:... withRowAnimation:...]-Methode in der didSelectRowAtIndexPath-Methode.

Ich bevorzuge das, weil ich einige Probleme mit Elementen hatte, die angezeigt werden sollten, wenn ich UITableViewCell erweitere, wenn ich die begin & end-Aktualisierungsmethode verwende. Ein weiterer Punkt ist, dass Sie zwischen einigen Animationen wählen können: Oben, Unten, Links, Rechts ...

8
Mike_NotGuilty

Dies ist Micks Antwort, aber für Swift 4. (IndexPath ersetzt NSIndexPath, der mit einem leeren IndexPath geliefert wird, da Swift durch Null ausfallen würde. Außerdem können Sie zwei Instanzen von IndexPath mit == vergleichen.

Deklarieren Sie die Eigenschaft extendedIndexPath.

var expandedIndexPath = IndexPath()

Optionaler viewDidLoad-Teil.

expandedIndexPath = IndexPath(row: 1, section: 2)

Dann der didSelectRow-Teil.

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    tableView.beginUpdates()

    if indexPath == expandedIndexPath {
        expandedIndexPath = IndexPath()
    } else {
        expandedIndexPath = indexPath
    }

    tableView.endUpdates()
}

Dann das Element heightForRow.

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    if indexPath == expandedIndexPath {
        return 100
    }

    return 44
}
3
David H

Ich habe den Quellcode von Gcamp verwendet und meine eigene Version erstellt. 

1) Initialisieren Sie in einer loadView-Methode ein veränderbares Array, in dem Sie den erweiterten oder nicht erweiterten Status Ihrer Abschnitte speichern. Es ist wichtig, erweiterte Status in einem separaten Array zu speichern, das beim Scrollen in der Tabellenansicht nicht zerstört wird (wenn Sie es beispielsweise in einer headerView speichern, wird es neu gezeichnet und vergisst, ob es erweitert wurde oder nicht). In meinem Fall handelt es sich um _sectionStatuses-Array. 

- (void)loadView
{
     // At the beginning all sections are expanded
    _sectionStates = [NSMutableArray arrayWithCapacity:self.tableView.numberOfSections];
    for (int i = 0; i < self.tableView.numberOfSections; i++) {
        _sectionStates[i] = [NSNumber numberWithBool:YES];
    }
}

2) Erstellen Sie eine benutzerdefinierte HeaderView für einen Abschnitt mit einer Schaltfläche zum Erweitern. Delegieren Sie eine Aktion von einer Schaltfläche in Ihrer headerView mithilfe des Delegierungsmusters an Ihren TableViewController. Geeignete Bilder finden Sie im Quellcode von Gcamp.

3) Erstellen Sie eine Aktion zum Entfernen oder Hinzufügen von Zeilen. Hier ist _foldersArray meine Struktur, die alle Daten enthält. Die headerView meines Abschnitts - MCExpandableAccountHeaderView - kennt ihre eigene Abschnittsnummer - ich übertrage sie dort, wenn ich für jeden Abschnitt Header-Ansichten erstelle. Es ist wichtig, diese Methode auf diese Methode zu übertragen, da Sie wissen müssen, welcher Abschnitt jetzt erweitert oder gestreckt ist.

- (void)expandClicked:(MCAccountHeaderView *)sender
{
MCExpandableAccountHeaderView *expandableAccountHeaderView = (MCExpandableAccountHeaderView*)sender;

// Finding a section, where a button was tapped
NSInteger section = expandableAccountHeaderView.section;

// Number of rows, that must be in a section when it is expanded
NSUInteger contentCount = [_foldersArray[section - 1][@"folders"] count];

// Change a saved status of a section
BOOL expanded = [_sectionStates[section] boolValue];
expanded = ! expanded;
expandableAccountHeaderView.expanded = expanded;
_sectionStates[section] = [NSNumber numberWithBool:expanded];

// Animation in a table
[self.tableView beginUpdates];

NSMutableArray* modifiedIndexPaths = [[NSMutableArray alloc] init];
for (NSUInteger i = 0; i < contentCount; i++) {
    NSIndexPath* indexPath = [NSIndexPath indexPathForRow:i inSection:section];
    [modifiedIndexPaths addObject:indexPath];
}

if (expandableAccountHeaderView.expanded) [self.tableView insertRowsAtIndexPaths:modifiedIndexPaths withRowAnimation:UITableViewRowAnimationFade];
else [self.tableView deleteRowsAtIndexPaths:modifiedIndexPaths withRowAnimation:UITableViewRowAnimationFade];

[self.tableView endUpdates];

// Scroll to the top of current expanded section
if (expandableAccountHeaderView.expanded) [self.tableView scrollToRowAtIndexPath:INDEX_PATH(0, section) atScrollPosition:UITableViewScrollPositionTop animated:YES];
}

4) Es ist auch wichtig, die richtige Anzahl oder Zeilen in einem Abschnitt zurückzugeben, abhängig davon, ob er erweitert ist oder nicht. 

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
     BOOL expanded = [_sectionStates[section] boolValue];

     return expanded ? [_foldersArray[section - 1][@"folders"] count] : 0;   
}
2
wzbozon

Nach diesem mittleren Artikel zum Erweitern der Zellen basierend auf einem Tastendruck und dem Festlegen der numbersOfLine für ein bestimmtes Label konnte ich die Animation mit ausführen

tableView.beginUpdates()
tableView.performBatchUpdates({
  cell.description.numberOfLines = !expanded ? 0 : 3
}, completion: nil)
tableView.endUpdates()

Hinweis performBatchUpdates ist nur in iOS 11 verfügbar

0

Für mich funktioniert es zu benutzen:

  1. auf UITableViewDelegate

    func tableView (_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

        print("Did select row: \(indexPath.row).")
    
        tableView.beginUpdates()
        tableView.endUpdates()
    }
    
  2. auf auswählbare/erweiterbare UITableViewCell

    überschreibe func setSelected (_ ausgewählt: Bool, animiert: Bool) {super.setSelected (ausgewählt, animiert: animiert)

       configStyle(selected)
    }
    
  3. Wichtig! tableView.rowHeight ist .automatic und UITableViewCell ist eine Einschränkung, um die automatische Höhenberechnung zu ermöglichen, d. h. ihre Höhenbeschränkung ist klar definiert, wie die Einschränkung auf die Ober-/Unterseite oder die hinzugefügten Höhenbeschränkungen oder die Verwendung der beschrifteten intrinsischen Inhaltsgröße.

0
Michał Ziobro
initialize iSelectedIndex = -1; and declare
UITableView *urTableView;

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{

return 10;    //Section count

}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{

return 3; //row count

}

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

static NSString *CellIdentifier = @"Cell";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

if(cell == nil)
{
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];

}

[cell.textLabel setText:[NSString stringWithFormat:@"sec:%d,row:%d",indexPath.section,indexPath.row]];

return cell;

}


- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{

// adding a label with the tap gesture to the header in each section

headerLabel = [[UILabel alloc]init]; 

headerLabel.tag = section;

headerLabel.userInteractionEnabled = YES;

headerLabel.backgroundColor = [UIColor greenColor];

headerLabel.text = [NSString stringWithFormat:@"Header No.%d",section];

headerLabel.frame = CGRectMake(0, 0, tableView.tableHeaderView.frame.size.width, tableView.tableHeaderView.frame.size.height);

UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(gestureTapped:)];

[headerLabel addGestureRecognizer:tapGesture];

return headerLabel;

}

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

return 50.0; //adjust the height as you need

}

- (void)gestureTapped:(UITapGestureRecognizer *)sender{

UIView *theSuperview = self.view; // whatever view contains 

CGPoint touchPointInSuperview = [sender locationInView:theSuperview];

UIView *touchedView = [theSuperview hitTest:touchPointInSuperview withEvent:nil];

if([touchedView isKindOfClass:[UILabel class]])
{

    if (iSelectedIndex != touchedView.tag) { //if new header is selected , need to expand

        iSelectedIndex = touchedView.tag;

    }else{   // if the header is already expanded , need to collapse

        iSelectedIndex = -1;

    }

    [urTableView beginUpdates];

    [urTableView endUpdates];

}

}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

// Show or hide cell

float height = 0.0;

if (indexPath.section == iSelectedIndex) {

    height = 44.0; // Show the cell - adjust the height as you need

}

return height;

}
0
archana

Zum Hinzufügen von 0x7fffffff answer habe ich festgestellt, dass ich in der if -Anweisung eine zusätzliche Bedingung innerhalb von didSelectRowAtIndexPath - benötigt.

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

   [tableView beginUpdates];

   if (self.expandedIndexPath && [indexPath compare:self.expandedIndexPath] == NSOrderedSame) {
       self.expandedIndexPath = nil;
   } else {
       self.expandedIndexPath = indexPath;
   }

   [tableView endUpdates];

}
0
RossP