Как реализовать представление аккордеона для iPhone SDK-приложения?

Кто-нибудь видел реализацию «аккордеона» (возможно, называемого «анимированным контуром») для iPhone? Я нашел пример проекта для Cocoa, но прежде чем попробовать порт, я надеялся, что кто-то уже изобрел колесо.

Чтобы было ясно, в UIView рассмотрите стек разделов, каждый из которых содержит заголовок, а затем некоторое содержимое. Когда пользователь касается заголовка (или через какое-либо сообщение / событие), если секция уже открыта => закрыть ее; если секция закрыта => откройте ее и закройте любой другой открытый раздел. Пример в jQuery выглядит так: http://docs.jquery.com/UI/Accordion

В моем случае я хотел бы иметь возможность размещать содержимое UIView в каждом разделе.

Мне было бы интересно увидеть некоторые реальные приложения, которые внедрили это – просто знать, что это возможно!

Я бы просто использовал 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, если хотите).

Каждое найденное мной решение использовало UITableView, который не работал для меня, потому что я не отображал табличные данные. Вот почему я создал элемент управления AccordionView . Использование довольно просто:

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

В реальной жизни это выглядит так:

введите описание изображения здесь

Черные полосы – это заголовки, и вы можете настроить их все, что хотите (я использую Three20).

Я нашел этот код: простая реализация аккордеона ..

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

Надеюсь, это поможет кому-то.

Я просто наткнулся на это и нашел решение mjdth очень простым и полезным. Однако вы можете использовать

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

вместо используемого метода reloadSections поскольку строки перезагрузки дают вам гораздо более плавный переход.

Вот class CollapsingTableViewDelegate которым я сейчас работаю, чтобы сделать это. Это работает только со статическим содержимым таблицы.

Вы поставляете реализацию CollapsingTableCellDelegate в этот class, который должен знать, как вычислить свернутые и расширенные размеры каждой строки и как создать UIView для каждой строки. Представление остается неизменным, если оно было свернуто или расширено, так что верхняя лента в представлении каждой строки служит в качестве кликабельного заголовка этой строки.

Затем вы делаете этот class источником данных и делегатом для своего UITableView .

Файл заголовка 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 

и исходный файл 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 

Не совершенство, но, похоже, в основном работает для меня.

Я нашел этот пример здесь, если кому-то интересно.

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

  • Как сделать ImageView UITableViewCell фиксированным, даже когда изображение меньше
  • UIScrollView: подкачка по горизонтали, прокрутка по вертикали?
  • Ошибка UIActivityViewController на iOS 8 iPads
  • Получите данные Exif от UIImage - UIImagePickerController
  • Objective-C: Как изменить class объекта во время выполнения?
  • UIImage imageNamed требует pathForResource?
  • Определение типа устройства
  • Сортировка NSArray строк или объектов даты
  • Класс Foo реализован как в MyApp, так и в MyAppTestCase. Один из двух будет использован. Какой из них не определен
  • Получить процентное использование процессора
  • Как установить приложение Cocoa в качестве браузера по умолчанию?
  • Давайте будем гением компьютера.