Я бы просто использовал UITableView, чтобы высота каждой ячейки зависела от того, "открыта" она или нет, а затем переходите оттуда. Легко изменить размер строк и можно просто сделать так, чтобы общая высота объединенных ячеек была доступной в UITableView, чтобы она выглядела как гармошка больше, чем просто таблица.
Это быстрый хак, который должен работать, но в вашем .h файле подкласса UITableViewController:
bool sectionopen[4]; ///or some other way of storing the sections expanded/closed state
И в .m файле поместите что-то вроде:
- (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];
}
Это в основном возьмет 4 строки и превратит их в свернутые секции, где выбор одной строки расширит ее до 240 пикселей и свернет все остальные строки до 40. Вы можете изменить все эти цифры, разобраться в секциях и делать с ними все, что захотите.
Я попробовал это, и это работает. Затем вы можете завершить его, добавив в код создания ячейки другое содержимое, чтобы добавить в секцию все, что захотите (включая, возможно, прокручиваемый UITextView, если хотите)
.Я только что наткнулся на это и нашел решение mjdth очень простым и полезным. Однако вы можете использовать
[self.tableView reloadRowsAtIndexPaths: paths withRowAnimation:UITableViewRowAnimationBottom];
вместо предложенного метода reloadSections
, поскольку строки перезагрузки обеспечивают более плавный переход.
Вот класс CollapsingTableViewDelegate
, с которым я сейчас работаю, чтобы сделать это. Это работает только со статическим содержимым таблицы.
Вы предоставляете этому классу реализацию CollapsingTableCellDelegate
, который должен знать, как вычислить свернутые и развернутые размеры каждой строки, и как создать UIView
для каждой строки. Представление остается неизменным в свернутом или развернутом виде, так что верхняя часть представления каждой строки служит кликабельным заголовком этой строки.
Затем вы делаете этот класс источником данных и делегатом для вашего UITableView
.
Файл заголовка 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
и файл исходников 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
Не совершенство, но, кажется, в основном работает для меня.