Aquí está la clase CollapsingTableViewDelegate
con la que estoy trabajando actualmente para hacer esto. Esto solo funciona con contenido de tabla estática.
Proporciona la implementación CollapsingTableCellDelegate
a esta clase, que debe saber cómo calcular los tamaños plegados y expandidos de cada fila, y cómo crear un UIView
para cada fila. La vista se mantiene igual, ya sea que se haya colapsado o expandido, de modo que la parte superior de la vista de cada fila sirva como encabezado seleccionable de esa fila.
A continuación, convierta esta clase en la fuente de datos y delegue para su UITableView
.
Archivo de cabecera CollapsingTableViewDelegate.h
:
#import <UIKit/UIKit.h>
@protocol CollapsingTableCellDelegate<NSObject>
@required
- (CGFloat)collapsingCellHeightForRow:(int)row expanded:(BOOL)expanded;
- (UIView *)collapsingCellViewForRow:(int)row;
@optional
- (BOOL)collapsingCellAllowCollapse:(int)row;
@end
struct cell;
@interface CollapsingTableViewDelegate : NSObject <UITableViewDelegate, UITableViewDataSource> {
id<CollapsingTableCellDelegate> cellDelegate;
int numCells;
int currentSelection;
struct cell *cells;
}
@property (nonatomic, retain, readonly) id<CollapsingTableCellDelegate> cellDelegate;
@property (nonatomic, assign, readonly) int numCells;
@property (nonatomic, assign) int currentSelection;
@property (nonatomic, assign, readonly) struct cell *cells;
- (CollapsingTableViewDelegate *)initWithCellDelegate:(id<CollapsingTableCellDelegate>)delegate numCells:(int)numCells;
- (void)tableView:(UITableView *)tableView touchRow:(int)newSelection;
@end
y fuente de archivo 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<CollapsingTableCellDelegate>)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
no la perfección, pero parece que funciona básicamente para mí.
Cualquier cosa es posible! –
@Jacob ¡No todo es posible! Ver http://stackoverflow.com/questions/4962539/creating-generic-method-names-in-generic-class. ;) – jakev
Eche un vistazo a https://github.com/nacho4d/Accordion Implementa una navegación de estilo Accordion para iPad, ¡allí puede ver cómo funciona todo! – myell0w