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

时间:2022-12-06 23:43:56

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

}


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

我实现的效果图如下:

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