Может ли кто-нибудь сказать мне способ выполнить UITableView
расширяемые/сбрасываемые анимации в sections
из UITableView
, как показано ниже?Развернуть/свернуть раздел в UITableView в iOS
или
Может ли кто-нибудь сказать мне способ выполнить UITableView
расширяемые/сбрасываемые анимации в sections
из UITableView
, как показано ниже?Развернуть/свернуть раздел в UITableView в iOS
или
Я уверен, что вы должны просто сделать свой собственный ряд пользовательских заголовков и просто положить, что в качестве первой строки каждого раздела. Подклассификация UITableView или заголовков, которые сейчас существуют, вероятно, будет огромной болью, и я не уверен, что вы можете легко получить от них действия так, как они работают сейчас. Вы можете легко настроить ячейку для просмотра как заголовок и установить tableView:didSelectRowAtIndexPath
, чтобы развернуть или свернуть раздел, который он находится в ручном режиме.
Если бы я был вами, я бы сохранил массив булевых, соответствующий «затраченному» значению каждого из ваших разделов. Затем вы можете установить tableView:didSelectRowAtIndexPath
в каждой из ваших собственных строк заголовков, чтобы переключить это значение, а затем перезагрузить этот конкретный раздел.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row == 0) {
///it's the first row of any section so it would be your custom section header
///put in your code to toggle your boolean value here
mybooleans[indexPath.section] = !mybooleans[indexPath.section];
///reload this section
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationFade];
}
}
Вы бы затем настроить ваш номер numberOfRowsInSection
проверить значение mybooleans
и возвращать либо 1, если раздел не расширен, или 1+ количество элементов в секции, если она расширяется.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (mybooleans[section]) {
///we want the number of people plus the header cell
return [self numberOfPeopleInGroup:section] + 1;
} else {
///we just want the header cell
return 1;
}
}
Вы также должны обновить cellForRowAtIndexPath
вернуть ячейку пользовательского заголовка для первой строки в любой секции.
, если вы использовали приложение Beejive, вы бы знали, что их сводный заголовок раздела фактически «плавает» в верхней части таблицы, даже когда вы прокручиваете часть своего раздела, точно так же, как обычные заголовки разделов Apple , это невозможно, если вы просто добавите ячейку в начале раздела. – user102008
Приятное элегантное решение!user102008 имеет точку в плавающем заголовке, но в сценарии, где вы действительно хотите прокручивать «разделы», это отличный подход. –
@mjdth plz дайте мне какой-нибудь пример кода bcz Мне нужна конкретная ячейка hide/unhide ..thanks заранее – Bajaj
У меня есть лучшее решение, что вы должны добавить UIButton в заголовок раздела и установить размер этой кнопки, равный размеру раздела, но скрыть его прозрачным цветом фона, после чего вам будет легко проверить, какой раздел щелкнуть, чтобы развернуть или коллапс
На мой взгляд, это решение лучше, чем принятый ответ, потому что семантически вы сохраняете заголовок как заголовок, и вы не используете фальшивую строку для имитации заголовка. Метод 'tableView: numberOfRowsInSection:' будет не затронут, и вы будете продолжать использовать его для того, что он на самом деле означает. То же самое касается 'tableView: cellForRowAtIndexPath:'. –
Итак, вы нажимаете кнопку в заголовке раздела, но как вы собираетесь определять, какой раздел нужно перезагрузить? – memmons
@Answerbot Привет, Это очень легко, установив тег для кнопки, используя то же значение с индексом раздела. –
Некоторые примеры кода для анимации в расширении/действие коллапса с помощью заголовка таблицы вид сечения обеспечивается Apple, здесь: Table View Animations and Gestures
ключ к этому подходу к реализации - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
и возвращать пользовательские UIView, который включает в себя (обычно того же размера, что и представление заголовка). Подклассифицируя UIView и используя это для представления заголовка (как это делает этот пример), вы можете легко сохранить дополнительные данные, такие как номер раздела.
Фантастический, спасибо: http://developer.apple.com/library/ios/#samplecode/TableViewUpdates/Introduction /Intro.html – EightyEight
есть ли образец кода, который будет работать на pre-iOS 4? – user102008
не помню, но почему код примера не работает на pre-iOS 4? – samwize
Это лучший способ я нашел, чтобы создать развернутое представление таблицы ячеек
.h файл
NSMutableIndexSet *expandedSections;
.m файл
if (!expandedSections)
{
expandedSections = [[NSMutableIndexSet alloc] init];
}
UITableView *masterTable = [[UITableView alloc] initWithFrame:CGRectMake(0,100,1024,648) style:UITableViewStyleGrouped];
masterTable.delegate = self;
masterTable.dataSource = self;
[self.view addSubview:masterTable];
Таблица методов зрения делегата
- (BOOL)tableView:(UITableView *)tableView canCollapseSection:(NSInteger)section
{
// if (section>0) return YES;
return YES;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 4;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if ([self tableView:tableView canCollapseSection:section])
{
if ([expandedSections containsIndex:section])
{
return 5; // return rows when expanded
}
return 1; // only top row showing
}
// Return the number of rows in the section.
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] ;
}
// Configure the cell...
if ([self tableView:tableView canCollapseSection:indexPath.section])
{
if (!indexPath.row)
{
// first row
cell.textLabel.text = @"Expandable"; // only top row showing
if ([expandedSections containsIndex:indexPath.section])
{
UIImageView *imView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"UITableContract"]];
cell.accessoryView = imView;
}
else
{
UIImageView *imView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"UITableExpand"]];
cell.accessoryView = imView;
}
}
else
{
// all other rows
if (indexPath.section == 0) {
cell.textLabel.text = @"section one";
}else if (indexPath.section == 1) {
cell.textLabel.text = @"section 2";
}else if (indexPath.section == 2) {
cell.textLabel.text = @"3";
}else {
cell.textLabel.text = @"some other sections";
}
cell.accessoryView = nil;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
}
else
{
cell.accessoryView = nil;
cell.textLabel.text = @"Normal Cell";
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([self tableView:tableView canCollapseSection:indexPath.section])
{
if (!indexPath.row)
{
// only first row toggles exapand/collapse
[tableView deselectRowAtIndexPath:indexPath animated:YES];
NSInteger section = indexPath.section;
BOOL currentlyExpanded = [expandedSections containsIndex:section];
NSInteger rows;
NSMutableArray *tmpArray = [NSMutableArray array];
if (currentlyExpanded)
{
rows = [self tableView:tableView numberOfRowsInSection:section];
[expandedSections removeIndex:section];
}
else
{
[expandedSections addIndex:section];
rows = [self tableView:tableView numberOfRowsInSection:section];
}
for (int i=1; i<rows; i++)
{
NSIndexPath *tmpIndexPath = [NSIndexPath indexPathForRow:i
inSection:section];
[tmpArray addObject:tmpIndexPath];
}
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (currentlyExpanded)
{
[tableView deleteRowsAtIndexPaths:tmpArray
withRowAnimation:UITableViewRowAnimationTop];
UIImageView *imView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"UITableExpand"]];
cell.accessoryView = imView;
}
else
{
[tableView insertRowsAtIndexPaths:tmpArray
withRowAnimation:UITableViewRowAnimationTop];
UIImageView *imView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"UITableContract"]];
cell.accessoryView = imView;
}
}
}
NSLog(@"section :%d,row:%d",indexPath.section,indexPath.row);
}
Вероятно, вы должны указывать вопросы как точные дубликаты, а не просто рассылать один и тот же ответ на все из них. – casperOne
Если раздел уже расширен, а другой раздел щелкнут, он дает ошибку – shivam
привет сэр, выбранный указатель hight, как изменить? HeightForRowAtIndexPath, как работать с вашим кодом? –
I ende d только создав headerView, в котором была кнопка (я увидел Son Nguyen's solution выше, после этого, но heres мой код ..это выглядит как много, но это довольно просто):
объявить пару Bools для вас секций
bool customerIsCollapsed = NO;
bool siteIsCollapsed = NO;
... код
теперь в ваших методов делегата Tableview ...
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, _tblSearchResults.frame.size.width, 35)];
UILabel *lblSection = [UILabel new];
[lblSection setFrame:CGRectMake(0, 0, 300, 30)];
[lblSection setFont:[UIFont fontWithName:@"Helvetica-Bold" size:17]];
[lblSection setBackgroundColor:[UIColor clearColor]];
lblSection.alpha = 0.5;
if(section == 0)
{
if(!customerIsCollapsed)
[lblSection setText:@"Customers --touch to show--"];
else
[lblSection setText:@"Customers --touch to hide--"];
}
else
{
if(!siteIsCollapsed)
[lblSection setText:@"Sites --touch to show--"];
else
[lblSection setText:@"Sites --touch to hide--"]; }
UIButton *btnCollapse = [UIButton buttonWithType:UIButtonTypeCustom];
[btnCollapse setFrame:CGRectMake(0, 0, _tblSearchResults.frame.size.width, 35)];
[btnCollapse setBackgroundColor:[UIColor clearColor]];
[btnCollapse addTarget:self action:@selector(touchedSection:) forControlEvents:UIControlEventTouchUpInside];
btnCollapse.tag = section;
[headerView addSubview:lblSection];
[headerView addSubview:btnCollapse];
return headerView;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
if(section == 0)
{
if(customerIsCollapsed)
return 0;
else
return _customerArray.count;
}
else if (section == 1)
{
if(siteIsCollapsed)
return 0;
else
return _siteArray.count;
}
return 0;
}
и, наконец, функция, вызываемая при нажатии одной из кнопок заголовка раздела:
- (IBAction)touchedSection:(id)sender
{
UIButton *btnSection = (UIButton *)sender;
if(btnSection.tag == 0)
{
NSLog(@"Touched Customers header");
if(!customerIsCollapsed)
customerIsCollapsed = YES;
else
customerIsCollapsed = NO;
}
else if(btnSection.tag == 1)
{
NSLog(@"Touched Site header");
if(!siteIsCollapsed)
siteIsCollapsed = YES;
else
siteIsCollapsed = NO;
}
[_tblSearchResults reloadData];
}
Мне просто интересно, пусть раздел рухнет и расширится анимированным или без анимации. Без анимации это будет выглядеть очень плохо. как мы можем добавить к нему анимацию? – Sam
@Sam, если вы используете что-то вроде '[self.tableView reloadSections: [NSIndexSet indexSetWithIndex: 0] withRowAnimation: UITableViewRowAnimationFade];' в методе коллапса/разворота он должен анимировать красиво. –
Таким образом, на основе решения «кнопка в заголовке», здесь чистая и минималистская реализация:
Вот код:
@interface MyTableViewController()
@property (nonatomic, strong) NSMutableIndexSet *collapsedSections;
@end
...
@implementation MyTableViewController
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (!self)
return;
self.collapsedSections = [NSMutableIndexSet indexSet];
return self;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// if section is collapsed
if ([self.collapsedSections containsIndex:section])
return 0;
// if section is expanded
#warning incomplete implementation
return [super tableView:tableView numberOfRowsInSection:section];
}
- (IBAction)toggleSectionHeader:(UIView *)sender
{
UITableView *tableView = self.tableView;
NSInteger section = sender.tag;
MyTableViewHeaderFooterView *headerView = (MyTableViewHeaderFooterView *)[self tableView:tableView viewForHeaderInSection:section];
if ([self.collapsedSections containsIndex:section])
{
// section is collapsed
headerView.button.selected = YES;
[self.collapsedSections removeIndex:section];
}
else
{
// section is expanded
headerView.button.selected = NO;
[self.collapsedSections addIndex:section];
}
[tableView beginUpdates];
[tableView reloadSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:UITableViewRowAnimationAutomatic];
[tableView endUpdates];
}
@end
// -------------------------------------------------------------------------------
// tableView:viewForHeaderInSection:
// -------------------------------------------------------------------------------
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIView *mView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 20, 20)];
[mView setBackgroundColor:[UIColor greenColor]];
UIImageView *logoView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 5, 20, 20)];
[logoView setImage:[UIImage imageNamed:@"carat.png"]];
[mView addSubview:logoView];
UIButton *bt = [UIButton buttonWithType:UIButtonTypeCustom];
[bt setFrame:CGRectMake(0, 0, 150, 30)];
[bt setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
[bt setTag:section];
[bt.titleLabel setFont:[UIFont systemFontOfSize:20]];
[bt.titleLabel setTextAlignment:NSTextAlignmentCenter];
[bt.titleLabel setTextColor:[UIColor blackColor]];
[bt setTitle: @"More Info" forState: UIControlStateNormal];
[bt addTarget:self action:@selector(addCell:) forControlEvents:UIControlEventTouchUpInside];
[mView addSubview:bt];
return mView;
}
#pragma mark - Suppose you want to hide/show section 2... then
#pragma mark add or remove the section on toggle the section header for more info
- (void)addCell:(UIButton *)bt{
// If section of more information
if(bt.tag == 2) {
// Initially more info is close, if more info is open
if(ifOpen) {
DLog(@"close More info");
// Set height of section
heightOfSection = 0.0f;
// Reset the parameter that more info is closed now
ifOpen = NO;
}else {
// Set height of section
heightOfSection = 45.0f;
// Reset the parameter that more info is closed now
DLog(@"open more info again");
ifOpen = YES;
}
//[self.tableView reloadData];
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:2] withRowAnimation:UITableViewRowAnimationFade];
}
}// end addCell
#pragma mark -
#pragma mark What will be the height of the section, Make it dynamic
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
if (indexPath.section == 2) {
return heightOfSection;
}else {
return 45.0f;
}
// vKj
This action will happen in your didSelectRowAtIndexPath, when you will try to hide or show number of cell in a section
first of all declare a global variable numberOfSectionInMoreInfo in .h file and in your viewDidLoad set suppose to numberOfSectionInMoreInfo = 4.
Now use following logic:
// More info link
if(row == 3) {
/*Logic: We are trying to hide/show the number of row into more information section */
NSString *log= [NSString stringWithFormat:@"Number of section in more %i",numberOfSectionInMoreInfo];
[objSpineCustomProtocol showAlertMessage:log];
// Check if the number of rows are open or close in view
if(numberOfSectionInMoreInfo > 4) {
// close the more info toggle
numberOfSectionInMoreInfo = 4;
}else {
// Open more info toggle
numberOfSectionInMoreInfo = 9;
}
//reload this section
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:1] withRowAnimation:UITableViewRowAnimationFade];
// vKj
Почему два ответа? Кажется, вы не представили два разных решения проблемы. – Cristik
я нашел еще один относительно простой способ решить эту проблему. Используя этот метод, нам не потребуется изменять нашу ячейку, которая почти всегда связана с индексом массива данных, что потенциально вызывает беспорядок в нашем контроллере представления.
Во-первых, мы добавим эти следующие свойства класса нашего контроллера:
@property (strong, nonatomic) NSMutableArray* collapsedSections;
@property (strong, nonatomic) NSMutableArray* sectionViews;
collapsedSections
сохранит свернутые номера раздела. sectionViews
сохранит наш пользовательский раздел.
Синтезировать его:
@synthesize collapsedSections;
@synthesize sectionViews;
Инициализировать его:
- (void) viewDidLoad
{
[super viewDidLoad];
self.collapsedSections = [NSMutableArray array];
self.sectionViews = [NSMutableArray array];
}
После этого, мы должны соединить наш UITableView, так что могут быть доступны из нашего класса контроллера представления:
@property (strong, nonatomic) IBOutlet UITableView *tblMain;
Подключите его к XIB для просмотра контроллера с помощью ctrl + drag
, как обычно.
Затем мы создаем вид, как пользовательский раздел заголовок для нашего представления таблицы путем выполнения этого UITableView делегата:
- (UIView*) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
// Create View
CGRect frame = CGRectZero;
frame.origin = CGPointZero;
frame.size.height = 30.f;
frame.size.width = tableView.bounds.size.width;
UIView* view = [[UIView alloc] initWithFrame:frame];
[view setBackgroundColor:[UIColor blueColor]];
// Add label for title
NSArray* titles = @[@"Title 1", @"Title 2", @"Title 3"];
NSString* selectedTitle = [titles objectAtIndex:section];
CGRect labelFrame = frame;
labelFrame.size.height = 30.f;
labelFrame.size.width -= 20.f;
labelFrame.origin.x += 10.f;
UILabel* titleLabel = [[UILabel alloc] initWithFrame:labelFrame];
[titleLabel setText:selectedTitle];
[titleLabel setTextColor:[UIColor whiteColor]];
[view addSubview:titleLabel];
// Add touch gesture
[self attachTapGestureToView:view];
// Save created view to our class property array
[self saveSectionView:view inSection:section];
return view;
}
Далее, мы реализуем метод, чтобы сохранить наш созданный ранее пользовательский заголовок раздела в классе собственности:
- (void) saveSectionView:(UIView*) view inSection:(NSInteger) section
{
NSInteger sectionCount = [self numberOfSectionsInTableView:[self tblMain]];
if(section < sectionCount)
{
if([[self sectionViews] indexOfObject:view] == NSNotFound)
{
[[self sectionViews] addObject:view];
}
}
}
Добавить UIGestureRecognizerDelegate
в наш контроллер представления .h файл:
@interface MyViewController : UIViewController<UITableViewDelegate, UITableViewDataSource, UIGestureRecognizerDelegate>
Затем мы создаем метод attachTapGestureToView:
- (void) attachTapGestureToView:(UIView*) view
{
UITapGestureRecognizer* tapAction = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onTap:)];
[tapAction setDelegate:self];
[view addGestureRecognizer:tapAction];
}
Выше метод добавит водопроводная жест распознаватель всем видом раздела мы создали ранее. Далее мы должны реализовать onTap:
селектор
- (void) onTap:(UITapGestureRecognizer*) gestureRecognizer
{
// Take view who attach current recognizer
UIView* sectionView = [gestureRecognizer view];
// [self sectionViews] is Array containing our custom section views
NSInteger section = [self sectionNumberOfView:sectionView];
// [self tblMain] is our connected IBOutlet table view
NSInteger sectionCount = [self numberOfSectionsInTableView:[self tblMain]];
// If section more than section count minus one set at last
section = section > (sectionCount - 1) ? 2 : section;
[self toggleCollapseSection:section];
}
Выше метод будет вызываться, когда пользователь нажмите любую из нашей точки зрения таблицы раздела. Этот метод ищет правильный номер раздела, основанный на нашем массиве sectionViews
, который мы создали ранее.
Кроме того, мы реализуем метод получения раздела wihch заголовка.
- (NSInteger) sectionNumberOfView:(UIView*) view
{
UILabel* label = [[view subviews] objectAtIndex:0];
NSInteger sectionNum = 0;
for(UIView* sectionView in [self sectionViews])
{
UILabel* sectionLabel = [[sectionView subviews] objectAtIndex:0];
//NSLog(@"Section: %d -> %@ vs %@", sectionNum, [label text], [sectionLabel text]);
if([[label text] isEqualToString:[sectionLabel text]])
{
return sectionNum;
}
sectionNum++;
}
return NSNotFound;
}
Далее, мы должны реализовать метод toggleCollapseSection:
- (void) toggleCollapseSection:(NSInteger) section
{
if([self isCollapsedSection:section])
{
[self removeCollapsedSection:section];
}
else
{
[self addCollapsedSection:section];
}
[[self tblMain] reloadSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:UITableViewRowAnimationFade];
}
Этот метод будет вставить/удалить номер раздела нашего collapsedSections
массива, который мы создали ранее. Когда номер раздела вставлен в этот массив, это означает, что раздел должен быть свернут и расширен, если в противном случае.
Далее мы реализуем removeCollapsedSection:
, addCollapsedSection:section
и isCollapsedSection:section
- (BOOL)isCollapsedSection:(NSInteger) section
{
for(NSNumber* existing in [self collapsedSections])
{
NSInteger current = [existing integerValue];
if(current == section)
{
return YES;
}
}
return NO;
}
- (void)removeCollapsedSection:(NSInteger) section
{
[[self collapsedSections] removeObjectIdenticalTo:[NSNumber numberWithInteger:section]];
}
- (void)addCollapsedSection:(NSInteger) section
{
[[self collapsedSections] addObject:[NSNumber numberWithInteger:section]];
}
Это три методы является только помощниками, чтобы сделать нам проще в обращении collapsedSections
массива.
Наконец, реализуйте этот делегат представления таблицы, чтобы наши пользовательские виды разделов выглядели красиво.
- (CGFloat) tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 30.f; // Same as each custom section view height
}
Надеюсь, это поможет.
У меня есть хорошее решение, вдохновленное Apple Table View Animations and Gestures. Я удалил ненужные части из образца Apple и перевел его в быстрый.
Я знаю, что ответ довольно длинный, но необходим весь код. К счастью, вы можете просто скопировать & мимо большей части кода и просто нужно сделать небольшую модификацию на шагах 1 и 3
1.создать SectionHeaderView.swift
и SectionHeaderView.xib
import UIKit
protocol SectionHeaderViewDelegate {
func sectionHeaderView(sectionHeaderView: SectionHeaderView, sectionOpened: Int)
func sectionHeaderView(sectionHeaderView: SectionHeaderView, sectionClosed: Int)
}
class SectionHeaderView: UITableViewHeaderFooterView {
var section: Int?
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var disclosureButton: UIButton!
@IBAction func toggleOpen() {
self.toggleOpenWithUserAction(true)
}
var delegate: SectionHeaderViewDelegate?
func toggleOpenWithUserAction(userAction: Bool) {
self.disclosureButton.selected = !self.disclosureButton.selected
if userAction {
if self.disclosureButton.selected {
self.delegate?.sectionHeaderView(self, sectionClosed: self.section!)
} else {
self.delegate?.sectionHeaderView(self, sectionOpened: self.section!)
}
}
}
override func awakeFromNib() {
var tapGesture: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "toggleOpen")
self.addGestureRecognizer(tapGesture)
// change the button image here, you can also set image via IB.
self.disclosureButton.setImage(UIImage(named: "arrow_up"), forState: UIControlState.Selected)
self.disclosureButton.setImage(UIImage(named: "arrow_down"), forState: UIControlState.Normal)
}
}
SectionHeaderView.xib
(вид с серым фоном) должно выглядеть примерно так в Tableview (вы можете настроить его в соответствии с вашими потребностями, конечно):
примечание:
а) toggleOpen
действие должно быть связано с disclosureButton
б) disclosureButton
и toggleOpen
действие не требуется. Вы можете удалить эти две вещи, если вам не нужна кнопка.
2.Create
import UIKit
class SectionInfo: NSObject {
var open: Bool = true
var itemsInSection: NSMutableArray = []
var sectionTitle: String?
init(itemsInSection: NSMutableArray, sectionTitle: String) {
self.itemsInSection = itemsInSection
self.sectionTitle = sectionTitle
}
}
3.in вашего Tableview
import UIKit
class TableViewController: UITableViewController, SectionHeaderViewDelegate {
let SectionHeaderViewIdentifier = "SectionHeaderViewIdentifier"
var sectionInfoArray: NSMutableArray = []
override func viewDidLoad() {
super.viewDidLoad()
let sectionHeaderNib: UINib = UINib(nibName: "SectionHeaderView", bundle: nil)
self.tableView.registerNib(sectionHeaderNib, forHeaderFooterViewReuseIdentifier: SectionHeaderViewIdentifier)
// you can change section height based on your needs
self.tableView.sectionHeaderHeight = 30
// You should set up your SectionInfo here
var firstSection: SectionInfo = SectionInfo(itemsInSection: ["1"], sectionTitle: "firstSection")
var secondSection: SectionInfo = SectionInfo(itemsInSection: ["2"], sectionTitle: "secondSection"))
sectionInfoArray.addObjectsFromArray([firstSection, secondSection])
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return sectionInfoArray.count
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if self.sectionInfoArray.count > 0 {
var sectionInfo: SectionInfo = sectionInfoArray[section] as! SectionInfo
if sectionInfo.open {
return sectionInfo.open ? sectionInfo.itemsInSection.count : 0
}
}
return 0
}
override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let sectionHeaderView: SectionHeaderView! = self.tableView.dequeueReusableHeaderFooterViewWithIdentifier(SectionHeaderViewIdentifier) as! SectionHeaderView
var sectionInfo: SectionInfo = sectionInfoArray[section] as! SectionInfo
sectionHeaderView.titleLabel.text = sectionInfo.sectionTitle
sectionHeaderView.section = section
sectionHeaderView.delegate = self
let backGroundView = UIView()
// you can customize the background color of the header here
backGroundView.backgroundColor = UIColor(red:0.89, green:0.89, blue:0.89, alpha:1)
sectionHeaderView.backgroundView = backGroundView
return sectionHeaderView
}
func sectionHeaderView(sectionHeaderView: SectionHeaderView, sectionOpened: Int) {
var sectionInfo: SectionInfo = sectionInfoArray[sectionOpened] as! SectionInfo
var countOfRowsToInsert = sectionInfo.itemsInSection.count
sectionInfo.open = true
var indexPathToInsert: NSMutableArray = NSMutableArray()
for i in 0..<countOfRowsToInsert {
indexPathToInsert.addObject(NSIndexPath(forRow: i, inSection: sectionOpened))
}
self.tableView.insertRowsAtIndexPaths(indexPathToInsert as [AnyObject], withRowAnimation: .Top)
}
func sectionHeaderView(sectionHeaderView: SectionHeaderView, sectionClosed: Int) {
var sectionInfo: SectionInfo = sectionInfoArray[sectionClosed] as! SectionInfo
var countOfRowsToDelete = sectionInfo.itemsInSection.count
sectionInfo.open = false
if countOfRowsToDelete > 0 {
var indexPathToDelete: NSMutableArray = NSMutableArray()
for i in 0..<countOfRowsToDelete {
indexPathToDelete.addObject(NSIndexPath(forRow: i, inSection: sectionClosed))
}
self.tableView.deleteRowsAtIndexPaths(indexPathToDelete as [AnyObject], withRowAnimation: .Top)
}
}
}
спасибо за то, что вы сделали это! С небольшим примером проекта на github было бы еще лучше ответить –
Спасибо за предоставление подробного ответа. Пример проекта будет лучше. –
Для осуществления раздела складных таблиц в прошивке, магия, как контролировать количество строк для каждой секции, или мы можем управлять высотой строк для каждого раздела.
Кроме того, нам нужно настроить заголовок раздела, чтобы мы могли прослушивать событие касания из области заголовка (будь то кнопка или весь заголовок).
Как бороться с заголовком? Это очень просто, мы расширим класс UITableViewCell и сделать пользовательскую ячейку заголовка следующим образом:
import UIKit
class CollapsibleTableViewHeader: UITableViewCell {
@IBOutlet var titleLabel: UILabel!
@IBOutlet var toggleButton: UIButton!
}
затем использовать viewForHeaderInSection подключить ячейку заголовка:
override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = tableView.dequeueReusableCellWithIdentifier("header") as! CollapsibleTableViewHeader
header.titleLabel.text = sections[section].name
header.toggleButton.tag = section
header.toggleButton.addTarget(self, action: #selector(CollapsibleTableViewController.toggleCollapse), forControlEvents: .TouchUpInside)
header.toggleButton.rotate(sections[section].collapsed! ? 0.0 : CGFloat(M_PI_2))
return header.contentView
}
помнить, что мы должны вернуть contentView потому что эта функция ожидает возвращения UIView.
Теперь давайте разбираться с разборной части, здесь есть функция переключения, которая переключает складную опору каждой секции:
func toggleCollapse(sender: UIButton) {
let section = sender.tag
let collapsed = sections[section].collapsed
// Toggle collapse
sections[section].collapsed = !collapsed
// Reload section
tableView.reloadSections(NSIndexSet(index: section), withRowAnimation: .Automatic)
}
зависит от того, как управлять данными раздела, в этом случае, у меня есть раздел что-то данные, как это:
struct Section {
var name: String!
var items: [String]!
var collapsed: Bool!
init(name: String, items: [String]) {
self.name = name
self.items = items
self.collapsed = false
}
}
var sections = [Section]()
sections = [
Section(name: "Mac", items: ["MacBook", "MacBook Air", "MacBook Pro", "iMac", "Mac Pro", "Mac mini", "Accessories", "OS X El Capitan"]),
Section(name: "iPad", items: ["iPad Pro", "iPad Air 2", "iPad mini 4", "Accessories"]),
Section(name: "iPhone", items: ["iPhone 6s", "iPhone 6", "iPhone SE", "Accessories"])
]
наконец, что нам нужно сделать, это на основе разборной опоры каждой секции, контролировать количество строк этого раздела:
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (sections[section].collapsed!) ? 0 : sections[section].items.count
}
У меня есть полностью рабочий пример на моем Github: https://github.com/jeantimex/ios-swift-collapsible-table-section
Если вы хотите реализовать сборно-разборные секции в таблице сгруппированы в стиле, у меня есть еще один демо с исходным кодом здесь: https://github.com/jeantimex/ios-swift-collapsible-table-section-in-grouped-section
Надеюсь, что это поможет.
Привет, Я сделал свой собственный раздел заголовка в файле xib и зарегистрировал nib для моего Table View Controller. Когда я удаляю раздел и пытаюсь развернуть/свернуть снова, я получаю фатальную ошибку, указав, что индекс выходит за пределы диапазона. Есть ли способ исправить это? Благодаря! – iamhx
Очень хорошее и чистое решение! – Joel
Некоторые примеры кода для анимации в расширении/действие коллапса с помощью заголовка вид раздела таблицы обеспечивается Apple, здесь: Table View анимаций и Жесты
Ключ к этому подходу к реализации - (UIView *) Tableview: (UITableView *) tableView viewForHeaderInSection: (NSInteger) и возвращает пользовательский UIView, который включает в себя кнопку (обычно такой же размер, как и заголовок). Подклассифицируя UIView и используя это для представления заголовка (как это делает этот пример), вы можете легко сохранить дополнительные данные, такие как номер раздела.
Я использовал NSDictionary как источник данных, это выглядит как много кода, но это очень просто и работает очень хорошо! how looks here
Я создал перечисление для секций
typedef NS_ENUM(NSUInteger, TableViewSection) {
TableViewSection0 = 0,
TableViewSection1,
TableViewSection2,
TableViewSectionCount
};
участки недвижимость:
@property (nonatomic, strong) NSMutableDictionary * sectionsDisctionary;
Метод, возвращающий мои разделы:
-(NSArray <NSNumber *> *)sections{
return @[@(TableViewSection0), @(TableViewSection1), @(TableViewSection2)];
}
А затем настроить мой soruce данные:
-(void)loadAndSetupData{
self.sectionsDisctionary = [NSMutableDictionary dictionary];
NSArray * sections = [self sections];
for (NSNumber * section in sections) {
NSArray * sectionObjects = [self objectsForSection:section.integerValue];
[self.sectionsDisctionary setObject:[NSMutableDictionary dictionaryWithDictionary:@{@"visible" : @YES, @"objects" : sectionObjects}] forKey:section];
}
}
-(NSArray *)objectsForSection:(NSInteger)section{
NSArray * objects;
switch (section) {
case TableViewSection0:
objects = @[] // objects for section 0;
break;
case TableViewSection1:
objects = @[] // objects for section 1;
break;
case TableViewSection2:
objects = @[] // objects for section 2;
break;
default:
break;
}
return objects;
}
Следующие методы помогут вам знать, когда открыт раздел, и как реагировать на Tableview источника данных:
Реагируйте раздел источника данных:
/**
* Asks the delegate for a view object to display in the header of the specified section of the table view.
*
* @param tableView The table-view object asking for the view object.
* @param section An index number identifying a section of tableView .
*
* @return A view object to be displayed in the header of section .
*/
- (UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
NSString * headerName = [self titleForSection:section];
YourCustomSectionHeaderClass * header = (YourCustomSectionHeaderClass *)[tableView dequeueReusableHeaderFooterViewWithIdentifier:YourCustomSectionHeaderClassIdentifier];
[header setTag:section];
[header addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)]];
header.title = headerName;
header.collapsed = [self sectionIsOpened:section];
return header;
}
/**
* Asks the data source to return the number of sections in the table view
*
* @param An object representing the table view requesting this information.
* @return The number of sections in tableView.
*/
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
// Return the number of sections.
return self.sectionsDisctionary.count;
}
/**
* Tells the data source to return the number of rows in a given section of a table view
*
* @param tableView: The table-view object requesting this information.
* @param section: An index number identifying a section in tableView.
* @return The number of rows in section.
*/
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
BOOL sectionOpened = [self sectionIsOpened:section];
return sectionOpened ? [[self objectsForSection:section] count] : 0;
}
Инструменты:
/**
Return the section at the given index
@param index the index
@return The section in the given index
*/
-(NSMutableDictionary *)sectionAtIndex:(NSInteger)index{
NSString * asectionKey = [self.sectionsDisctionary.allKeys objectAtIndex:index];
return [self.sectionsDisctionary objectForKey:asectionKey];
}
/**
Check if a section is currently opened
@param section the section to check
@return YES if is opened
*/
-(BOOL)sectionIsOpened:(NSInteger)section{
NSDictionary * asection = [self sectionAtIndex:section];
BOOL sectionOpened = [[asection objectForKey:@"visible"] boolValue];
return sectionOpened;
}
/**
Handle the section tap
@param tap the UITapGestureRecognizer
*/
- (void)handleTapGesture:(UITapGestureRecognizer*)tap{
NSInteger index = tap.view.tag;
[self toggleSection:index];
}
Точка обзора видимости
/**
Switch the state of the section at the given section number
@param section the section number
*/
-(void)toggleSection:(NSInteger)section{
if (index >= 0){
NSMutableDictionary * asection = [self sectionAtIndex:section];
[asection setObject:@(![self sectionIsOpened:section]) forKey:@"visible"];
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:UITableViewRowAnimationFade];
}
}
Расширяя this ответ написан в Objective C, я писал для тех, кто пишет в Swift
Идея заключается в том, чтобы использовать секции в таблице и установите количество строк в разделе 1 (развалилась) и 3 (расширенный), когда первая строка в этой секции сливают
таблица решает, сколько строк рисовать на основе массив булевых значений
Вам нужно создать две строки в раскадровке и дать им идентификаторы повторного использования «CollapsingRow» и «GroupHeading»
import UIKit
class CollapsingTVC:UITableViewController{
var sectionVisibilityArray:[Bool]!// Array index corresponds to section in table
override func viewDidLoad(){
super.viewDidLoad()
sectionVisibilityArray = [false,false,false]
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
override func numberOfSections(in tableView: UITableView) -> Int{
return sectionVisibilityArray.count
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat{
return 0
}
// numberOfRowsInSection - Get count of entries
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var rowsToShow:Int = 0
if(sectionVisibilityArray[section]){
rowsToShow = 3 // Or however many rows should be displayed in that section
}else{
rowsToShow = 1
}
return rowsToShow
}// numberOfRowsInSection
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
if(indexPath.row == 0){
if(sectionVisibilityArray[indexPath.section]){
sectionVisibilityArray[indexPath.section] = false
}else{
sectionVisibilityArray[indexPath.section] = true
}
self.tableView.reloadSections([indexPath.section], with: .automatic)
}
}
// cellForRowAtIndexPath - Get table cell corresponding to this IndexPath
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell:UITableViewCell
if(indexPath.row == 0){
cell = tableView.dequeueReusableCell(withIdentifier: "GroupHeading", for: indexPath as IndexPath)
}else{
cell = tableView.dequeueReusableCell(withIdentifier: "CollapsingRow", for: indexPath as IndexPath)
}
return cell
}// cellForRowAtIndexPath
}
Попробуйте следующее: http://stackoverflow.com/questions/33186659/how-to-create-drop-down-list-in-uitableview-in-ios –
[Отметьте мой ответ так же для пользовательского заголовка ] (http://stackoverflow.com/questions/18203434/uitableview-with-open-closed-sections/40932319#40932319) http://stackoverflow.com/questions/18203434/uitableview-with-open-closed-sections/40932319 # 40932319 –