Как реализовать представление аккордеона для iPhone SDK-приложения?
Кто-нибудь видел реализацию «аккордеона» (возможно, называемого «анимированным контуром») для iPhone? Я нашел пример проекта для Cocoa, но прежде чем попробовать порт, я надеялся, что кто-то уже изобрел колесо.
Чтобы было ясно, в UIView рассмотрите стек разделов, каждый из которых содержит заголовок, а затем некоторое содержимое. Когда пользователь касается заголовка (или через какое-либо сообщение / событие), если секция уже открыта => закрыть ее; если секция закрыта => откройте ее и закройте любой другой открытый раздел. Пример в jQuery выглядит так: http://docs.jquery.com/UI/Accordion
В моем случае я хотел бы иметь возможность размещать содержимое UIView в каждом разделе.
- Выясните, нажал ли пользователь кнопку «Назад» в controllerе uinavigation?
- Воспроизведение звука на iPhone даже в бесшумном режиме
- Получить текущего первого ответчика без использования частного API
- Как сделать ImageView UITableViewCell фиксированным, даже когда изображение меньше
- Проверка подлинности электронной почты на textField в iPhone sdk
Мне было бы интересно увидеть некоторые реальные приложения, которые внедрили это – просто знать, что это возможно!
- objective-C: Как получить адрес маршрутизатора?
- Прокрутка UITableView внутри UIScrollView
- захват себя в этом блоке, вероятно, приведет к циклу сохранения
- Как я могу округлить значение float до двух постсимвольных позиций?
- Есть ли способ указать позицию / индекс аргумента в NSString stringWithFormat?
- Не удалось добавить объекты в NSMutableArray в Objective C
- Плохой URL-адрес при запросе с помощью NSURL
- NSMutableArray addObject не работает
Я бы просто использовал 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/