自定义PopView

改代码是参考一个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) {
        
    }];
}

原文地址:https://www.cnblogs.com/hualuoshuijia/p/9983821.html