自定义PopView

时间:2022-12-20 11:28:49

改代码是参考一个Demo直接改的,代码中有一些漏洞,如果发现其他的问题,可以下方直接留言

自定义PopView

自定义PopView

.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) { }];
}

自定义PopView的更多相关文章

  1. iOS实现自定义的弹出视图(popView)

    前段时间,在项目中有个需求是支付完成后,弹出红包,实现这么一个发红包的功能.做了最后,实现的效果大致如下: 一.使用方法 整个ViewController的代码大致如下 // //  SecondVi ...

  2. Android定位&amp&semi;地图&amp&semi;导航——自定义公交路线代码

    一.问题描述 基于百度地图实现检索指定城市指定公交的交通路线图,效果如图所示 二.通用组件Application类,主要创建并初始化BMapManager public class App exten ...

  3. Android自定义遮罩层设计

    在做网页设计时,前端设计人员会经常用到基于JS开发的遮罩层,并且背景半透明.这样的效果怎么样在Android上实现呢?这个实现并不困难,先来上效果图: <ignore_js_op> 201 ...

  4. 关于Unity3D自定义编辑器的学习

    被人物编辑器折腾了一个月,最终还是交了点成品上去(还要很多优化都还么做).  刚接手这项工作时觉得没概念,没想法,不知道.后来就去看<<Unity5.X从入门到精通>>中有关于 ...

  5. 一起学微软Power BI系列-使用技巧&lpar;5&rpar;自定义PowerBI时间日期表

    1.日期函数表作用 经常使用Excel或者PowerBI,Power Pivot做报表,时间日期是一个重要的纬度,加上做一些钻取,时间日期函数表不可避免.所以今天就给大家分享一个自定义的做日期表的方法 ...

  6. JavaScript自定义浏览器滚动条兼容IE、 火狐和chrome

    今天为大家分享一下我自己制作的浏览器滚动条,我们知道用css来自定义滚动条也是挺好的方式,css虽然能够改变chrome浏览器的滚动条样式可以自定义,css也能够改变IE浏览器滚动条的颜色.但是css ...

  7. ASP&period;NET Aries 入门开发教程8:树型列表及自定义右键菜单

    前言: 前面几篇重点都在讲普通列表的相关操作. 本篇主要讲树型列表的操作. 框架在设计时,已经把树型列表和普通列表全面统一了操作,用法几乎是一致的. 下面介绍一些差距化的内容: 1:树型列表绑定: v ...

  8. ASP&period;NET Aries 入门开发教程5:自定义列表页工具栏区

    前言: 抓紧时间,继续写教程,因为发现用户期待的内容,都在业务处理那一块. 不得不继续勤劳了. 这节主要介绍工具栏区的玩法. 工具栏的默认介绍: 工具栏默认包括5个按钮,根据不同的权限决定显示: 添加 ...

  9. UWP中实现自定义标题栏

    UWP中实现自定义标题栏 0x00 起因 在UWP开发中,有时候我们希望实现自定义标题栏,例如在标题栏中加入搜索框.按钮之类的控件.搜了下资料居然在一个日文网站找到了一篇介绍这个主题的文章: http ...

随机推荐

  1. &lt&semi;java基础学习&gt&semi;JAVA 对象和类

    Java is an Object-Oriented Language. As a language that has the Object Oriented feature, Java suppor ...

  2. hdu 4738 2013杭州赛区网络赛 桥&plus;重边&plus;连通判断 &ast;&ast;&ast;

    题意:有n座岛和m条桥,每条桥上有w个兵守着,现在要派不少于守桥的士兵数的人去炸桥,只能炸一条桥,使得这n座岛不连通,求最少要派多少人去. 处理重边 边在遍历的时候,第一个返回的一定是之前去的边,所以 ...

  3. 极客DIY:使用树莓派制作一套&OpenCurlyDoubleQuote;NAS&plus;私有云盘&plus;下载机”

    原创作者:HackLiu 0×00 前言 ‍ ‍ 如果你家里有多台设备需要联网需要娱乐,你一定会或多或少遇到设备碎片化带来的烦恼.当然,已经有很多厂商包括新晋的小米.360在内的互联网公司做了这个事情 ...

  4. Android-adb相关

    最近做android开发遇到无法通过usb链接设备的情况,通过wifi连接设备调试也颇为方便 1.android 要root , 下载终端app  比如 BetterTerminal 2.通过以下命令 ...

  5. 使用dropwizard&lpar;3&rpar;-加入DI-dagger2

    前言 习惯了Spring全家桶,对spring的容器爱不释手.使用dropwizard,看起来确实很轻,然而,真正使用的时候不得不面临一个问题.我们不可能一个resource就能把所有的业务逻辑囊括! ...

  6. JQuery纵向下拉菜单实现心得

    jquery库给我们带来了许多便利,不愧是轻量级的DOM框架,在前面的博文中小编分别对jquery的基础知识以及jquery的一些小demo有一系列的简单介绍,期待各位小伙伴的指导.使用jquery实 ...

  7. 下载安装windows版Redis

    链接       https://github.com/MicrosoftArchive/redis/releases 选择版本下载 在redis目录打开cmd命令输入 redis-server.ex ...

  8. win7下解压安装mysql的方法

    在win7下通过解压安装mysql 5.7一直出现启动不成功,网上找了好久终于找到一个解决方法,记录一下: 1.解压下载的压缩包 2.在解压目录下,将my-default.ini改名为my.ini, ...

  9. HDOJ5437&lpar;优先队列&rpar;

    Alisha’s Party Time Limit: 3000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) ...

  10. vue利用watch侦听对象具体的属性 ~ 巧用计算属性computed做中间层

    有时候需要侦听某个对象具体的属性,可以按下面案例进行: <template> <div> <input type="text" v-model=&qu ...