目标
技术方案
1. 引导页展示逻辑
页面首次展示时,展示引导蒙层
引导蒙层有单独版本号,在版本号不升级的情况下只展示一次
引导蒙层分步展示,点击蒙层任意位置,进入下一步当最后一次不展示完成后才算完成
2. 蒙层设计
按照 UI交互,将蒙层分为 6 部分,如下
-
蒙层组成
四个矩形阴影遮罩(Top+Bottom+Left+Right )
一个矩形透明遮罩( Focus)
-
形状需求 图片
-
其他自定义View
3. 接口设计
@interface ISCPageGuideMaskView : UIView
@property (nonatomic, strong, readonly) UIControl *focusArea;
@property (nonatomic, strong) void (^completeBlock)(void);
/// 在 layout 中 1.设置 maskView. focusArea 的 left.right.top.bottom 的位置 2.设置其他的
+ (instancetype)maskViewWithLayout:(void (^)(ISCPageGuideMaskView *maskView))layout;
@end
@protocol ISCPageGuideProtocol <NSObject>
@required
/// page guide 最新版本
- (NSNumber *)pageGuideLatestVersion;
@optional
/// page guide 分步
- (ISCPageGuideMaskView *)pageGuideStep1;
- (ISCPageGuideMaskView *)pageGuideStep2;
- (ISCPageGuideMaskView *)pageGuideStep3;
- (ISCPageGuideMaskView *)pageGuideStep4;
- (ISCPageGuideMaskView *)pageGuideStep5;
/// 自定义显隐规则,否则走默认逻辑(自动对比版本)
- (BOOL)pageGuideShouldShow;
@end
@interface ISCPageGuideHelper : NSObject
/// 展示 Page Guide
+ (void)showPageGuideIfNeeded:(id <ISCPageGuideProtocol>)guide closeAutomatically:(BOOL)autoClose;
/// 展示完成后记录状态
+ (void)updateShowedPageGuideVersion:(id <ISCPageGuideProtocol>)guide;
#pragma mark - Utils
/// 坐标转换
+ (CGPoint)getViewOriginInWindow:(UIView *)view;
/// 版本比较
+ (NSNumber *)pageGuideShowedVersion:(id <ISCPageGuideProtocol>)guide;
@end
核心代码实现
@implementation ISCPageGuideHelper
+ (void)showPageGuideIfNeeded:(id <ISCPageGuideProtocol>)guide closeAutomatically:(BOOL)autoClose
{
if ([self shouldShowPageGuideWithViewController:guide]) {
[self showPageGuide:guide step:1 closeAutomatically:autoClose];
}
}
+ (BOOL)showPageGuide:(id <ISCPageGuideProtocol>)guide step:(NSInteger)step closeAutomatically:(BOOL)autoClose
{
// 构建引导页
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
NSString *stepSelector = [NSString stringWithFormat:@"pageGuideStep%@", @(step)];
ISCPageGuideMaskView *guideStepView =
[guide respondsToSelector:NSSelectorFromString(stepSelector)]
? [guide performSelector:NSSelectorFromString(stepSelector)]
: nil;
#pragma clang diagnostic pop
// 如果没有引导页, 异常退出
if (!guideStepView) {
return NO;
}
// 根据当前步数,确定下一步,并且在最后一步进行停住
@weakify(self, guideStepView);
guideStepView.completeBlock = ^{
@strongify(self, guideStepView);
NSInteger nextStep = step + 1;
[self showPageGuide:guide step:nextStep closeAutomatically:autoClose]
|| autoClose ? ({
[guideStepView removeFromSuperview];
[self updateShowedPageGuideVersion:guide];
}) : nil;
};
// 展示浮层
UIView *window = [UIApplication sharedApplication].keyWindow;
[window addSubview:guideStepView];
[window bringSubviewToFront:guideStepView];
// 完成展示,正常退出
return YES;
}
...
@end