【iOS開發(fā)】轉(zhuǎn)場動畫(一)-簡單接觸

轉(zhuǎn)場動畫:
12.29
自己寫過一個轉(zhuǎn)場動畫以后,感覺這個轉(zhuǎn)場動畫設(shè)計的很好锦亦,邏輯清晰,自由度也比較大舔庶,而且實(shí)現(xiàn)起來也比較容易肚逸。
一朦促、present 動畫
問題:
1洒疚、為什么在+ animateTransition方法中乏德,一定要自己調(diào)用
[containerview addSubview:toVc.view]钝满。
這個有點(diǎn)想不明白悍引,不是應(yīng)該自己添加的嗎?帽氓?
我在第一次嘗試的時候,忘記把toVc.view 添加到上面去俩块,結(jié)果雖然最后調(diào)用了[transitionContext completeTransition:YES];,但是還是transationView 還在視圖中黎休,造成界面不能夠再操作。
現(xiàn)在想想玉凯,自己添加其實(shí)是有了更多的自由度势腮,可以用來管理什么時候再把新的toVc.view 添加到容器上。

自定義轉(zhuǎn)場動畫的實(shí)現(xiàn):
1漫仆、在要實(shí)現(xiàn)自定義轉(zhuǎn)場動畫的viewController 的初始化方法里面里面設(shè)置轉(zhuǎn)場動畫的代理和style:

self.transitioningDelegate = self;
self.modalPresentationStyle = UIModalPresentationCustom;

2捎拯、實(shí)現(xiàn)轉(zhuǎn)場動畫的代理方法。 這里只實(shí)現(xiàn)了最基本的兩個方法盲厌,即present 和dismiss動畫署照。另外還有手勢操作和動畫被打斷時的的代理方法。
這兩個代理方法都返回一個遵守<UIViewControllerAnimatedTransitioning>協(xié)議的對象吗浩,我這里是 CircleTransitionAnimation類建芙。

- (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source
{
    return [CircleTransitionAnimation transitioningWithType:CircleTransitionAnimationTypePresent];
}
- (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed
{
    return [CircleTransitionAnimation transitioningWithType:CircleTransitionAnimationTypeDismiss];
}

3、自定義遵守<UIViewControllerAnimatedTransitioning>協(xié)議的類懂扼,我這里是 CircleTransitionAnimation類禁荸。
在這個類中實(shí)現(xiàn)相關(guān)協(xié)議方法來完成轉(zhuǎn)場動畫:

#pragma mark UIViewControllerTransitioning
//這個方法返回轉(zhuǎn)場動畫的持續(xù)時長
- (NSTimeInterval)transitionDuration:(nullable id <UIViewControllerContextTransitioning>)transitionContext;
{
    return 0.5;
}

//這個方法是 轉(zhuǎn)場時要執(zhí)行的動畫,我把代碼分到兩個私有方法里面了
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext{
    //animation
    switch (_type) {
        case CircleTransitionAnimationTypePresent:
            [self presentAnimationWithContext:transitionContext];
            break;
        case CircleTransitionAnimationTypeDismiss:
            [self dismissAnimationWithContext:transitionContext];
        default:
            break;
    }
}

// This is a convenience and if implemented will be invoked by the system when the transition context's completeTransition: method is invoked.
- (void)animationEnded:(BOOL) transitionCompleted
{
    NSLog(@"animation ended");
}

#pragma mark CAAnimationDelegate
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
    NSLog(@"animationDidStop");
    switch (_type) {
        case CircleTransitionAnimationTypePresent:{
            NSLog(@"animationDidStop:present");
            id<UIViewControllerContextTransitioning> transitionContext = [anim valueForKey:@"transitionContext"];
            [transitionContext completeTransition:YES];
            NSLog(@"%@",[transitionContext viewControllerForKey:UITransitionContextToViewKey].view);
            //這邊為什么取不到 view???
            [transitionContext viewControllerForKey:UITransitionContextToViewKey].view.layer.mask = nil;
            
        }
            break;
        case CircleTransitionAnimationTypeDismiss:{
            NSLog(@"animationDidStop:dismiss");
            id<UIViewControllerContextTransitioning> transitionContext = [anim valueForKey:@"transitionContext"];
            [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
            if ([transitionContext transitionWasCancelled]) {
                [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey].view.layer.mask = nil;
            }
        }
            break;
    }
}

#pragma mark - custom delegates

#pragma mark - event responses

#pragma mark - public methods 
+ (instancetype)transitioningWithType:(CircleTransitionAnimationType)type
{
    CircleTransitionAnimation *transitioning = [[self alloc]init];
    transitioning.type = type;
    return transitioning;
}

#pragma mark - private methods
- (void)presentAnimationWithContext:(id <UIViewControllerContextTransitioning>)transitionContext
{
    //vc
    ViewController *fromVc = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIViewController *toVc = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    UIView *containerView = [transitionContext containerView];
    [containerView addSubview:toVc.view];
    //圓形放大動畫
    //mask
    UIBezierPath *startPath = [UIBezierPath bezierPathWithOvalInRect:fromVc.Btnframe];
    float radius = sqrt(kScreenWidth * kScreenWidth + kScreenHeight * kScreenHeight) / 2.0;
    //沒理解
//    CGFloat x = MAX(fromVc.Btnframe.origin.x, containerView.frame.size.width - fromVc.Btnframe.origin.x);
//    CGFloat y = MAX(fromVc.Btnframe.origin.y, containerView.frame.size.height - fromVc.Btnframe.origin.y);
//    CGFloat radius = sqrtf(pow(x, 2) + pow(y, 2));
    UIBezierPath *endPath = [UIBezierPath bezierPathWithArcCenter:containerView.center radius:radius startAngle:0 endAngle:M_PI * 2 clockwise:YES];
    CAShapeLayer *maskLayer = [CAShapeLayer new];
    maskLayer.path = endPath.CGPath;
    maskLayer.fillColor = [UIColor greenColor].CGColor;
    toVc.view.layer.mask = maskLayer;
    //animation
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"path"];
    animation.values = @[(__bridge id)startPath.CGPath,(__bridge id)endPath.CGPath];
    animation.duration = [self transitionDuration:transitionContext];
    animation.keyTimes = @[@1];
    animation.beginTime = CACurrentMediaTime();
    animation.removedOnCompletion = YES;
    animation.delegate = self;
    [animation setValue:transitionContext forKey:@"transitionContext"];
    [maskLayer addAnimation:animation forKey:@"path"];
}

- (void)dismissAnimationWithContext:(id <UIViewControllerContextTransitioning>)transitionContext
{
    UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UINavigationController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    ViewController *temp = toVC;
    UIView *containerView = [transitionContext containerView];
    //畫兩個圓路徑
    CGFloat radius = sqrtf(containerView.frame.size.height * containerView.frame.size.height + containerView.frame.size.width * containerView.frame.size.width) / 2;
    UIBezierPath *startCycle = [UIBezierPath bezierPathWithArcCenter:containerView.center radius:radius startAngle:0 endAngle:M_PI * 2 clockwise:YES];
    UIBezierPath *endCycle =  [UIBezierPath bezierPathWithOvalInRect:temp.Btnframe];
    //創(chuàng)建CAShapeLayer進(jìn)行遮蓋
    CAShapeLayer *maskLayer = [CAShapeLayer layer];
    maskLayer.fillColor = [UIColor greenColor].CGColor;
    maskLayer.path = endCycle.CGPath;
    fromVC.view.layer.mask = maskLayer;
    //創(chuàng)建路徑動畫
    CABasicAnimation *maskLayerAnimation = [CABasicAnimation animationWithKeyPath:@"path"];
    maskLayerAnimation.delegate = self;
    maskLayerAnimation.fromValue = (__bridge id)(startCycle.CGPath);
    maskLayerAnimation.toValue = (__bridge id)((endCycle.CGPath));
    maskLayerAnimation.duration = [self transitionDuration:transitionContext];
    maskLayerAnimation.delegate = self;
    maskLayerAnimation.timingFunction = [CAMediaTimingFunction  functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    [maskLayerAnimation setValue:transitionContext forKey:@"transitionContext"];
    [maskLayer addAnimation:maskLayerAnimation forKey:@"path"];
}

這樣就完成了一個簡單的轉(zhuǎn)場動畫,最終的效果圖如下:

CircleTransitioning.gif
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末阀湿,一起剝皮案震驚了整個濱河市赶熟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌陷嘴,老刑警劉巖映砖,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異罩旋,居然都是意外死亡啊央,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進(jìn)店門涨醋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瓜饥,“玉大人,你說我怎么就攤上這事浴骂∨彝粒” “怎么了?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長趣苏。 經(jīng)常有香客問我狡相,道長,這世上最難降的妖魔是什么食磕? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任尽棕,我火速辦了婚禮,結(jié)果婚禮上彬伦,老公的妹妹穿的比我還像新娘滔悉。我一直安慰自己,他們只是感情好单绑,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布回官。 她就那樣靜靜地躺著,像睡著了一般搂橙。 火紅的嫁衣襯著肌膚如雪歉提。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天区转,我揣著相機(jī)與錄音苔巨,去河邊找鬼。 笑死蜗帜,一個胖子當(dāng)著我的面吹牛恋拷,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播厅缺,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蔬顾,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了湘捎?” 一聲冷哼從身側(cè)響起诀豁,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎窥妇,沒想到半個月后舷胜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡活翩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年烹骨,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片材泄。...
    茶點(diǎn)故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡沮焕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出拉宗,到底是詐尸還是另有隱情峦树,我是刑警寧澤辣辫,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站魁巩,受9級特大地震影響急灭,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜谷遂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一葬馋、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧埋凯,春花似錦点楼、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽换怖。三九已至甩恼,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間沉颂,已是汗流浹背条摸。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留铸屉,地道東北人钉蒲。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像彻坛,于是被迫代替她去往敵國和親顷啼。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評論 2 355

推薦閱讀更多精彩內(nèi)容