展开和折叠 tableView 部分 iOS?
Expanding and collapsing tableView sections iOS?
我能够成功展开和折叠 tableView 部分,但是我无法对单个部分执行此操作,因此 far.So 所有部分同时折叠或展开,这是因为我调用 [tableView reloadData]
.那么如何展开或折叠特定部分?
这是我目前的做法。
-(UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
headerLabel = [[UILabel alloc]init];
headerLabel.tag = section;
headerLabel.userInteractionEnabled = YES;
headerLabel.backgroundColor = [[UIColor grayColor]colorWithAlphaComponent:0.2];
headerLabel.text = [menuCategoryArray objectAtIndex:section];
headerLabel.frame = CGRectMake(5, 0, tableView.tableHeaderView.frame.size.width, tableView.tableHeaderView.frame.size.height);
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(headerClicked:)];
tapGesture.cancelsTouchesInView = NO;
[headerLabel addGestureRecognizer:tapGesture];
return headerLabel;
}
-(void)headerClicked:(UIGestureRecognizer*)sender
{
if (!isShowingList) {
isShowingList=YES;
[self.menuTableView reloadData];
UILabel *lbl = (UILabel*)sender.view;
NSLog(@"header no : %d", lbl.tag);
}else{
isShowingList=NO;
[self.menuTableView reloadData];
UILabel *lbl = (UILabel*)sender.view;
NSLog(@"header no : %d", lbl.tag);
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
if (isShowingList) {
return [[[[jsonArray valueForKey:@"menus"] valueForKey:@"menuName"] objectAtIndex:section] count];
}else{
return 0;
}
return 0;
}
你真的最好不要使用 'tableView update block'。请查看此 viewController 以获得我最近发布的答案。 updateBlock 允许您操作一些变量或其他影响数据源的变量,并指示 table 到 add/remove rows/sections 以反映该更改。请注意,当您调用 endUpdates 方法时,table 不得与模型冲突,否则您将得到一个异常。
#import "ViewController.h"
//dont worry, the header is empty except for import <UIKit/UIKit.h>, this is a subclass on UIViewController
@interface ViewController ()<UITableViewDataSource, UITableViewDelegate>
@property (weak, nonatomic) UITableView *tableView;
@end
@implementation ViewController
{
//ivars
BOOL sectionIsOpen[4]; //we will use this BOOL array to keep track of the open/closed state for each section. Obviously I have the number of sections fixed at 4 here, but you could make a more dynamic array with malloc() if neccesary..
}
- (void)viewDidLoad {
[super viewDidLoad];
UITableView *tv = [[UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStyleGrouped];
tv.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
tv.dataSource = self;
tv.delegate = self;
[self.view addSubview:tv];
self.tableView = tv;
// Do any additional setup after loading the view, typically from a nib.
}
#pragma mark - UITableViewDataSource
-(NSInteger )numberOfSectionsInTableView:(UITableView *)tableView{
return 4;
}
-(NSInteger )tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return ((sectionIsOpen[section]) ? [self numberOfRowsInSection:section] : 0);
}
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
//put your switch() here...
return [NSString stringWithFormat:@"I am section %i", (int)section ];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *cellId = @"cellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId];
if (!cell) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellId];
}
//etc etc decorate your cell...
cell.textLabel.text = [NSString stringWithFormat:@"cell %i / %i", (int)indexPath.section, (int)indexPath.row ];
return cell;
}
#pragma mark - UITableViewDelegate
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
const CGRect fr = CGRectMake(0, 0, 320.0, 40.0 );
UIButton *btn = [[UIButton alloc]initWithFrame:fr];
[btn setTitle:[self tableView:tableView titleForHeaderInSection:section] forState:UIControlStateNormal ];
[btn setTag:section];
[btn addTarget:self action:@selector(sectionOpenToggle:) forControlEvents:UIControlEventTouchUpInside];
// add an image, colour etc if you like
return btn;
}
#pragma mark - tableViewHelpers
//the number of rows in sectionX when it is open...
-(NSInteger )numberOfRowsInSection:(NSInteger )section{
//get your count from your model
return section + 1;
}
//opening/closing a section
-(void )setSection:(NSInteger )section toOpen:(BOOL )open{
if (open != sectionIsOpen[section]) {
//build an array of indexPath objects
NSMutableArray *indxPths = [NSMutableArray array];
for (NSInteger row = 0; row < [self numberOfRowsInSection:section]; row ++) {
[indxPths addObject: [NSIndexPath indexPathForRow:row inSection:section ]
];
}
[self.tableView beginUpdates];
if (open) {
[self.tableView insertRowsAtIndexPaths:indxPths withRowAnimation:UITableViewRowAnimationFade];
//nb there is a large ENUM of tableViewRowAnimation types to experiment with..
}else{
[self.tableView deleteRowsAtIndexPaths:indxPths withRowAnimation:UITableViewRowAnimationFade];
}
sectionIsOpen[section] = open;
[self.tableView endUpdates];
}
}
-(void )sectionOpenToggle:(id )sender{
[self setSection:[sender tag] toOpen: !sectionIsOpen[[sender tag]] ];
}
// open/close all sections.
-(void )setAllSectionsOpen:(BOOL )open{
for (NSInteger section = 0; section < [self numberOfSectionsInTableView:self.tableView]; section ++) {
[self setSection:section toOpen:open];
}
}
//these two for your convenience, hook up to navbar items etc..
-(IBAction)openAllSections:(id)sender{
[self setAllSectionsOpen:YES];
}
-(IBAction)closeAllSections:(id)sender{
[self setAllSectionsOpen:NO];
}
@end
先取isShowingList
为
@property (nonatomic, strong) NSMutableArray *isShowingList;
为了识别之前打开的部分,您需要另一个 属性
@property (nonatomic, assign) NSInteger openSectionIndex;
当您初始化数据时,在您的情况下为 isShowingList,在重新加载之前初始化 isShowingList
数组 table
self.isShowingList = [NSMutableArray array];
if (jsonArray && [jsonArray valueForKey:@"menus"] && [[jsonArray valueForKey:@"menus"] valueForKey:@"menuName"]) {
for (int i = 0; i < [[[jsonArray valueForKey:@"menus"] valueForKey:@"menuName"] count]; i++) {
[self.isShowingList addObject:[NSNumber numberWithBool:NO]];
}
}
并像这样在 viewDidLoad()
中初始化 openSectionIndex
self.openSectionIndex = NSNotFound;
并且您的代码应该像这样更改
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if ([[self.isShowingList objectAtIndex:section] boolValue]) {
return [[[[jsonArray valueForKey:@"menus"] valueForKey:@"menuName"] objectAtIndex:section] count];
} else {
return 0;
}
return 0;
}
-(void)headerClicked:(UIGestureRecognizer*)sender {
UILabel *lbl = (UILabel*)sender.view;
NSLog(@"header no : %d", lbl.tag);
if ([[self.isShowingList objectAtIndex:lbl.tag] boolValue]) {
[self closeSection:lbl.tag];
} else {
[self openSection:lbl.tag];
}
}
//methods for expanding and collapsing sections
- (void)openSection:(NSInteger)section {
[self.isShowingList replaceObjectAtIndex:section withObject:[NSNumber numberWithBool:YES]];
NSInteger countOfRowsToInsert = [[[[jsonArray valueForKey:@"menus"] valueForKey:@"menuName"] objectAtIndex:section] count];
NSMutableArray *indexPathsToInsert = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i < countOfRowsToInsert; i++) {
[indexPathsToInsert addObject:[NSIndexPath indexPathForRow:i inSection:section]];
}
NSMutableArray *indexPathsToDelete = [[NSMutableArray alloc] init];
NSInteger previousOpenSectionIndex = self.openSectionIndex;
if (previousOpenSectionIndex != NSNotFound) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.menuTableView reloadSections:[NSIndexSet indexSetWithIndex:previousOpenSectionIndex] withRowAnimation:UITableViewRowAnimationNone];
});
[self.isShowingList replaceObjectAtIndex:previousOpenSectionIndex withObject:[NSNumber numberWithBool:NO]];
NSInteger countOfRowsToDelete = [[[[jsonArray valueForKey:@"menus"] valueForKey:@"menuName"] objectAtIndex:previousOpenSectionIndex] count];
for (NSInteger i = 0; i < countOfRowsToDelete; i++) {
[indexPathsToDelete addObject:[NSIndexPath indexPathForRow:i inSection:previousOpenSectionIndex]];
}
}
// Apply the updates.
[self.menuTableView beginUpdates];
[self.menuTableView insertRowsAtIndexPaths:indexPathsToInsert withRowAnimation:UITableViewRowAnimationAutomatic];
[self.menuTableView deleteRowsAtIndexPaths:indexPathsToDelete withRowAnimation:UITableViewRowAnimationAutomatic];
[self.menuTableView endUpdates];
self.openSectionIndex = section;
}
- (void)closeSection:(NSInteger)section {
[self.isShowingList replaceObjectAtIndex:section withObject:[NSNumber numberWithBool:NO]];
NSInteger countOfRowsToDelete = [self.menuTableView numberOfRowsInSection:section];
if (countOfRowsToDelete > 0) {
NSMutableArray *indexPathsToDelete = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i < countOfRowsToInsert; i++) {
[indexPathsToDelete addObject:[NSIndexPath indexPathForRow:i inSection:section]];
}
[self.menuTableView deleteRowsAtIndexPaths:indexPathsToDelete withRowAnimation:UITableViewRowAnimationTop];
}
self.openSectionIndex = NSNotFound;
}
我能够成功展开和折叠 tableView 部分,但是我无法对单个部分执行此操作,因此 far.So 所有部分同时折叠或展开,这是因为我调用 [tableView reloadData]
.那么如何展开或折叠特定部分?
这是我目前的做法。
-(UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
headerLabel = [[UILabel alloc]init];
headerLabel.tag = section;
headerLabel.userInteractionEnabled = YES;
headerLabel.backgroundColor = [[UIColor grayColor]colorWithAlphaComponent:0.2];
headerLabel.text = [menuCategoryArray objectAtIndex:section];
headerLabel.frame = CGRectMake(5, 0, tableView.tableHeaderView.frame.size.width, tableView.tableHeaderView.frame.size.height);
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(headerClicked:)];
tapGesture.cancelsTouchesInView = NO;
[headerLabel addGestureRecognizer:tapGesture];
return headerLabel;
}
-(void)headerClicked:(UIGestureRecognizer*)sender
{
if (!isShowingList) {
isShowingList=YES;
[self.menuTableView reloadData];
UILabel *lbl = (UILabel*)sender.view;
NSLog(@"header no : %d", lbl.tag);
}else{
isShowingList=NO;
[self.menuTableView reloadData];
UILabel *lbl = (UILabel*)sender.view;
NSLog(@"header no : %d", lbl.tag);
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
if (isShowingList) {
return [[[[jsonArray valueForKey:@"menus"] valueForKey:@"menuName"] objectAtIndex:section] count];
}else{
return 0;
}
return 0;
}
你真的最好不要使用 'tableView update block'。请查看此 viewController 以获得我最近发布的答案。 updateBlock 允许您操作一些变量或其他影响数据源的变量,并指示 table 到 add/remove rows/sections 以反映该更改。请注意,当您调用 endUpdates 方法时,table 不得与模型冲突,否则您将得到一个异常。
#import "ViewController.h"
//dont worry, the header is empty except for import <UIKit/UIKit.h>, this is a subclass on UIViewController
@interface ViewController ()<UITableViewDataSource, UITableViewDelegate>
@property (weak, nonatomic) UITableView *tableView;
@end
@implementation ViewController
{
//ivars
BOOL sectionIsOpen[4]; //we will use this BOOL array to keep track of the open/closed state for each section. Obviously I have the number of sections fixed at 4 here, but you could make a more dynamic array with malloc() if neccesary..
}
- (void)viewDidLoad {
[super viewDidLoad];
UITableView *tv = [[UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStyleGrouped];
tv.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
tv.dataSource = self;
tv.delegate = self;
[self.view addSubview:tv];
self.tableView = tv;
// Do any additional setup after loading the view, typically from a nib.
}
#pragma mark - UITableViewDataSource
-(NSInteger )numberOfSectionsInTableView:(UITableView *)tableView{
return 4;
}
-(NSInteger )tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return ((sectionIsOpen[section]) ? [self numberOfRowsInSection:section] : 0);
}
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
//put your switch() here...
return [NSString stringWithFormat:@"I am section %i", (int)section ];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *cellId = @"cellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId];
if (!cell) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellId];
}
//etc etc decorate your cell...
cell.textLabel.text = [NSString stringWithFormat:@"cell %i / %i", (int)indexPath.section, (int)indexPath.row ];
return cell;
}
#pragma mark - UITableViewDelegate
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
const CGRect fr = CGRectMake(0, 0, 320.0, 40.0 );
UIButton *btn = [[UIButton alloc]initWithFrame:fr];
[btn setTitle:[self tableView:tableView titleForHeaderInSection:section] forState:UIControlStateNormal ];
[btn setTag:section];
[btn addTarget:self action:@selector(sectionOpenToggle:) forControlEvents:UIControlEventTouchUpInside];
// add an image, colour etc if you like
return btn;
}
#pragma mark - tableViewHelpers
//the number of rows in sectionX when it is open...
-(NSInteger )numberOfRowsInSection:(NSInteger )section{
//get your count from your model
return section + 1;
}
//opening/closing a section
-(void )setSection:(NSInteger )section toOpen:(BOOL )open{
if (open != sectionIsOpen[section]) {
//build an array of indexPath objects
NSMutableArray *indxPths = [NSMutableArray array];
for (NSInteger row = 0; row < [self numberOfRowsInSection:section]; row ++) {
[indxPths addObject: [NSIndexPath indexPathForRow:row inSection:section ]
];
}
[self.tableView beginUpdates];
if (open) {
[self.tableView insertRowsAtIndexPaths:indxPths withRowAnimation:UITableViewRowAnimationFade];
//nb there is a large ENUM of tableViewRowAnimation types to experiment with..
}else{
[self.tableView deleteRowsAtIndexPaths:indxPths withRowAnimation:UITableViewRowAnimationFade];
}
sectionIsOpen[section] = open;
[self.tableView endUpdates];
}
}
-(void )sectionOpenToggle:(id )sender{
[self setSection:[sender tag] toOpen: !sectionIsOpen[[sender tag]] ];
}
// open/close all sections.
-(void )setAllSectionsOpen:(BOOL )open{
for (NSInteger section = 0; section < [self numberOfSectionsInTableView:self.tableView]; section ++) {
[self setSection:section toOpen:open];
}
}
//these two for your convenience, hook up to navbar items etc..
-(IBAction)openAllSections:(id)sender{
[self setAllSectionsOpen:YES];
}
-(IBAction)closeAllSections:(id)sender{
[self setAllSectionsOpen:NO];
}
@end
先取isShowingList
为
@property (nonatomic, strong) NSMutableArray *isShowingList;
为了识别之前打开的部分,您需要另一个 属性
@property (nonatomic, assign) NSInteger openSectionIndex;
当您初始化数据时,在您的情况下为 isShowingList,在重新加载之前初始化 isShowingList
数组 table
self.isShowingList = [NSMutableArray array];
if (jsonArray && [jsonArray valueForKey:@"menus"] && [[jsonArray valueForKey:@"menus"] valueForKey:@"menuName"]) {
for (int i = 0; i < [[[jsonArray valueForKey:@"menus"] valueForKey:@"menuName"] count]; i++) {
[self.isShowingList addObject:[NSNumber numberWithBool:NO]];
}
}
并像这样在 viewDidLoad()
中初始化 openSectionIndex
self.openSectionIndex = NSNotFound;
并且您的代码应该像这样更改
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if ([[self.isShowingList objectAtIndex:section] boolValue]) {
return [[[[jsonArray valueForKey:@"menus"] valueForKey:@"menuName"] objectAtIndex:section] count];
} else {
return 0;
}
return 0;
}
-(void)headerClicked:(UIGestureRecognizer*)sender {
UILabel *lbl = (UILabel*)sender.view;
NSLog(@"header no : %d", lbl.tag);
if ([[self.isShowingList objectAtIndex:lbl.tag] boolValue]) {
[self closeSection:lbl.tag];
} else {
[self openSection:lbl.tag];
}
}
//methods for expanding and collapsing sections
- (void)openSection:(NSInteger)section {
[self.isShowingList replaceObjectAtIndex:section withObject:[NSNumber numberWithBool:YES]];
NSInteger countOfRowsToInsert = [[[[jsonArray valueForKey:@"menus"] valueForKey:@"menuName"] objectAtIndex:section] count];
NSMutableArray *indexPathsToInsert = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i < countOfRowsToInsert; i++) {
[indexPathsToInsert addObject:[NSIndexPath indexPathForRow:i inSection:section]];
}
NSMutableArray *indexPathsToDelete = [[NSMutableArray alloc] init];
NSInteger previousOpenSectionIndex = self.openSectionIndex;
if (previousOpenSectionIndex != NSNotFound) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.menuTableView reloadSections:[NSIndexSet indexSetWithIndex:previousOpenSectionIndex] withRowAnimation:UITableViewRowAnimationNone];
});
[self.isShowingList replaceObjectAtIndex:previousOpenSectionIndex withObject:[NSNumber numberWithBool:NO]];
NSInteger countOfRowsToDelete = [[[[jsonArray valueForKey:@"menus"] valueForKey:@"menuName"] objectAtIndex:previousOpenSectionIndex] count];
for (NSInteger i = 0; i < countOfRowsToDelete; i++) {
[indexPathsToDelete addObject:[NSIndexPath indexPathForRow:i inSection:previousOpenSectionIndex]];
}
}
// Apply the updates.
[self.menuTableView beginUpdates];
[self.menuTableView insertRowsAtIndexPaths:indexPathsToInsert withRowAnimation:UITableViewRowAnimationAutomatic];
[self.menuTableView deleteRowsAtIndexPaths:indexPathsToDelete withRowAnimation:UITableViewRowAnimationAutomatic];
[self.menuTableView endUpdates];
self.openSectionIndex = section;
}
- (void)closeSection:(NSInteger)section {
[self.isShowingList replaceObjectAtIndex:section withObject:[NSNumber numberWithBool:NO]];
NSInteger countOfRowsToDelete = [self.menuTableView numberOfRowsInSection:section];
if (countOfRowsToDelete > 0) {
NSMutableArray *indexPathsToDelete = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i < countOfRowsToInsert; i++) {
[indexPathsToDelete addObject:[NSIndexPath indexPathForRow:i inSection:section]];
}
[self.menuTableView deleteRowsAtIndexPaths:indexPathsToDelete withRowAnimation:UITableViewRowAnimationTop];
}
self.openSectionIndex = NSNotFound;
}