iOS 半透明新手引导的封装

Liu

经过一个月的加班加点,由我负责的公司分项目终于完成了阶段性的开发,在改bug的空余,总结了一下工程中用到的一些东西,现把我封装的“半透明新手引导功能”分享出来,供大家交流学习,有不足,还望提出,共同进步~

1.功能图

一般的新手引导页,只需要出现一次,一次显示出全部需要提示的功能就可以了,像这样:

MJGuide0.png

但在我们项目中,不仅仅这样,还要通过点击一次次的显示不同的功能提示,一次可以显示一张,也可以显示多张,像这样:

MJGuide1.gif
MJGuide2.gif
2.代码区

万变不离其宗,如果你的项目只需要简单的一个新功能引导,并不需要那么多引导视图,那么我们可以用以下代码来实现,我也是根据此代码来封装多视图的,参考 黑黑的小土豆

  1. 创建半透明视图加载在window上,并添加点击手势
CGRect frame = [UIScreen mainScreen].bounds;
UIView * bgView = [[UIView alloc]initWithFrame:frame];
bgView.backgroundColor = RGBHEXA(0x323232, 0.8);

UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(sureTapClick:)];
[bgView addGestureRecognizer:tap];
[[UIApplication sharedApplication].keyWindow addSubview:bgView];
  1. 获取目标视图在window坐标系的frame
CGRect rect = [self.view convertRect:self.wobBtn.frame toView:[UIApplication sharedApplication].keyWindow];
  1. UIBezierPath 绘制镂空路径
UIBezierPath *path = [UIBezierPath bezierPathWithRect:frame];
[path appendPath:[[UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:5] bezierPathByReversingPath]];
// bezierPathByReversingPath 的意思就是反转 就是将你设置的路径以外的部分加入到路径中这样 你设置的路径就不在绘制的范围之内。在setMaskLayer的时候 你设置的那部分路径就没有了 就成了镂空的。 clockwise 这个值得意思也是这样。
  1. 渲染路径
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = path.CGPath;
shapeLayer.strokeColor = [UIColor blueColor].CGColor;
[bgView.layer setMask:shapeLayer];
  1. 把UI设计的功能引导图加到半透明视图上
UIImageView * imageView = [[UIImageView alloc]initWithFrame:CGRectMake(frame.size.width -225,CGRectGetMaxY(rect),200, 100)];
imageView.image = [UIImage imageNamed:@"img_guidehelp_bookshelf_purchasehistory"];
[bgView addSubview:imageView];
  1. 手势事件
- (void)sureTapClick:(UITapGestureRecognizer *)tap{
    UIView * view = tap.view;
    [view removeFromSuperview];
    [view.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
    [view removeGestureRecognizer:tap];
}
3.封装区

MXRGuideMaskView 想要展示多个新功能引导视图,肯定需要接受外界传递参数:图片组、图片位置组、镂空区位置组、展示顺序

/**
 初始化数据
 
 @param images 图片字符串
 @param imageframeArr 图片位置 @[[NSValue valueWithCGRect:CGRectMake(20, 205, 170, 50)]]
 @param rectArr 矩形透明区位置
 @param orderArr 顺序 例:@[@2,@1,@3]
 */
- (void)addImages:(NSArray *)images imageFrame:(NSArray *)imageframeArr TransparentRect:(NSArray *)rectArr orderArr:(NSArray *)orderArr;

然后,在 .m 方法中,判断具体的逻辑:

  1. 判断顺序数组总数是否等于图片数组,避免不必要的 crash
NSInteger numCount = 0;
for (NSNumber * num in orderArr) {
    NSInteger order = [num integerValue];
    numCount += order;
}
if (numCount != images.count) {
    return;
}
  1. 准备数据
self.orderArr = [orderArr mutableCopy];
[images enumerateObjectsUsingBlock:^(NSString *obj, NSUInteger idx, BOOL * _Nonnull stop) {
    UIImage * image = [UIImage imageNamed:obj];
    [self.imageArr addObject:image];
}];
self.frameArr = [imageframeArr mutableCopy];

for (NSInteger i=0; i<rectArr.count; i++) {
    UIBezierPath *transparentPath = [UIBezierPath bezierPathWithRoundedRect:[rectArr[i] CGRectValue] cornerRadius:5];
    [self.transparentPaths addObject:transparentPath];
}
  1. 控制多个显示逻辑
for (NSInteger i=0; i<[orderArr[0] integerValue]; i++) {
    [self addImage:_imageArr[i] withFrame:[_frameArr[i] CGRectValue]];
    [self addTransparentPath:_transparentPaths[i]];
}
- (void)addImage:(UIImage*)image withFrame:(CGRect)frame{
    
    UIImageView * imageView   = [[UIImageView alloc]initWithFrame:frame];
    imageView.backgroundColor = [UIColor clearColor];
    imageView.image           = image;
    [self addSubview:imageView];
}

- (void)addTransparentPath:(UIBezierPath *)transparentPath {
    [self.overlayPath appendPath:transparentPath];
    self.fillLayer.path = self.overlayPath.CGPath;
}

4.点击事件

- (void)tapClickedMaskView{
    
    _index++;
    if (_index < _orderArr.count) {
        
        [self refreshMask];
        [self.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
        
        // 控制多个显示逻辑
        NSInteger baseNum = [_orderArr[_index-1] integerValue];
        countNum = countNum + baseNum;
        NSInteger endNum = [_orderArr[_index] integerValue]+countNum;
        for (NSInteger i=countNum; i<endNum; i++) {
            
            [self addTransparentPath:_transparentPaths[i]];
            [self addImage:_imageArr[i] withFrame:[_frameArr[i] CGRectValue]];
        }
    }else{
        countNum = 0;
        [self dismissMaskView];
    }
}
- (void)refreshMask {
    
    UIBezierPath *overlayPath = [self generateOverlayPath];
    self.overlayPath = overlayPath;
    
}

- (UIBezierPath *)generateOverlayPath {
    
    UIBezierPath *overlayPath = [UIBezierPath bezierPathWithRect:self.bounds];
    [overlayPath setUsesEvenOddFillRule:YES];
    
    return overlayPath;
}

4.使用方法

使用起来也很方便,只需要初始化MXRGuideMaskView视图,然后传递参数,展示出来,就OK啦~

- (void)setupGuideView{
    MXRGuideMaskView *maskView = [MXRGuideMaskView new];
    [maskView addImages:imageArr imageFrame:imgFrameArr TransparentRect:transparentRectArr orderArr:orderArr];
    [maskView showMaskViewInView:self.view];
}

是不是很简单那,嘤嘤嘤 ~
整理了一个【Demo】出来,喜欢就点赞哦 ~

star.gif
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容

  • 1、通过CocoaPods安装项目名称项目信息 AFNetworking网络请求组件 FMDB本地数据库组件 SD...
    X先生_未知数的X阅读 15,937评论 3 118
  • 这片羽毛来自白鹅身上,它已经飘荡了很长时间了,它飘过村庄,在一扎金黄的麦垛上静静的休息了一段时间,一个孩子将他拾起...
    春迟秋暮阅读 453评论 0 2
  • 这片园子, 往左走,是泰坦尼克, 往右走,是新鸳鸯蝴蝶梦, 都是中国拳。 中间最好, 我知道那儿周末有京剧。 这会...
    爱稳阅读 294评论 0 0
  • 结构体定义 结构体,通俗讲就像是打包封装,把一些有共同特征(比如同属于某一类事物的属性,往往是某种业务相关属性的聚...
    巧克力er阅读 277评论 1 1