今天我們看下按鈕轉(zhuǎn)場動畫的實現(xiàn)牌借,下面是不帶導航欄和帶導航欄的效果(不帶導航欄會好看些 = =)
一茁彭、button動畫相關代碼:
1.首先是SHAnimationButton熬丧,button對象的創(chuàng)建糕簿、屬性舵鳞、動畫開始結(jié)束方法以及代理方法等
SHAnimationButton.h
#import <UIKit/UIKit.h>
@class SHAnimationButton;
@protocol SHAnimationButtonDelegate <NSObject>
/**
動畫開始
@param SHAnimationButton SHAnimationButton
*/
- (void)SHAnimationButtonDidStartAnimation:(SHAnimationButton *)SHAnimationButton;
/**
動畫將要接結(jié)束
@param SHAnimationButton SHAnimationButton
*/
- (void)SHAnimationButtonWillFinishAnimation:(SHAnimationButton *)SHAnimationButton;
/**
動畫已經(jīng)結(jié)束
@param SHAnimationButton SHAnimationButton
*/
- (void)SHAnimationButtonDidFinishAnimation:(SHAnimationButton *)SHAnimationButton;
@end
@interface SHAnimationButton : UIButton
/**
代理對象
*/
@property (nonatomic, weak) id<SHAnimationButtonDelegate> delegate;
/**
創(chuàng)建對象
@param frame frame
@return 對象
*/
+ (instancetype)buttonWithFrame:(CGRect)frame;
/**
邊緣顏色
@param color color
*/
- (void)setborderColor:(UIColor *)color;
/**
邊緣寬度
@param width width
*/
- (void)setborderWidth:(CGFloat)width;
/**
手動執(zhí)行開始動畫(一般在button的響應里調(diào)用震檩,調(diào)用后會走代理進行回調(diào))
*/
- (void)startAnimation;
/**
手動停止動畫(停止前和停止后會走代理回調(diào))
*/
- (void)stopAnimation;
@end
SHAnimationButton.m
#import "SHAnimationButton.h"
#import "SHCircleAnimationView.h"
static NSTimeInterval startDuration = 0.3;
static NSTimeInterval endDuration = 0.5;
@interface SHAnimationButton ()
@property (nonatomic, strong) SHCircleAnimationView *circleView;
@property (nonatomic, assign) CGRect origionRect;
@end
@implementation SHAnimationButton
- (SHCircleAnimationView *)circleView{
if (!_circleView) {
_circleView = [SHCircleAnimationView viewWithButton:self];
[self addSubview:_circleView];
}
return _circleView;
}
+ (instancetype)buttonWithFrame:(CGRect)frame{
SHAnimationButton *button = [SHAnimationButton buttonWithType:UIButtonTypeCustom];
button.frame = frame;
button.layer.cornerRadius = frame.size.height / 2;
button.layer.masksToBounds = YES;
// 不裁剪超出父視圖的子視圖部分
button.clipsToBounds = NO;
button.origionRect = button.frame;
return button;
}
- (void)setborderColor:(UIColor *)color{
self.layer.borderColor = color.CGColor;
}
- (void)setborderWidth:(CGFloat)width{
self.layer.borderWidth = width;
}
- (void)startAnimation{
CGPoint center = self.center;
CGFloat width = self.layer.cornerRadius * 2;
CGFloat height = self.frame.size.height;
CGRect desFrame = CGRectMake(center.x - width / 2, center.y - height / 2, width, height);
self.userInteractionEnabled = NO;
if ([self.delegate respondsToSelector:@selector(SHAnimationButtonDidStartAnimation:)]) {
[self.delegate SHAnimationButtonDidStartAnimation:self];
}
[UIView animateWithDuration:startDuration animations:^{
self.titleLabel.alpha = .0f;
self.frame = desFrame;
} completion:^(BOOL finished) {
[self.circleView startAnimation];
}];
}
- (void)stopAnimation{
self.userInteractionEnabled = YES;
if ([self.delegate respondsToSelector:@selector(SHAnimationButtonWillFinishAnimation:)]) {
[self.delegate SHAnimationButtonWillFinishAnimation:self];
}
[self.circleView removeFromSuperview];
self.circleView = nil;
[UIView animateWithDuration:endDuration animations:^{
self.frame = self.origionRect;
self.titleLabel.alpha = 1.0f;
} completion:^(BOOL finished) {
if ([self.delegate respondsToSelector:@selector(SHAnimationButtonDidFinishAnimation:)]) {
[self.delegate SHAnimationButtonDidFinishAnimation:self];
}
}];
}
@end
2.然后是SHCircleAnimationView,利用UIBezierPath繪制外圍的圓圈視圖
SHCircleAnimationView.h
#import <UIKit/UIKit.h>
@interface SHCircleAnimationView : UIView
+ (instancetype)viewWithButton:(UIButton *)button;
- (void)startAnimation;
@end
SHCircleAnimationView.m
#import "SHCircleAnimationView.h"
@interface SHCircleAnimationView ()
@property (nonatomic, strong) UIColor *borderColor;
@property (nonatomic, strong) NSTimer *timer;
@property (nonatomic, assign) CGFloat timeFlag;
@end
@implementation SHCircleAnimationView
+ (instancetype)viewWithButton:(UIButton *)button{
SHCircleAnimationView *animationView = [[SHCircleAnimationView alloc] initWithFrame:CGRectMake(-8, -8, button.frame.size.width + 16, button.frame.size.height + 16)];
animationView.backgroundColor = [UIColor clearColor];
animationView.borderColor = button.titleLabel.textColor;
animationView.timeFlag = 0;
return animationView;
}
- (void)removeFromSuperview{
[self.timer invalidate];
[super removeFromSuperview];
}
- (void)startAnimation{
self.timer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:@selector(continueAnimation) userInfo:nil repeats:YES];
[self.timer fire];
}
- (void)continueAnimation{
self.timeFlag += 0.02;
// 因為drawRect方法只調(diào)用1次蜓堕,所以如果需要刷新圖形抛虏,需要用setNeedsDisplay強制調(diào)用刷新
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect{
UIBezierPath *path = [UIBezierPath bezierPath];
// 圓心
CGPoint center = CGPointMake(rect.size.width / 2, rect.size.height / 2);
// 半徑
CGFloat radius = rect.size.width / 2 - 2;
// 起始的弧度
CGFloat start = -M_PI_2 + self.timeFlag * 2 * M_PI;
// 圓弧結(jié)束的弧度
CGFloat end = -M_PI_2 + 0.45 * 2 * M_PI + self.timeFlag * 2 * M_PI;
[path addArcWithCenter:center radius:radius startAngle:start endAngle:end clockwise:YES]; // clockwise:YES為順時針,NO為逆時針
// 設置描邊色
[self.borderColor setStroke];
// 設置描邊寬度
path.lineWidth = 1.5;
// 描邊
[path stroke];
}
@end
二套才、navigation動畫相關代碼:
1.首先是SHNavAnimation迂猴,navgationController的動畫
SHNavAnimation.h
#import <UIKit/UIKit.h>
@interface SHNavAnimation : NSObject<UIViewControllerAnimatedTransitioning>
@property (nonatomic, strong) UIButton *centerButton;
@end
SHNavAnimation.m
#import "SHNavAnimation.h"
@interface SHNavAnimation ()<CAAnimationDelegate>
@property (nonatomic, strong) id <UIViewControllerContextTransitioning> transitionContext;
@end
@implementation SHNavAnimation
/**
動畫持續(xù)時間
@param transitionContext 轉(zhuǎn)場上下文
@return NSTimeInterval
*/
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext{
return 0.5;
}
/**
動畫的內(nèi)容
@param transitionContext 轉(zhuǎn)場上下文
*/
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext{
self.transitionContext = transitionContext;
UIView *contentView = [self.transitionContext containerView];
CGPoint point = self.centerButton.center;
// 創(chuàng)建在rect里的內(nèi)切曲線
UIBezierPath *origionPath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(point.x , point.y, 0, 0)];
CGFloat X = [UIScreen mainScreen].bounds.size.width - point.x;
CGFloat Y = [UIScreen mainScreen].bounds.size.height - point.y;
CGFloat radius = sqrtf(X * X + Y * Y);
UIBezierPath *finalPath = [UIBezierPath bezierPathWithOvalInRect:CGRectInset(CGRectMake(point.x , point.y, 0, 0), -radius, -radius)];
// 獲取參與轉(zhuǎn)場的視圖控制器
UIViewController *toVc = [self.transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
CAShapeLayer *layer = [CAShapeLayer layer];
layer.path = finalPath.CGPath;
toVc.view.layer.mask = layer;
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"path"];
animation.delegate = self;
// 所改變屬性的起始值
animation.fromValue = (__bridge id _Nullable)(origionPath.CGPath);
// 所改變屬性的結(jié)束時的值
animation.toValue = (__bridge id _Nullable)(finalPath.CGPath);
// 動畫的時長
animation.duration = 0.25;
// 添加動畫
[layer addAnimation:animation forKey:@"path"];
[contentView addSubview:toVc.view];
}
#pragma mark - CAAnimationDelegate
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{
[self.transitionContext completeTransition:YES];
}
@end
2.然后是SHNavigationController,自定義navigationController背伴,使用自定義的push方法
SHNavigationController.h
#import <UIKit/UIKit.h>
@interface SHNavigationController : UINavigationController
- (void)pushViewController:(UIViewController *)viewController withCenterButton:(UIButton*)button;
@end
SHNavigationController.m
#import "SHNavigationController.h"
#import "SHNavAnimation.h"
@interface SHNavigationController ()<UINavigationControllerDelegate>
@property (nonatomic, strong) UIButton *centerButton;
@end
@implementation SHNavigationController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)pushViewController:(UIViewController *)viewController withCenterButton:(UIButton *)button{
self.centerButton = button;
self.delegate = self;
[super pushViewController:viewController animated:YES];
}
#pragma mark - UINavigationControllerDelegate
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC{
SHNavAnimation *animation = [[SHNavAnimation alloc] init];
animation.centerButton = self.centerButton;
return animation;
}
@end
三沸毁、調(diào)用
需要先將controller放到SHNavigationController中
#import "ViewController.h"
#import "SHAnimationButton.h"
#import "SecondViewController.h"
#import "SHNavigationController.h"
@interface ViewController ()<SHAnimationButtonDelegate>
@property (nonatomic, strong) SHAnimationButton *button;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 可以在這里將navigationBar隱藏峰髓,效果會更好
self.navigationController.navigationBarHidden = YES;
self.view.backgroundColor = [UIColor cyanColor];
SHAnimationButton *okButton = [SHAnimationButton buttonWithFrame:CGRectMake(80, 100, self.view.bounds.size.width - 2 * 80, 50)];
okButton.delegate = self;
okButton.backgroundColor = [UIColor whiteColor];
[okButton setTitle:@"OK" forState:(UIControlStateNormal)];
[okButton setTitleColor:[UIColor redColor] forState:(UIControlStateNormal)];
[self.view addSubview:okButton];
[okButton addTarget:self action:@selector(click:) forControlEvents:(UIControlEventTouchUpInside)];
SHAnimationButton *loginButton = [SHAnimationButton buttonWithFrame:CGRectMake(30, 300, self.view.bounds.size.width - 2 * 30, 50)];
loginButton.delegate = self;
loginButton.backgroundColor = [UIColor whiteColor];
[loginButton setTitle:@"Login" forState:(UIControlStateNormal)];
[loginButton setTitleColor:[UIColor lightGrayColor] forState:(UIControlStateNormal)];
[self.view addSubview:loginButton];
[loginButton addTarget:self action:@selector(click:) forControlEvents:(UIControlEventTouchUpInside)];
self.button = loginButton;
}
- (void)click:(SHAnimationButton *)button{
[button startAnimation];
}
#pragma mark - SHAnimationButtonDelegate
- (void)SHAnimationButtonDidStartAnimation:(SHAnimationButton *)SHAnimationButton{
NSLog(@"開始動畫");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.8 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[SHAnimationButton stopAnimation];
});
}
- (void)SHAnimationButtonWillFinishAnimation:(SHAnimationButton *)SHAnimationButton{
NSLog(@"動畫將要結(jié)束時回調(diào) 即 結(jié)束動畫未執(zhí)行時");
if (SHAnimationButton == self.button) {
SecondViewController *secondVC = [[SecondViewController alloc] init];
[((SHNavigationController*)self.navigationController) pushViewController:secondVC withCenterButton:SHAnimationButton];
}
}
- (void)SHAnimationButtonDidFinishAnimation:(SHAnimationButton *)SHAnimationButton{
NSLog(@"結(jié)束動畫");
}
@end