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

本文介绍了一种在iOS应用中实现TableView下拉菜单的方法。通过自定义section视图和cell,实现了点击section展开和收起下拉菜单的功能,并提供了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

我实现的效果图如下:




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值