Come implementare una vista fisarmonica per un’app iPhone SDK?

Qualcuno ha visto l’implementazione di una vista “fisarmonica” (forse chiamata “contorno animato”) per l’iPhone? Ho trovato un progetto di esempio per Cocoa, ma prima di provare un porto, speravo che qualcuno avesse già inventato la ruota.

Per chiarire, in un UIView, considera una serie di sezioni, ciascuna contenente un’intestazione, e quindi alcuni contenuti. Quando l’utente tocca l’intestazione (o attraverso qualche messaggio / evento), se la sezione è già aperta => chiudila; se la sezione è chiusa => aprila e chiudi qualsiasi altra sezione aperta. Un esempio di jQuery è simile a http://docs.jquery.com/UI/Accordion

Nel mio caso, vorrei poter inserire qualsiasi contenuto di UIView in ogni sezione.

Sarei interessato a vedere solo alcune app reali che hanno implementato questo – solo per sapere che è ansible!

Vorrei solo usare un UITableView, fare in modo che l’altezza di ogni cella dipenda dal fatto che sia “aperta” o meno e poi andare da lì. È facile ridimensionare le righe e si potrebbe semplicemente rendere l’altezza totale delle celle combinate l’altezza disponibile in UITableView in modo che assomigli ad una fisarmonica più che a una tabella.

Questo è un trucco rapido che dovrebbe funzionare, ma nel file .h della sottoclass UITableViewController:

bool sectionopen[4]; ///or some other way of storing the sections expanded/closed state 

E nel file .m metti qualcosa come:

 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return 4; } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { if (sectionopen[indexPath.row]) { return 240;///it's open } else { return 45;///it's closed } } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *mycell = [[[UITableViewCell alloc] init] autorelease]; mycell.textLabel.text= @"Section Name"; return mycell; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { ///turn them all off sectionopen[0]=NO; sectionopen[1]=NO; sectionopen[2]=NO; sectionopen[3]=NO; ///open this one sectionopen[indexPath.row]=YES; ///animate the opening and expand the row [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade]; } 

Praticamente prenderà 4 righe e le trasformsrà in sezioni pieghevoli dove la selezione di una riga la espande a 240 pixel e collassa tutte le altre righe a 40. Puoi cambiare tutti quei numeri e capire le sezioni e fare qualsiasi altra cosa desideri con esso.

L’ho provato e funziona. Puoi quindi completarlo aggiungendo l’altro contenuto al codice di creazione della cella per aggiungere tutto ciò che desideri in una sezione (incluso eventualmente un UITextView a scorrimento, se lo desideri).

Ogni soluzione che ho trovato utilizza UITableView, che non ha funzionato per me, perché non ho mostrato dati tabulari. Questo è il motivo per cui ho creato il controllo AccordionView . L’utilizzo è piuttosto semplice:

 AccordionView *accordion = [[AccordionView alloc] initWithFrame:CGRectMake(0, 0, 320, 420)]; [self addSubview:accordion]; // Only height is taken into account, so other parameters are just dummy UIButton *header1 = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 0, 30)]; [header1.titleLabel setText:@"First row"]; UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, 200)]; // ... add subviews to view1 [accordion addHeader:header1 withView:view1]; // ... add more panels [accordion setSelectedIndex:0]; 

Nella vita reale assomiglia a questo:

inserisci la descrizione dell'immagine qui

Le barre nere sono le intestazioni e puoi personalizzarle tutte (io sto usando Three20).

Ho trovato questo codice: una semplice implementazione della fisarmonica ..

https://github.com/kuon/ios-example-accordion

Spero che questo possa aiutare qualcuno ..

Mi sono imbattuto in questo e ho trovato la soluzione di mjdth molto semplice e utile. Tuttavia, potresti voler usare

 [self.tableView reloadRowsAtIndexPaths: paths withRowAnimation:UITableViewRowAnimationBottom]; 

invece del metodo di reloadSections reloadSections come le righe di ricarica ti dà una transizione molto più agevole.

Ecco la class CollapsingTableViewDelegate cui sto lavorando attualmente per farlo. Funziona solo con contenuto statico della tabella.

CollapsingTableCellDelegate implementazione CollapsingTableCellDelegate a questa class, che deve sapere come calcolare le dimensioni espanse e compresse di ogni riga e come creare un UIView per ogni riga. La vista rimane invariata, sia espansa che espansa, in modo che la porzione superiore della vista di ogni riga funga da intestazione cliccabile di quella riga.

Quindi si rende a questa class l’origine dati e il delegato per UITableView .

File di intestazione CollapsingTableViewDelegate.h :

 #import  @protocol CollapsingTableCellDelegate @required - (CGFloat)collapsingCellHeightForRow:(int)row expanded:(BOOL)expanded; - (UIView *)collapsingCellViewForRow:(int)row; @optional - (BOOL)collapsingCellAllowCollapse:(int)row; @end struct cell; @interface CollapsingTableViewDelegate : NSObject  { id cellDelegate; int numCells; int currentSelection; struct cell *cells; } @property (nonatomic, retain, readonly) id cellDelegate; @property (nonatomic, assign, readonly) int numCells; @property (nonatomic, assign) int currentSelection; @property (nonatomic, assign, readonly) struct cell *cells; - (CollapsingTableViewDelegate *)initWithCellDelegate:(id)delegate numCells:(int)numCells; - (void)tableView:(UITableView *)tableView touchRow:(int)newSelection; @end 

e il file sorgente CollapsingTableViewDelegate.m :

 #import "CollapsingTableViewDelegate.h" @implementation CollapsingTableViewDelegate struct cell { u_char expanded; u_char collapsable; }; @synthesize cellDelegate; @synthesize currentSelection; @synthesize cells; @synthesize numCells; #pragma mark - #pragma mark Setup and Teardown - (CollapsingTableViewDelegate *)initWithCellDelegate:(id)delegate numCells:(int)num { if ([super init] == nil) return nil; if ((cells = calloc(num, sizeof(*cells))) == NULL) { [self autorelease]; return nil; } cellDelegate = [delegate retain]; numCells = num; for (int row = 0; row < self.numCells; row++) { struct cell *const cell = &self.cells[row]; cell->collapsable = ![self.cellDelegate respondsToSelector:@selector(collapsingCellAllowCollapse:)] || [self.cellDelegate collapsingCellAllowCollapse:row]; cell->expanded = !cell->collapsable; } currentSelection = -1; return self; } - (void)dealloc { [cellDelegate release]; free(cells); [super dealloc]; } - (void)tableView:(UITableView *)tableView reloadRow:(int)row fade:(BOOL)fade { [tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:row inSection:0]] withRowAnimation:fade ? UITableViewRowAnimationFade : UITableViewRowAnimationNone]; } - (void)tableView:(UITableView *)tableView touchRow:(int)newSelection { // Sanity check if (newSelection < -1 || newSelection >= self.numCells) { NSLog(@"CollapsingTableViewDelegate: invalid row %d not in the range [-1..%d)", newSelection, self.numCells); return; } // Gather info int oldSelection = self.currentSelection; BOOL sameCellSelected = newSelection == oldSelection; struct cell *const oldCell = oldSelection != -1 ? &self.cells[oldSelection] : NULL; struct cell *const newCell = newSelection != -1 ? &self.cells[newSelection] : NULL; // Mark old cell as collapsed and new cell as expanded if (newCell != NULL) newCell->expanded = TRUE; if (oldCell != NULL) oldCell->expanded = FALSE; self.currentSelection = sameCellSelected ? -1 : newSelection; // Update table view if (oldSelection >= newSelection) { if (oldSelection != -1) [self tableView:tableView reloadRow:oldSelection fade:sameCellSelected]; if (newSelection != -1 && !sameCellSelected) [self tableView:tableView reloadRow:newSelection fade:TRUE]; } else { if (newSelection != -1 && !sameCellSelected) [self tableView:tableView reloadRow:newSelection fade:TRUE]; if (oldSelection != -1) [self tableView:tableView reloadRow:oldSelection fade:sameCellSelected]; } // If expanding a cell, scroll it into view if (newSelection != -1 && !sameCellSelected) { [tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:newSelection inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:TRUE]; } } #pragma mark - #pragma mark Table view data source - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.numCells; } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { int row = [indexPath row]; struct cell *const cell = &self.cells[row]; return [self.cellDelegate collapsingCellHeightForRow:row expanded:cell->expanded]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { int row = [indexPath row]; UIView *cellView = [self.cellDelegate collapsingCellViewForRow:row]; [cellView removeFromSuperview]; UITableViewCell *tvcell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil] autorelease]; [tvcell.contentView addSubview:cellView]; tvcell.clipsToBounds = TRUE; tvcell.selectionStyle = UITableViewCellSelectionStyleNone; return tvcell; } #pragma mark - #pragma mark Table view delegate - (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath { int row = [indexPath row]; struct cell *const cell = &self.cells[row]; return cell->collapsable ? indexPath : nil; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)newSelection { [tableView deselectRowAtIndexPath:newSelection animated:TRUE]; [self tableView:tableView touchRow:[newSelection row]]; } @end 

Non è la perfezione, ma sembra fondamentalmente funzionare per me.

Ho trovato questo esempio qui se qualcuno è interessato.

http://www.cocoanetics.com/2011/03/expandingcollapsing-tableview-sections/