您的位置:首页 > 其它

TableView的点击出现和关闭下拉菜单的实现

2015-04-03 09:55 513 查看
之前开发过程中总是会遇到很多问题,百度后会根据大家写的博客找到解决方法,不得不说还是非常感谢各位博主的开源奉献的精神。所以我也开个博客,把在项目开发中的一些点点滴滴记录下来。目前项目中要实现一个功能,就是从服务器获取数据,同时实现上拉和下拉功能,在点击一行后会出现下拉菜单,再点击后会关闭下拉菜单。我觉得这样得功能在很多项目里是很常见的,所以我写了一个单机版的,大家可以直接把我的代码拿去修改一下就可以了。这篇文章就先写如何实现显示下拉菜单功能,至于TableView的上拉刷新和下拉加载功能,我会在下一篇博客写到。

首先我们要在视图控制器内创建4个属性:

@interface
ViewController ()<UITableViewDataSource,UITableViewDelegate,CustomerInfoSectionViewDelegate>

@property(nonatomic,strong)UITableView *listTableView;

@property(nonatomic,strong)NSMutableArray *dataArray;

@property (assign,
nonatomic) NSInteger openedSection;

@property(nonatomic,strong)NSArray *cellArray;

@end


其中listTableView就是我们要展示的TableView,dataArray是用来获取显示数据的数组,cellArray是用来显示下拉菜单数据的数组,openedSection是记录已经打开得section的index,便于在后面打开别的section时关闭之前打开的section下拉菜单。

然后我们初始化数据和控件:

- (void)viewDidLoad {

[super
viewDidLoad];

self.openedSection =
NSNotFound;

_dataArray = [[NSMutableArray
alloc]init];

//_listTableView要显示的section数目

for (int i =
0; i < 5; i++)
{

NSMutableDictionary *dic = [[NSMutableDictionary
alloc]init];
[dic
setValue:@"55555"
forKey:@"detail"];
[_dataArray
addObject:dic];

}

_cellArray =
@[@"1",@"2",@"3"];//下拉显示的cell的数量

self.view.backgroundColor =
UIColorFromRGB(0xf8f8f8);

_listTableView = [[UITableView
alloc]initWithFrame:CGRectMake(10.f,
20.f,CGRectGetWidth([UIScreen
mainScreen].applicationFrame) -
20.f, [[UIScreen
mainScreen] applicationFrame].size.height -
20.f)
style:UITableViewStylePlain];

_listTableView.delegate =
self;

_listTableView.dataSource =
self;

_listTableView.separatorStyle =
UITableViewCellSeparatorStyleNone;

[_listTableView
registerClass:[ViewOfCustomerTableViewCell
class]
forCellReuseIdentifier:ViewOfCustomerTableViewCellIdentifier];

_listTableView.allowsSelection =
YES;

_listTableView.backgroundColor = [UIColor
clearColor];

[self.view
addSubview:_listTableView];

}

在要显示的TableView中要展示数据,我们要自定义我们想要的section的视图和cell。首先展示出来的时section,然后点击section会显示cell。新建一个

CustomerInfoSectionView:

在CustomerInfoSectionView.h中添加属性和方法:

#import <UIKit/UIKit.h>

@protocol CustomerInfoSectionViewDelegate;

@interface CustomerInfoSectionView :
UIView

@property(nonatomic,strong)UILabel *nameLabel;

@property(nonatomic,strong)UILabel *managerNameLabel;

@property(nonatomic,strong)UILabel *departmentLabel;

@property(nonatomic,strong)UILabel *addressLabel;

@property (assign,
nonatomic) BOOL isOpen;

@property (nonatomic,
assign)
id <CustomerInfoSectionViewDelegate> delegate;

@property (nonatomic,
assign) NSInteger section;

@property (strong,
nonatomic) UIImageView *arrow;
-(void)toggleOpen:(id)sender;
-(void)toggleOpenWithUserAction:(BOOL)userAction;
- (void)initWithNameLabel:(NSString*)name ManagerNameLabel:(NSString*)managerName
DepartmentLabel:(NSString*)department AddressLabel:(NSString*)address section:(NSInteger)sectionNumber delegate:(id
<CustomerInfoSectionViewDelegate>)delegate;

@end

@protocol CustomerInfoSectionViewDelegate <NSObject>

@optional
-(void)sectionHeaderView:(CustomerInfoSectionView*)sectionHeaderView sectionOpened:(NSInteger)section;
-(void)sectionHeaderView:(CustomerInfoSectionView*)sectionHeaderView sectionClosed:(NSInteger)section;

@end

-(void)toggleOpenWithUserAction:(BOOL)userAction是点击section的方法,在这个方法中我们通过判断当前点击的section是否打开的状态来设置箭头图标的方向,并且调用委托方法-(void)sectionHeaderView:(CustomerInfoSectionView*)sectionHeaderView
sectionOpened:(NSInteger)section

在CustomerInfoSectionView.m中,具体实现点击方法和初始化界面,初始化界面我就不写了,直接上重要代码,其他的可以在我的demo里看:

-(void)toggleOpen:(id)sender {

[self
toggleOpenWithUserAction:YES];
}

-(void)toggleOpenWithUserAction:(BOOL)userAction {

//判断所在sectionView是否打开来旋转箭头

_isOpen = !_isOpen;

if (userAction) {

if (_isOpen) {

[UIView
animateWithDuration:.3
animations:^{

self.arrow.transform
= CGAffineTransformMakeRotation(M_PI);
}];

if ([self.delegate
respondsToSelector:@selector(sectionHeaderView:sectionOpened:)]) {

[self.delegate
sectionHeaderView:self
sectionOpened:self.section];
}
}

else {

[UIView
animateWithDuration:.3
animations:^{

self.arrow.transform =
CGAffineTransformIdentity;
}];

if ([self.delegate
respondsToSelector:@selector(sectionHeaderView:sectionClosed:)]) {

[self.delegate
sectionHeaderView:self
sectionClosed:self.section];
}
}
}
}

自定义完section的view后,回到之前的视图控制器,在tableview的委托方法中:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{

return [_dataArray
count];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{

//根据字典里的MENU_OPENED_KEY的值来显示或者隐藏下拉的cell

NSMutableDictionary *sectionInfo = [_dataArray
objectAtIndex:section];

return [[sectionInfo
objectForKey:MENU_OPENED_KEY]
boolValue] ? [_cellArray
count] : 0;
}

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{

return 50.f;
}

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{

NSMutableDictionary *dic = [_dataArray
objectAtIndex:section];

CustomerInfoSectionView *view = [dic
objectForKey:MENU_HEADER_VIEW_KEY];

if (!view)
{

view = [[CustomerInfoSectionView
alloc]init];

[view initWithNameLabel:@"陈"
ManagerNameLabel:@"周"
DepartmentLabel:@"111"
AddressLabel:@"222"
section:section delegate:self];
[dic
setObject:view forKey:MENU_HEADER_VIEW_KEY];

if (section % 2 ==
0)
{
view.backgroundColor =
UIColorFromRGB(0xf8f8f8);
}

}

return view;
}

首先获取section的个数,然后再判断每一个section中cell的个数,重点是点击section后得委托方法,话不多说,直接上代码:

#pragma mark Section header delegate

-(void)sectionHeaderView:(CustomerInfoSectionView*)sectionHeaderView sectionOpened:(NSInteger)sectionOpened
{

NSMutableDictionary *sectionInfo = [_dataArray
objectAtIndex:sectionHeaderView.section];

[sectionInfo setObject:[NSNumber
numberWithBool:YES]
forKey:MENU_OPENED_KEY];//将当前打开的section标记为1

NSMutableArray *indexPathsToInsert = [[NSMutableArray
alloc] init];

for (int i =
0; i < [_cellArray
count]; i++)
{
[indexPathsToInsert
addObject:[NSIndexPath
indexPathForRow:i
inSection:sectionOpened]];

}//点击显示下拉的cell,将其加入到indexPathsToInsert数组中

NSMutableArray *indexPathsToDelete = [[NSMutableArray
alloc] init];

NSInteger previousOpenSectionIndex =
self.openedSection;

if (previousOpenSectionIndex !=
NSNotFound)//有点开的section,这样打开新的section下拉菜单时要把先前的scetion关闭
{

NSMutableDictionary *previousOpenSectionInfo = [_dataArray
objectAtIndex:previousOpenSectionIndex];

CustomerInfoSectionView *previousOpenSection = [previousOpenSectionInfo
objectForKey:MENU_HEADER_VIEW_KEY];
[previousOpenSectionInfo
setObject:[NSNumber
numberWithBool:NO]
forKey:MENU_OPENED_KEY];
[previousOpenSection
toggleOpenWithUserAction:NO];//箭头方向改变

[UIView
animateWithDuration:.3
animations:^{
previousOpenSection.arrow.transform =
CGAffineTransformIdentity;
}];

for (int i =
0; i < [_cellArray
count]; i++)//将要关闭的cell写入indexPathsToDelete数组中
{
[indexPathsToDelete
addObject:[NSIndexPath
indexPathForRow:i
inSection:previousOpenSectionIndex]];
}

}

// Style the animation so that there's a smooth flow in either direction.

UITableViewRowAnimation insertAnimation;//系统提供的显示下拉cell菜单动画

UITableViewRowAnimation deleteAnimation;//关闭下拉菜单动画

if (previousOpenSectionIndex ==
NSNotFound || sectionOpened < previousOpenSectionIndex) {
insertAnimation =
UITableViewRowAnimationTop;

deleteAnimation = UITableViewRowAnimationBottom;
}

else {

insertAnimation = UITableViewRowAnimationBottom;
deleteAnimation =
UITableViewRowAnimationTop;
}

// Apply the updates.

[self.listTableView
beginUpdates];
[self.listTableView
insertRowsAtIndexPaths:indexPathsToInsert
withRowAnimation:insertAnimation];//将之前插入到indexPathsToInsert数组中的cell都插入显示出来
[self.listTableView
deleteRowsAtIndexPaths:indexPathsToDelete
withRowAnimation:deleteAnimation];//将之前打开得下拉菜单关闭

[self.listTableView
endUpdates];

self.openedSection = sectionOpened;
}

-(void)sectionHeaderView:(CustomerInfoSectionView*)sectionHeaderView sectionClosed:(NSInteger)sectionClosed
{

NSMutableDictionary *sectionInfo = [_dataArray
objectAtIndex:sectionHeaderView.section];

[sectionInfo setObject:[NSNumber
numberWithBool:NO]
forKey:MENU_OPENED_KEY];

NSInteger countOfRowsToDelete = [self.listTableView
numberOfRowsInSection:sectionClosed];

if (countOfRowsToDelete >
0)
{

NSMutableArray *indexPathsToDelete = [[NSMutableArray
alloc] init];

for (NSInteger i =
0; i < countOfRowsToDelete; i++)
{
[indexPathsToDelete
addObject:[NSIndexPath
indexPathForRow:i
inSection:sectionClosed]];
}

[self.listTableView
deleteRowsAtIndexPaths:indexPathsToDelete
withRowAnimation:UITableViewRowAnimationTop];
}

self.openedSection =
NSNotFound;
}

至于cell的自定义,童鞋们自己根据自己得需要定制即可,这个单机demo已经上传,大家可以点击这里下载,免积分哦~第一次写博客,不足之处还请大家多多指正啊

我实现的效果图如下:





内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐