iOS 可高度自定义的底部弹框
技术: iOS Objective-C
概述
一个可以让开发者通过编写 tableView 的内容随心所欲的定制自己想要的底部弹框
详细
一. 运行效果图
二. 实现过程
1. 实现一个有遮罩效果的半透明 view,然后添加一个可设置展示内容高度的 contentView
// 这个遮罩是可以遮住全屏 - (void)createUI{ self.frame = CGRectMake(0, 0, SS_ScreenW, SS_ScreenH); self.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.4]; self.userInteractionEnabled = YES; [self addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(disMissView)]]; [self.contentView addSubview:self.tbView]; } // contentView 是通过懒加载实现的 - (UIView *)contentView{ if (!_contentView) { _contentView = [UIView new]; _contentView.backgroundColor = [UIColor whiteColor]; _contentView.frame = CGRectMake(0, SS_ScreenH - _contentHeight - SS_BottomMargin, SS_ScreenW, _contentHeight + SS_BottomMargin); _contentView.opaque = YES; [self addSubview:_contentView]; } return _contentView; }
2. 我们实现的底部弹框实质上一个可滑动的表单(tableView),在 contentView 上添加一个 tableView
- (UITableView *)tbView{ if (!_tbView) { // _tbView = [[UITableView alloc]initWithFrame:CGRectZero style:UITableViewStyleGrouped]; _tbView = [UITableView new]; _tbView.delegate = self; _tbView.dataSource = self; [_tbView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"ss"]; } return _tbView; }
3. 通过设置UIView 动画,实现遮罩 menuView 的展示和消失效果
// 将 menuView 展示在父 view 上 [view addSubview:self]; [view addSubview:self.contentView]; self.contentView.frame = CGRectMake(0, SS_ScreenH, SS_ScreenW, _contentHeight); __weak typeof(self) weakSelf = self; [UIView animateWithDuration:_animationDuration animations:^{ self.alpha = 1.0; self.contentView.frame = CGRectMake(0, SS_ScreenH - weakSelf.contentHeight - SS_BottomMargin, SS_ScreenW, weakSelf.contentHeight + SS_BottomMargin); } completion:^(BOOL finished) { }]; // 将 menuView 从父 view 上移除 __weak typeof(self) weakSelf = self; [UIView animateWithDuration:_animationDuration animations:^{ self.alpha = 0.0; self.contentView.frame = CGRectMake(0, SS_ScreenH, SS_ScreenW, weakSelf.contentHeight); } completion:^(BOOL finished) { [self removeFromSuperview]; [self.contentView removeFromSuperview]; }];
4. 实现选项和头部的定制化
通过编写自己的代理方法,让开发人员根据自己项目的实际需要设置各个选项,并且可以定制固定的头部以及底部
@protocol SSMenuViewDelegate <NSObject> @required; // 返回 tableView 的行数 - (NSInteger)menuTableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section; // 返回 tableViewCell 需要自定义 cell 的分割线 - (UITableViewCell *)menuTableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath; @optional; // 设置组数 - (NSInteger)menuNumberOfSectionsInTableView:(UITableView *)tableView; // 选中某个 tableView Cell - (void)menuTableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath; // 定义每个选项的cell的高度 - (CGFloat)menuTableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath; // 定义headerView - (UIView *)menuTableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section; // 定义headerView 的高度 - (CGFloat)menuTableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section; // 定义 footterView - (UIView *)menuTableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section; - (CGFloat)menuTableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section; @end
三. 项目结构
四. 使用手册
1. 首先,根据目录,将 SSMenuView.h, SSMenuView.m 文件,添加到自己项目中
2. 创建弹框控件
由于在使用类似弹框的时候,用户可能会多次点击使用,为了避免重复创建,建议使用懒加载创建一个弹窗控件
# pragma # pragma mark - Lazy - - (SSMenuView *)menuView{ if (!_menuView) { _menuView = [SSMenuView new]; _menuView.delegate = self; // _menuView.contentHeight = 44 * 6; // _menuView.tbView.separatorStyle = UITableViewCellSeparatorStyleNone; } return _menuView; }
3. 根据自己的项目需要,创建自己的弹框内容
# pragma # pragma mark - SSMenuViewDelegate - - (NSInteger)menuTableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ return 4; } - (UITableViewCell *)menuTableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cellID"]; if (!cell) { cell = [[UITableViewCell alloc]initWithStyle:(UITableViewCellStyleDefault) reuseIdentifier:@"cellID"]; } cell.textLabel.textAlignment = NSTextAlignmentCenter; cell.textLabel.text = [NSString stringWithFormat:@"这是选项%ld",indexPath.row]; cell.selectionStyle = UITableViewCellSelectionStyleNone; return cell; } - (CGFloat)menuTableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{ return 44; } - (CGFloat)menuTableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{ return 44; } - (UIView *)menuTableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section{ UIView *footer = [UIView new]; footer.backgroundColor = [UIColor orangeColor]; return footer; } - (UIView *)menuTableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{ UIView *header = [UIView new]; header.backgroundColor = [UIColor whiteColor]; header.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 44); UILabel *lab = [UILabel new]; lab.text = @"这是选项的头部"; [header addSubview:lab]; lab.textAlignment = NSTextAlignmentCenter; lab.frame = header.frame; return header; }
4. 根据需要,在触发点击事件,弹出弹框
此处,有2种展示方式,根据开发者自己的需要选择是否将弹框完全全屏
- (IBAction)click:(id)sender { // [self.menuView showInView:self.view]; [self.menuView showInWindow]; } // 隐藏弹框 [self.menuView disMissView];