先看一下效果
Demo: 代码方式(万能使用)+贝塞尔方式(把页面某个字圈起来,支持圆形方形)
1.需求背景
在app版本迭代过程中,有些功能模块的入口可能改版较大,位置发生了变动,为了用户的体验,常常需要上面样式的新功能引导页
注意:新功能引导页可不是新特性啊.....
一.思路1,UI适配不同屏幕分辨率的机型。ios还好,安卓可就要骂街了啊~那么多机型。况且如果你的版本迭代比较频繁,tabBar个数和页面是动态化配置,那UI需要大量分别率的切图,对其是很大的工作量。而且以后只能靠该方式UI维护
二.思路2,前端代码生成。那么生成方式怎么处理,如何精准的get到控件的坐标尺寸呢?如果你的页面嵌套比较多呢?
为了解决上述问题我们需要如下处理
1.单利,目的是只出现一次并不再需要频繁创建,调用方便,而且最重要的是可以随时增加属性 在你页面任何层级位置记录你某个控件的bounds frame。如果你需要的话
2.怎么拿到你控件尺寸。即便拿到了也是对于父控件的尺寸,所以我们只需要记录或者知道控件的横坐标初始位置即可
3.怎么处理tabBar的item的frame https://www.jianshu.com/p/004f068678ea tabBar Frame 参照这里喔!
三:使用方法
具体实现请将下方代码拷贝到你继承于 NSObject的类中即可。
//
// SGGuideManager.h
// sonkwoapp
//
// Created by zdby on 2022/9/30.
//
#import
typedef void(^FinishBlock)(void);
typedefNS_ENUM(NSInteger,SGGuidePageType) {
SGGuidePageTop1 =0,
SGGuidePageTop2,
SGGuidePageTop3,
SGGuidePageTabBar
};
@interface SGGuideManager : NSObject
// 获取单例
+ (instancetype)shareManager;
/**
显示方法
@param type 指引页类型
*/
- (void)showGuidePageWithType:(SGGuidePageType)type;
/**
显示方法
@param type 指引页类型
@param completion 完成时回调
*/
- (void)showGuidePageWithType:(SGGuidePageType)typecompletion:(FinishBlock)completion;
@end
//
// SGGuideManager.m
// sonkwoapp
//
// Created by zdby on 2022/9/30.
//
#import "SGGuideManager.h"
@interface SGGuideManager ()
@property (nonatomic, copy) FinishBlockfinish;
@property (nonatomic, strong) NSString *guidePageKey;
@property (nonatomic, assign) SGGuidePageType guidePageType;
@property (nonatomic, strong) UIView *bgView;
@end
@implementation SGGuideManager
+ (instancetype)shareManager {
staticSGGuideManager *instance =nil;
staticdispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[selfalloc] init];
});
returninstance;
}
#pragma mark--引导页的下一页
- (void)showGuidePageWithType:(SGGuidePageType)typecompletion:(FinishBlock)completion {
[selfcreatControlWithType:type completion:completion];
}
#pragma mark-- 引导页最后一步
- (void)showGuidePageWithType:(SGGuidePageType)type {
[selfcreatControlWithType:type completion:NULL];
}
- (void)creatControlWithType:(SGGuidePageType)typecompletion:(FinishBlock)completion {
_finish = completion;
// 遮盖视图
CGRect frame = [UIScreen mainScreen].bounds;
UIView *bgView = [[UIView alloc] initWithFrame:frame];
bgView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.6f];
[bgView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:selfaction:@selector(tap:)]];
[KeyWindow addSubview:bgView];
_bgView = bgView;
//有几个引导页就配置几个
switch(type) {
caseSGGuidePageTop1:
[selfconfigSGGuidePageTop1];
_guidePageKey = SGGuidePageTop1Key ;
break;
caseSGGuidePageTop2:
[selfconfigSGGuidePageTop2];
_guidePageKey = SGGuidePageTop2Key;
break;
caseSGGuidePageTop3:
[selfconfigSGGuidePageTop3];
_guidePageKey = SGGuidePageTop3Key;
break;
caseSGGuidePageTabBar:
[selfconfigSGGuidePageTabBar];
_guidePageKey = SGGuidePageTabBarKey;
break;
default:
break;
}
}
#pragma mark--configGuide
-(void)configSGGuidePageTop1 {
//用户可以不浏览直接跳过(新功能引导有其存在的必要性,不建议优化这里直接跳过,如果你们需求如此那就加上吧)
UIButton *jumpBtn = [[UIButton alloc]initWithFrame:CGRectMake(SGScreen_Width-20-40,84,40,24)];
[jumpBtn setTitle:@"跳过"forState:UIControlStateNormal];
[jumpBtn setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
jumpBtn.titleLabel.font = [UIFont SGFontWithStyle:FontWeightStyleRegular size:13];
[jumpBtn addTarget:selfaction:@selector(jumpGuide) forControlEvents:UIControlEventTouchUpInside];
[_bgView addSubview:jumpBtn];
//如果你的页面是嵌套页面如:头条样式支持左右滑动切换页面的,则无法或很难拿到控件,即便拿到也是获取其对于父控件的尺寸,这里我们只关注一点
//1.控件在不同机型的横坐标初始位置
UIImageView *topImageView1 = [[UIImageView alloc]initWithFrame:CGRectMake(9,87,133,90)];
topImageView1.image = [UIImage imageNamed:@"guide1-1"];
topImageView1.contentMode = UIViewContentModeScaleAspectFill;
topImageView1.clipsToBounds =YES;
[_bgView addSubview:topImageView1];
UIImageView *topImageView2 = [[UIImageView alloc]initWithFrame:CGRectMake(43, topImageView1.bottom+5,240,210)];
topImageView2.image = [UIImage imageNamed:@"guide1-2"];
topImageView2.contentMode = UIViewContentModeScaleAspectFill;
topImageView2.clipsToBounds =YES;
[_bgView addSubview:topImageView2];
}
-(void)configSGGuidePageTop2 {
CGFloat with1= [SGHelper getWidthWithText:@"推荐"height:20font:[UIFont fontWithName:@"Helvetica-Bold"size:17]];
CGFloat with2= [SGHelper getWidthWithText:@"活动"height:20font:[UIFont fontWithName:@"Helvetica-Bold"size:15]];
CGFloat with3= [SGHelper getWidthWithText:@"榜单"height:20font:[UIFont fontWithName:@"Helvetica-Bold"size:15]];
UIImageView *topImageView1 = [[UIImageView alloc]initWithFrame:CGRectMake(25+with1+35+with2+35+with3+23-133,87,133,120)];
topImageView1.image = [UIImage imageNamed:@"guide2-1"];
topImageView1.contentMode = UIViewContentModeScaleAspectFill;
topImageView1.clipsToBounds =YES;
[_bgView addSubview:topImageView1];
UIImageView *topImageView2 = [[UIImageView alloc]initWithFrame:CGRectMake(36, topImageView1.bottom+5,240,210)];
topImageView2.image = [UIImage imageNamed:@"guide2-2"];
topImageView2.contentMode = UIViewContentModeScaleAspectFill;
topImageView2.clipsToBounds =YES;
[_bgView addSubview:topImageView2];
}
-(void)configSGGuidePageTabBar {
UIImageView *topImageView1 = UIImageView.alloc.init;
if(SGUserDefaultGet(SG_ActivityBtn_CacheKey)) {
topImageView1.frame = CGRectMake(4.0/15.0*SGScreen_Width-20.0, SGScreen_Height-(isIphoneX?139:124),168,124);
}else{
topImageView1.frame = CGRectMake(4.0/12.0*SGScreen_Width-20.0, SGScreen_Height-(isIphoneX?139:124),168,124);
}
topImageView1.image = [UIImage imageNamed:@"guide3-1"];
topImageView1.contentMode = UIViewContentModeScaleAspectFill;
topImageView1.clipsToBounds =YES;
[_bgView addSubview:topImageView1];
//底部配置了中间按钮
UIImageView *topImageView2 = [[UIImageView alloc]initWithFrame:CGRectMake(68, topImageView1.top-5-109,240,109)];
topImageView2.image = [UIImage imageNamed:@"guide3-2"];
topImageView2.contentMode = UIViewContentModeScaleAspectFill;
topImageView2.clipsToBounds =YES;
[_bgView addSubview:topImageView2];
}
-(void)configSGGuidePageTop3 {
CGFloat with1= [SGHelper getWidthWithText:@"推荐"height:20font:[UIFont fontWithName:@"Helvetica-Bold"size:17]];
CGFloat with2= [SGHelper getWidthWithText:@"活动"height:20font:[UIFont fontWithName:@"Helvetica-Bold"size:15]];
CGFloat with3= [SGHelper getWidthWithText:@"榜单"height:20font:[UIFont fontWithName:@"Helvetica-Bold"size:15]];
UIImageView *topImageView1 = [[UIImageView alloc]initWithFrame:CGRectMake(25+with1+15,87,20+with2+35+with3+30,120)];
topImageView1.image = [UIImage imageNamed:@"guide4-1"];
topImageView1.contentMode = UIViewContentModeScaleAspectFill;
topImageView1.clipsToBounds =YES;
[_bgView addSubview:topImageView1];
//底部配置了中间按钮
UIImageView *topImageView2 = [[UIImageView alloc]initWithFrame:CGRectMake(60, topImageView1.bottom+5,240,133)];
topImageView2.image = [UIImage imageNamed:@"guide4-2"];
topImageView2.contentMode = UIViewContentModeScaleAspectFill;
topImageView2.clipsToBounds =YES;
[_bgView addSubview:topImageView2];
}
#pragma mark--Action
-(void)jumpGuide {
//跳过直接移除并标记新功能引导页已被浏览不再展示
[[NSUserDefaults standardUserDefaults] setBool:YESforKey:SGGuidePageTop1Key];
[_bgView removeFromSuperview];
[[_bgView subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];
_bgView =nil;
}
- (void)tap:(UITapGestureRecognizer *)recognizer {
UIView *bgView = recognizer.view;
[bgView removeFromSuperview];
[bgView removeGestureRecognizer:recognizer];
[[bgView subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];
bgView =nil;
[[NSUserDefaults standardUserDefaults] setBool:YESforKey:_guidePageKey];
if(_finish) _finish();
}
@end