之前开发过程中总是会遇到很多问题,百度后会根据大家写的博客找到解决方法,不得不说还是非常感谢各位博主的开源奉献的精神。所以我也开个博客,把在项目开发中的一些点点滴滴记录下来。目前项目中要实现一个功能,就是从服务器获取数据,同时实现上拉和下拉功能,在点击一行后会出现下拉菜单,再点击后会关闭下拉菜单。我觉得这样得功能在很多项目里是很常见的,所以我写了一个单机版的,大家可以直接把我的代码拿去修改一下就可以了。这篇文章就先写如何实现显示下拉菜单功能,至于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 {
[superviewDidLoad];
self.openedSection =NSNotFound;
_dataArray = [[NSMutableArrayalloc]init];
//_listTableView要显示的section数目
for (int i =0; i < 5; i++)
{
NSMutableDictionary *dic = [[NSMutableDictionaryalloc]init];
[dicsetValue:@"55555"forKey:@"detail"];
[_dataArrayaddObject:dic];
}
_cellArray =@[@"1",@"2",@"3"];//下拉显示的cell的数量
self.view.backgroundColor =UIColorFromRGB(0xf8f8f8);
_listTableView = [[UITableViewalloc]initWithFrame:CGRectMake(10.f,20.f,CGRectGetWidth([UIScreenmainScreen].applicationFrame) -20.f, [[UIScreenmainScreen] applicationFrame].size.height -20.f) style:UITableViewStylePlain];
_listTableView.delegate =self;
_listTableView.dataSource =self;
_listTableView.separatorStyle =UITableViewCellSeparatorStyleNone;
[_listTableViewregisterClass:[ViewOfCustomerTableViewCellclass] forCellReuseIdentifier:ViewOfCustomerTableViewCellIdentifier];
_listTableView.allowsSelection =YES;
_listTableView.backgroundColor = [UIColorclearColor];
[self.viewaddSubview:_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 {
[selftoggleOpenWithUserAction:YES];
}
-(void)toggleOpenWithUserAction:(BOOL)userAction {
//判断所在sectionView是否打开来旋转箭头
_isOpen = !_isOpen;
if (userAction) {
if (_isOpen) {
[UIViewanimateWithDuration:.3animations:^{
self.arrow.transform = CGAffineTransformMakeRotation(M_PI);
}];
if ([self.delegaterespondsToSelector:@selector(sectionHeaderView:sectionOpened:)]) {
[self.delegatesectionHeaderView:selfsectionOpened:self.section];
}
}
else {
[UIViewanimateWithDuration:.3animations:^{
self.arrow.transform =CGAffineTransformIdentity;
}];
if ([self.delegaterespondsToSelector:@selector(sectionHeaderView:sectionClosed:)]) {
[self.delegatesectionHeaderView:selfsectionClosed:self.section];
}
}
}
}
自定义完section的view后,回到之前的视图控制器,在tableview的委托方法中:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [_dataArraycount];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
//根据字典里的MENU_OPENED_KEY的值来显示或者隐藏下拉的cell
NSMutableDictionary *sectionInfo = [_dataArrayobjectAtIndex: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 = [_dataArrayobjectAtIndex:section];
CustomerInfoSectionView *view = [dicobjectForKey:MENU_HEADER_VIEW_KEY];
if (!view)
{
view = [[CustomerInfoSectionViewalloc]init];
[view initWithNameLabel:@"陈"ManagerNameLabel:@"周"DepartmentLabel:@"111"AddressLabel:@"222"section:section delegate:self];
[dicsetObject: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 = [_dataArrayobjectAtIndex:sectionHeaderView.section];
[sectionInfo setObject:[NSNumbernumberWithBool:YES]forKey:MENU_OPENED_KEY];//将当前打开的section标记为1
NSMutableArray *indexPathsToInsert = [[NSMutableArrayalloc] init];
for (int i =0; i < [_cellArraycount]; i++)
{
[indexPathsToInsertaddObject:[NSIndexPathindexPathForRow:i inSection:sectionOpened]];
}//点击显示下拉的cell,将其加入到indexPathsToInsert数组中
NSMutableArray *indexPathsToDelete = [[NSMutableArrayalloc] init];
NSInteger previousOpenSectionIndex = self.openedSection;
if (previousOpenSectionIndex !=NSNotFound)//有点开的section,这样打开新的section下拉菜单时要把先前的scetion关闭
{
NSMutableDictionary *previousOpenSectionInfo = [_dataArrayobjectAtIndex:previousOpenSectionIndex];
CustomerInfoSectionView *previousOpenSection = [previousOpenSectionInfoobjectForKey:MENU_HEADER_VIEW_KEY];
[previousOpenSectionInfosetObject:[NSNumbernumberWithBool:NO]forKey:MENU_OPENED_KEY];
[previousOpenSectiontoggleOpenWithUserAction:NO];//箭头方向改变
[UIViewanimateWithDuration:.3animations:^{
previousOpenSection.arrow.transform =CGAffineTransformIdentity;
}];
for (int i =0; i < [_cellArraycount]; i++)//将要关闭的cell写入indexPathsToDelete数组中
{
[indexPathsToDeleteaddObject:[NSIndexPathindexPathForRow: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.listTableViewbeginUpdates];
[self.listTableViewinsertRowsAtIndexPaths:indexPathsToInsert withRowAnimation:insertAnimation];//将之前插入到indexPathsToInsert数组中的cell都插入显示出来
[self.listTableViewdeleteRowsAtIndexPaths:indexPathsToDelete withRowAnimation:deleteAnimation];//将之前打开得下拉菜单关闭
[self.listTableViewendUpdates];
self.openedSection = sectionOpened;
}
-(void)sectionHeaderView:(CustomerInfoSectionView*)sectionHeaderView sectionClosed:(NSInteger)sectionClosed
{
NSMutableDictionary *sectionInfo = [_dataArrayobjectAtIndex:sectionHeaderView.section];
[sectionInfo setObject:[NSNumbernumberWithBool:NO]forKey:MENU_OPENED_KEY];
NSInteger countOfRowsToDelete = [self.listTableViewnumberOfRowsInSection:sectionClosed];
if (countOfRowsToDelete > 0)
{
NSMutableArray *indexPathsToDelete = [[NSMutableArrayalloc] init];
for (NSInteger i =0; i < countOfRowsToDelete; i++)
{
[indexPathsToDeleteaddObject:[NSIndexPathindexPathForRow:i inSection:sectionClosed]];
}
[self.listTableViewdeleteRowsAtIndexPaths:indexPathsToDelete withRowAnimation:UITableViewRowAnimationTop];
}
self.openedSection =NSNotFound;
}