改代码是参考一个Demo直接改的,代码中有一些漏洞,如果发现其他的问题,可以下方直接留言
.h文件
#import <UIKit/UIKit.h> typedef void(^PopoverBlock)(NSInteger index); @interface CustomPopView : UIView //@property(nonatomic,copy)void(^block)(int index); //-(void)setDataArr:(NSArray *)titleArr withView:(id *)view withBlock:(void(^)(NSString *a))block; @property (nonatomic, copy) NSArray *menuTitles; @property(nonatomic,copy)void(^PopoverHiddenBlock)(BOOL isHidden ); - (void)showFromView:(id)aView selected:(PopoverBlock)selected; @end @interface PopoverArrow : UIView @end
.m文件
#import "CustomPopView.h" // 字体大小 #define kPopoverFontSize 14.f // 十六进制颜色 #define UIColorFromRGB(rgbValue) [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 green:((float)((rgbValue & 0xFF00) >> 8))/255.0 blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0] #define SCREEN_W [UIScreen mainScreen].bounds.size.width #define SCREEN_H [UIScreen mainScreen].bounds.size.height // 箭头高度 #define kArrowH 8 // 箭头宽度 #define kArrowW 15 //每行的高度 #define CELL_HEIGHT 38 // #define Identifier @"cell" // 边框颜色 #define kBorderColor UIColorFromRGB(0xE1E2E3) @interface CustomPopView () <UITableViewDelegate, UITableViewDataSource> { PopoverBlock _selectedBlock; UIView *_backgroundView; PopoverArrow *_arrowView; } @property (nonatomic, retain) UITableView *tableView; @end @implementation CustomPopView - (instancetype)initWithFrame:(CGRect)frame { if (!(self = [super initWithFrame:frame])) return nil; self.backgroundColor = [UIColor clearColor]; // 箭头 _arrowView = [PopoverArrow new]; [self addSubview:_arrowView]; // tableView放在箭头底下, 用于箭头挡住tableView边框 [self insertSubview:self.tableView belowSubview:_arrowView]; return self; } - (void)layoutSubviews { [super layoutSubviews]; // 设置tableView默认的分割线起终点位置 if ([self.tableView respondsToSelector:@selector(setSeparatorInset:)]) { [self.tableView setSeparatorInset:UIEdgeInsetsZero]; } if ([self.tableView respondsToSelector:@selector(setLayoutMargins:)]) { [self.tableView setLayoutMargins:UIEdgeInsetsZero]; } self.tableView.layer.cornerRadius = 5.f; self.tableView.layer.borderColor = kBorderColor.CGColor; self.tableView.layer.borderWidth = 1.f; } #pragma mark -- getter - (UITableView *)tableView { if (_tableView) return _tableView; _tableView = [UITableView new]; _tableView.delegate = self; _tableView.dataSource = self; _tableView.rowHeight = CELL_HEIGHT; _tableView.backgroundColor = [UIColor whiteColor]; _tableView.showsVerticalScrollIndicator = NO; [_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:Identifier]; _tableView.tableFooterView = UIView.new; return _tableView; } #pragma mark -- delegate - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.menuTitles.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:Identifier]; cell.textLabel.font = [UIFont systemFontOfSize:kPopoverFontSize]; cell.textLabel.text = [self.menuTitles objectAtIndex:indexPath.row]; return cell; } - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { if ([cell respondsToSelector:@selector(setSeparatorInset:)]) { [cell setSeparatorInset:UIEdgeInsetsZero]; } if ([cell respondsToSelector:@selector(setLayoutMargins:)]) { [cell setLayoutMargins:UIEdgeInsetsZero]; } } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [UIView animateWithDuration:0.25 animations:^{ self.alpha = 0; } completion:^(BOOL finished) { [_backgroundView removeFromSuperview]; _backgroundView = nil; if (_selectedBlock) { _selectedBlock(indexPath.row); } [self removeFromSuperview]; }]; } #pragma mark -- private // 点击透明层隐藏 - (void)hide { [UIView animateWithDuration:0.25 animations:^{ self.alpha = 0; } completion:^(BOOL finished) { [_backgroundView removeFromSuperview]; _backgroundView = nil; if(self.PopoverHiddenBlock){ self.PopoverHiddenBlock(YES); } [self removeFromSuperview]; }]; } #pragma mark -- public /*! * @author lifution * * @brief 显示弹窗 * * @param aView 箭头指向的控件 * @param selected 选择完成回调 */ - (void)showFromView:(id)aView selected:(PopoverBlock)selected { if (selected) _selectedBlock = selected; //aView只能传两种参数,一种是UIView 另一种UIBarButtonItem if(!([aView isKindOfClass:[UIView class]] || [aView isKindOfClass:[UIBarButtonItem class]])){ return; } UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow; // 背景遮挡 _backgroundView = UIView.new; _backgroundView.frame = keyWindow.bounds; _backgroundView.backgroundColor = [UIColor blackColor]; _backgroundView.alpha = 0.2; _backgroundView.userInteractionEnabled = YES; [_backgroundView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hide)]]; [keyWindow addSubview:_backgroundView]; // 刷新数据更新contentSize [self.tableView reloadData]; // 获取触发弹窗的按钮在window中的坐标 CGRect triggerRect ; if([aView isKindOfClass:[UIView class]]){ UIView *view = (UIView *)aView; triggerRect = [view convertRect:view.bounds toView:keyWindow]; }else{ UIView *bgView = [aView valueForKey:@"_view"]; triggerRect = [bgView convertRect:bgView.bounds toView: keyWindow]; } // 箭头指向的中心点 CGFloat arrowCenterX = CGRectGetMaxX(triggerRect)-CGRectGetWidth(triggerRect)/2; // 取得标题中的最大宽度 CGFloat maxWidth = 0; for (id obj in self.menuTitles) { if ([obj isKindOfClass:[NSString class]]) { CGSize titleSize = [obj sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:kPopoverFontSize]}]; if (titleSize.width > maxWidth) { maxWidth = titleSize.width; } } } CGFloat curWidth = ((maxWidth+80)>SCREEN_W-30)?SCREEN_W-30:(maxWidth+80); CGFloat curHeight = CELL_HEIGHT*self.menuTitles.count+kArrowH; CGFloat curX = arrowCenterX-curWidth/2; CGFloat curY = CGRectGetMaxY(triggerRect)+10; // 如果箭头指向点距离屏幕右边减去5px不足curWidth的一半的话就重新设置curX if ((SCREEN_W-arrowCenterX-5)<curWidth/2) { curX = curX-(curWidth/2-(SCREEN_W-arrowCenterX-5)); } // 如果箭头指向点距离屏幕左边加上5px不足curWidth的一半的话就重新设置curX if (arrowCenterX+5<curWidth/2) { curX = curX+(curWidth/2-arrowCenterX)+5; } //如果高度大于10行,则最高按10计算 if(curHeight>CELL_HEIGHT*10+kArrowH){ curHeight = CELL_HEIGHT*10+kArrowH; } self.frame = CGRectMake(curX, curY - 18, curWidth, curHeight); _arrowView.frame = CGRectMake(arrowCenterX-curX-kArrowW/2, 0, kArrowW, kArrowH+1); // 箭头高度 +1 遮挡住tableView的边框 self.tableView.frame = CGRectMake(0, kArrowH, curWidth,curHeight - kArrowH ); [keyWindow addSubview:self]; self.alpha = 0; [UIView animateWithDuration:0.3 animations:^{ self.alpha = 1; }]; } @end // 箭头 @implementation PopoverArrow - (instancetype)initWithFrame:(CGRect)frame { if (!(self = [super initWithFrame:frame])) return nil; self.backgroundColor = [UIColor clearColor]; return self; } // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. - (void)drawRect:(CGRect)rect { [super drawRect:rect]; // Drawing code CGSize curSize = rect.size; CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetLineWidth(context, 1); CGContextSetStrokeColorWithColor(context, kBorderColor.CGColor); CGContextSetFillColorWithColor(context, UIColor.whiteColor.CGColor); CGContextBeginPath(context); CGContextMoveToPoint(context, 0, curSize.height); CGContextAddLineToPoint(context, curSize.width/2, 0); CGContextAddLineToPoint(context, curSize.width, curSize.height); CGContextDrawPath(context, kCGPathFillStroke); } @end
使用:
view = [CustomPopView new]; view.menuTitles = @[@"1",@"2",@"3"]; UIBarButtonItem *item = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(addBtnClick:)]; self.navigationItem.rightBarButtonItem = item; -(void)addBtnClick:(UIBarButtonItem *)item{ [view showFromView:item selected:^(NSInteger index) { }]; }