本文主要介绍使用UIBezierPath,CAShapeLayer和CABasicAnimation 来自定义具有动画效果的弹出提示框(AlertView)。
1.在这里alertView继承的是UIWindow,
(1)基本思路是:在自定义的window添加一个子视图UIView,
(2)在view的层上添加一个子层CAShapeLayer,在子层上绘制UIBezierPath路径,往层上添加CABasicAnimation动画,动画按路径运行
(3)往window上添加两个UILabel显示消息标题和内容,添加一个取消按钮和一个确定按钮
2.实现步骤
(1)XSAlertView.h
<span style="font-size:18px;">typedef enum : NSInteger{ /** * 点击确定按钮 */ XSAlertViewClickOk, /** * 点击取消按钮 */ XSAlertViewClickCancel } XSAlertViewClickType; /** * 提示框的样式 */ typedef enum : NSInteger { XSAlertviewStyleDefault, // 默认样式----成功 XSAlertviewStyleSuccess, // 成功 XSAlertviewStyleFail, // 失败 XSAlertviewStyleWaring // 警告 } XSAlerTviewStyle; typedef void(^Completion)(XSAlertViewClickType buttonIndex); @interface XSAlertView : UIWindow { } // 按钮单击回调block @property (nonatomic,strong)Completion completeBlock; /** * 单例 * * @return 返回XSAlertView对象 */ + (id)shared; /** * 创建AlertView并展示 * * @param style 绘制的图片样式 * @param title 警示标题 * @param message 警示内容 * @param cancel 取消按钮标题 * @param ok 确定按钮标题 * @param completion 按钮点击时回调 * * @return 返回XSAlertView */ + (id)showAlertWithStyle:(XSAlerTviewStyle)style title:(NSString *)title message:(NSString *)message cancelButtonTitle:(NSString *)cancel okButtonTitle:(NSString *)ok completion:(Completion)completion;</span></span>(2)创建单例,节约内存
<span style="font-size:18px;">static XSAlertView *alertView = nil; +(id)shared { // 同步锁 static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ alertView = [[XSAlertView alloc]init]; }); return alertView; }</span>(3)创建UIView,用于绘制logo
<span style="font-size:18px;">- (void)_logoInit { // 移除上一次绘制 [_logoView removeFromSuperview]; _logoView = nil; // 创建新画布 _logoView = [[UIView alloc]init]; _logoView.center = CGPointMake(self.center.x, self.center.y); _logoView.bounds = CGRectMake(0.f, 0.f, kScreenWidth / 1.5f, kScreenHeight / 2.5f); _logoView.backgroundColor = [UIColor colorWithWhite:1.f alpha:0.7f]; _logoView.layer.cornerRadius = 10.f; _logoView.layer.shadowOffset = CGSizeMake(0.f, 5.f); _logoView.layer.shadowColor = [UIColor blackColor].CGColor; _logoView.layer.shadowOpacity = 0.3f; // 不透明度:0表示完全透明 _logoView.layer.shadowRadius = 10.f; // 保证画布在最底层 if (_titleLabel != nil) { [self insertSubview:_logoView belowSubview:_titleLabel]; } else { [self addSubview:_logoView]; } } </span>(4)往window上添加按钮和标签,此处比较简单,代码简单繁琐,就不列出了。
(5)往_logoView的层上添加层,绘制路径,此处给出绘制提示正确的弹出框的图片代码
<span style="font-size:18px;">- (void)_drawRight { // 初始化画布 [self _logoInit]; // 圆的中心 CGPoint pathCenter = CGPointMake(_logoView.frame.size.width / 2.f, _logoView.frame.size.height / 2.f - 50); // 画圆(360度的弧线) UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:pathCenter radius:40.f startAngle:0 endAngle:M_PI * 2 clockwise:YES]; // 勾的起点坐标 CGFloat x = _logoView.frame.size.width / 2.5f + 5.f; CGFloat y = _logoView.frame.size.height / 2.f - 45.f; path.lineCapStyle = kCGLineCapRound; path.lineJoinStyle = kCGLineCapRound; // 画勾的起点 [path moveToPoint:CGPointMake(x, y)]; [path addLineToPoint:CGPointMake(x + 10.f, y + 10.f)]; [path addLineToPoint:CGPointMake(x + 35.f, y - 20.f)]; // 新建层 CAShapeLayer *layer = [[CAShapeLayer alloc]init]; layer.fillColor = [UIColor clearColor].CGColor; layer.strokeColor = [UIColor greenColor].CGColor; layer.lineWidth = 5.f; layer.path = path.CGPath; CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; animation.fromValue = @0; animation.toValue = @1; animation.duration = 0.5f; [layer addAnimation:animation forKey:@"strokeEnd"]; [_logoView.layer addSublayer:layer]; </span>在这里值得一提的是,CAshapeLayer的strokeStart,strokeEnd与CABasicAnimation 的fromValue,toValue的用法和做出的效果下面是我个人对这个的总结:
<span style="font-size:18px;">1 keyPath = strokeStart 动画的fromValue = 0,toValue = 1 strokeEnd默认为1,strokeStart从 0 到 1 ,strokeStart = 0 时有一条完整的路径,strokeStart = 1 时 路径消失,效果就是一条从路径起点到终点慢慢的消失 2 keyPath = strokeStart 动画的fromValue = 1,toValue = 0 strokeEnd默认为1,strokeStart从 1 到 0 ,strokeStart = 1 时无路径,strokeStart = 0 时 画出一条完整的路径,效果就是一条从路径终点到起点慢慢的出现 3 keyPath = strokeEnd 动画的fromValue = 0,toValue = 1 strokeStart默认为0,strokeEnd从 0-1,strokeEnd=0 时,无路径,strokeEnd=1 时,一条完整路径。效果就是一条从路径起点到终点慢慢的出现 4 keyPath = strokeEnd 动画的fromValue = 1,toValue = 0 效果就是反方向路径慢慢消失</span>
<span style="font-size:18px;">/** * 创建AlertView并展示 * * @param style 绘制的图片样式 * @param title 警示标题 * @param message 警示内容 * @param cancel 取消按钮标题 * @param ok 确定按钮标题 * @param completion 按钮点击时回调 * * @return 返回XSAlertView */</span>
<pre name="code" class="objc"><span style="font-size:18px;">+(id)showAlertWithStyle:(XSAlerTviewStyle)style title:(NSString *)title message:(NSString *)message cancelButtonTitle:(NSString *)cancel okButtonTitle:(NSString *)ok completion:(Completion)completion { switch (style) { // 成功、默认 case XSAlertviewStyleDefault: case XSAlertviewStyleSuccess: [[self shared] _drawRight]; break; // 失败 case XSAlertviewStyleFail: [[self shared] _drawWrong]; break; // 警告 case XSAlertviewStyleWaring: [[self shared] _drawWaring]; default: break; } [[self shared] _addButtonTitleWithCancle:cancel OK:ok]; [[self shared] _addTitle:title message:message]; [[self shared] setCompleteBlock:nil];//释放掉之前的Block [[self shared] setCompleteBlock:completion]; [[self shared] setHidden:NO];//设置为不隐藏 return [self shared]; </span>}
(7) 最后调用我们自己写的弹出框
<span style="font-size:18px;">- (void)show:(UIButton *)button { NSString * title = nil; NSString * message = nil; NSString * cancle = @"取消"; NSString * ok = @"确定"; switch (button.tag+1) { // 成功 case XSAlertviewStyleSuccess: case XSAlertviewStyleDefault: title = @"温馨提示"; message = @"登录成功"; cancle = nil; break; // 失败 case XSAlertviewStyleFail: title = @"错误提示"; message = @"您输入的号码有误。"; break; // 警告 case XSAlertviewStyleWaring: title = @"警告"; message = @"您确定要开抢吗!!"; default: break; } //为成员变量Window赋值则立即显示Window _alertWindow = [XSAlertView showAlertWithStyle:button.tag+1 title:title message:message cancelButtonTitle:cancle okButtonTitle:ok completion:^(XSAlertViewClickType buttonIndex) { if (buttonIndex == 0) { NSLog(@"确定"); // ... } else { NSLog(@"取消"); // ... } //Window隐藏 _sheetWindow.hidden = YES; //置为nil,释放内存 _sheetWindow = nil; }]; } </span>
最终的效果图:
完整代码在我的上传的资源中。