最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

iOS如何自定義控制器轉(zhuǎn)場(chǎng)動(dòng)畫push詳解

 更新時(shí)間:2017年12月22日 10:19:24   作者:Fendouzhe  
在平時(shí)開發(fā)中,有時(shí)候需要一些轉(zhuǎn)場(chǎng)動(dòng)畫給界面調(diào)整增添一些活力,而實(shí)現(xiàn)這些動(dòng)畫相對(duì)比較繁瑣。下面這篇文章主要給大家介紹了關(guān)于iOS如何自定義控制器轉(zhuǎn)場(chǎng)動(dòng)畫push的相關(guān)資料,需要的朋友可以參考下。

前言

最近有些空閑時(shí)間,整理了下最近做的項(xiàng)目,本文主要介紹了關(guān)于iOS自定義控制器轉(zhuǎn)場(chǎng)動(dòng)畫push的相關(guān)內(nèi)容,分享出來供大家參考學(xué)習(xí),下面話不多說了,來一起看看詳細(xì)的介紹吧。

效果圖:


iOS7 開始蘋果推出了自定義轉(zhuǎn)場(chǎng)的 API 。從此,任何可以用 CoreAnimation 實(shí)現(xiàn)的動(dòng)畫,都可以出現(xiàn)在兩個(gè) ViewController 的切換之間。并且實(shí)現(xiàn)方式高度解耦,這也意味著在保證代碼干凈的同時(shí)想要替換其他動(dòng)畫方案時(shí)只需簡(jiǎn)單改一個(gè)類名就可以了,真正體會(huì)了一把高顏值代碼帶來的愉悅感。

其實(shí)網(wǎng)上關(guān)于自定義轉(zhuǎn)場(chǎng)動(dòng)畫的教程很多,這里我是希望同學(xué)們能易懂,易上手。

轉(zhuǎn)場(chǎng)分兩種Push和Modal,所以自定義轉(zhuǎn)場(chǎng)動(dòng)畫也就肯定分兩種,今天我們講的是Push

自定義轉(zhuǎn)場(chǎng)動(dòng)畫Push

首先搭建界面,添加4個(gè)按鈕:

- (void)addButton{  
 self.buttonArr = [NSMutableArray array];  
 CGFloat margin=50;
 CGFloat width=(self.view.frame.size.width-margin*3)/2;
 CGFloat height = width;
 CGFloat x = 0;
 CGFloat y = 0;
 //列
 NSInteger col = 2;
 for (NSInteger i = 0; i < 4; i ++) {   
  x = margin + (i%col)*(margin+width);
  y = margin + (i/col)*(margin+height) + 150;
   
  UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
  button.frame = CGRectMake(x, y, width, height);
  button.layer.cornerRadius = width * 0.5;
  [button addTarget:self action:@selector(btnclick:) forControlEvents:UIControlEventTouchUpInside];
  button.backgroundColor = [UIColor colorWithRed:arc4random()%255/255.0 green:arc4random()%255/255.0 blue:arc4random()%255/255.0 alpha:1.0];
  button.tag = i+1;
  [self.view addSubview:button];
  [self.buttonArr addObject:button];
 }
}

添加動(dòng)畫:

- (void)setupButtonAnimation{  
 [self.buttonArr enumerateObjectsUsingBlock:^(UIButton * _Nonnull button, NSUInteger idx, BOOL * _Nonnull stop) {   
  // positionAnimation
  CAKeyframeAnimation *positionAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
  positionAnimation.calculationMode = kCAAnimationPaced;
  positionAnimation.fillMode = kCAFillModeForwards;
  positionAnimation.repeatCount = MAXFLOAT;
  positionAnimation.autoreverses = YES;
  positionAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
  positionAnimation.duration = (idx == self.buttonArr.count - 1) ? 4 : 5+idx;
  UIBezierPath *positionPath = [UIBezierPath bezierPathWithOvalInRect:CGRectInset(button.frame, button.frame.size.width/2-5, button.frame.size.height/2-5)];
  positionAnimation.path = positionPath.CGPath;
  [button.layer addAnimation:positionAnimation forKey:nil];   
  // scaleXAniamtion
  CAKeyframeAnimation *scaleXAniamtion = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale.x"];
  scaleXAniamtion.values = @[@1.0,@1.1,@1.0];
  scaleXAniamtion.keyTimes = @[@0.0,@0.5,@1.0];
  scaleXAniamtion.repeatCount = MAXFLOAT;
  scaleXAniamtion.autoreverses = YES;
  scaleXAniamtion.duration = 4+idx;
  [button.layer addAnimation:scaleXAniamtion forKey:nil];   
  // scaleYAniamtion
  CAKeyframeAnimation *scaleYAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale.y"];
  scaleYAnimation.values = @[@1,@1.1,@1.0];
  scaleYAnimation.keyTimes = @[@0.0,@0.5,@1.0];
  scaleYAnimation.autoreverses = YES;
  scaleYAnimation.repeatCount = YES;
  scaleYAnimation.duration = 4+idx;
  [button.layer addAnimation:scaleYAnimation forKey:nil];   
 }];
}

界面搭建好了:

然后想在Push的時(shí)候?qū)崿F(xiàn)自定義轉(zhuǎn)場(chǎng)動(dòng)畫首先要遵守一個(gè)協(xié)議UINavigationControllerDelegate

蘋果在 UINavigationControllerDelegate 中給出了幾個(gè)協(xié)議方法,通過返回類型就可以很清楚地知道各自的具體作用。

//用來自定義轉(zhuǎn)場(chǎng)動(dòng)畫
- (nullable id)navigationController:(UINavigationController *)navigationController         animationControllerForOperation:(UINavigationControllerOperation)operation            fromViewController:(UIViewController *)fromVC             toViewController:(UIViewController *)toVC NS_AVAILABLE_IOS(7_0);
//為這個(gè)動(dòng)畫添加用戶交互
- (nullable id)navigationController:(UINavigationController *)navigationController       interactionControllerForAnimationController:(id) animationController NS_AVAILABLE_IOS(7_0);

在第一個(gè)方法里只要返回一個(gè)準(zhǔn)守UIViewControllerInteractiveTransitioning協(xié)議的對(duì)象,并在里面實(shí)現(xiàn)動(dòng)畫即可

  • 創(chuàng)建繼承自 NSObject 并且聲明 UIViewControllerAnimatedTransitioning 的的動(dòng)畫類。
  • 重載 UIViewControllerAnimatedTransitioning 中的協(xié)議方法。
//返回動(dòng)畫時(shí)間
- (NSTimeInterval)transitionDuration:(nullable id)transitionContext;
//將動(dòng)畫的代碼寫到里面即可
- (void)animateTransition:(id)transitionContext;

首先我自定義一個(gè)名為L(zhǎng)RTransitionPushController的類繼承于NSObject準(zhǔn)守了UIViewControllerAnimatedTransitioning協(xié)議

 - (void)animateTransition:(id)transitionContext{  
 self.transitionContext = transitionContext;  
 //獲取源控制器 注意不要寫成 UITransitionContextFromViewKey
 LRTransitionPushController *fromVc = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
 //獲取目標(biāo)控制器 注意不要寫成 UITransitionContextToViewKey
 LRTransitionPopController *toVc = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];  
 //獲得容器視圖
 UIView *containView = [transitionContext containerView];
 // 都添加到container中。注意順序 目標(biāo)控制器的view需要后面添加
 [containView addSubview:fromVc.view];
 [containView addSubview:toVc.view];  
 UIButton *button = fromVc.button;
 //繪制圓形
 UIBezierPath *startPath = [UIBezierPath bezierPathWithOvalInRect:button.frame];
  
 //創(chuàng)建兩個(gè)圓形的 UIBezierPath 實(shí)例;一個(gè)是 button 的 size ,另外一個(gè)則擁有足夠覆蓋屏幕的半徑。最終的動(dòng)畫則是在這兩個(gè)貝塞爾路徑之間進(jìn)行的
 //按鈕中心離屏幕最遠(yuǎn)的那個(gè)角的點(diǎn)
 CGPoint finalPoint;
 //判斷觸發(fā)點(diǎn)在那個(gè)象限
 if(button.frame.origin.x > (toVc.view.bounds.size.width / 2)){
  if (button.frame.origin.y < (toVc.view.bounds.size.height / 2)) {
   //第一象限
   finalPoint = CGPointMake(0, CGRectGetMaxY(toVc.view.frame));
  }else{
   //第四象限
   finalPoint = CGPointMake(0, 0);
  }
 }else{
  if (button.frame.origin.y < (toVc.view.bounds.size.height / 2)) {
   //第二象限
   finalPoint = CGPointMake(CGRectGetMaxX(toVc.view.frame), CGRectGetMaxY(toVc.view.frame));
  }else{
   //第三象限
   finalPoint = CGPointMake(CGRectGetMaxX(toVc.view.frame), 0);
  }
 } 
 CGPoint startPoint = CGPointMake(button.center.x, button.center.y);
 //計(jì)算向外擴(kuò)散的半徑 = 按鈕中心離屏幕最遠(yuǎn)的那個(gè)角距離 - 按鈕半徑
 CGFloat radius = sqrt((finalPoint.x-startPoint.x) * (finalPoint.x-startPoint.x) + (finalPoint.y-startPoint.y) * (finalPoint.y-startPoint.y)) - sqrt(button.frame.size.width/2 * button.frame.size.width/2 + button.frame.size.height/2 * button.frame.size.height/2);
 UIBezierPath *endPath = [UIBezierPath bezierPathWithOvalInRect:CGRectInset(button.frame, -radius, -radius)];  
 //賦值給toVc視圖layer的mask
 CAShapeLayer *maskLayer = [CAShapeLayer layer];
 maskLayer.path = endPath.CGPath;
 toVc.view.layer.mask = maskLayer;
  
 CABasicAnimation *maskAnimation =[CABasicAnimation animationWithKeyPath:@"path"];
 maskAnimation.fromValue = (__bridge id)startPath.CGPath;
 maskAnimation.toValue = (__bridge id)endPath.CGPath;
 maskAnimation.duration = [self transitionDuration:transitionContext];
 maskAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
 maskAnimation.delegate = self;
 [maskLayer addAnimation:maskAnimation forKey:@"path"]; 
}

在控制器里面用來自定義轉(zhuǎn)場(chǎng)動(dòng)畫的方法里返回剛才自定義的動(dòng)畫類

- (id)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC{  
 if (operation == UINavigationControllerOperationPush) {
  return [LRTranstionAnimationPush new];
 }else{
  return nil;
 }
}

到此為止自定義轉(zhuǎn)場(chǎng)動(dòng)畫就完成了

pop的動(dòng)畫只是把push動(dòng)畫反過來做一遍這里就不細(xì)講了,有疑問的可以去看代碼

添加滑動(dòng)返回手勢(shì)

上面說到這個(gè)方法是為這個(gè)動(dòng)畫添加用戶交互的所以我們要在pop時(shí)實(shí)現(xiàn)滑動(dòng)返回

最簡(jiǎn)單的方式應(yīng)該就是利用UIKit提供的UIPercentDrivenInteractiveTransition類了,這個(gè)類已經(jīng)實(shí)現(xiàn)了UIViewControllerInteractiveTransitioning協(xié)議,同學(xué)men可以通過這個(gè)類的對(duì)象指定轉(zhuǎn)場(chǎng)動(dòng)畫的完成百分比。

//為這個(gè)動(dòng)畫添加用戶交互
- (nullable id)navigationController:(UINavigationController *)navigationController       interactionControllerForAnimationController:(id) animationController NS_AVAILABLE_IOS(7_0);

第一步 添加手勢(shì)

 UIPanGestureRecognizer *gestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
 [self.view addGestureRecognizer:gestureRecognizer];

第二步 通過用戶滑動(dòng)的變化確定動(dòng)畫執(zhí)行的比例

- (void)handlePan:(UIPanGestureRecognizer *)gestureRecognizer {  
 /*調(diào)用UIPercentDrivenInteractiveTransition的updateInteractiveTransition:方法可以控制轉(zhuǎn)場(chǎng)動(dòng)畫進(jìn)行到哪了,
  當(dāng)用戶的下拉手勢(shì)完成時(shí),調(diào)用finishInteractiveTransition或者cancelInteractiveTransition,UIKit會(huì)自動(dòng)執(zhí)行剩下的一半動(dòng)畫,
  或者讓動(dòng)畫回到最開始的狀態(tài)。*/   
 if ([gestureRecognizer translationInView:self.view].x>=0) {
  //手勢(shì)滑動(dòng)的比例
  CGFloat per = [gestureRecognizer translationInView:self.view].x / (self.view.bounds.size.width);
  per = MIN(1.0,(MAX(0.0, per)));   
  if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {    
   self.interactiveTransition = [UIPercentDrivenInteractiveTransition new];
   [self.navigationController popViewControllerAnimated:YES];    
  } else if (gestureRecognizer.state == UIGestureRecognizerStateChanged){    
   if([gestureRecognizer translationInView:self.view].x ==0){     
    [self.interactiveTransition updateInteractiveTransition:0.01];     
   }else{     
    [self.interactiveTransition updateInteractiveTransition:per];
   }    
  } else if (gestureRecognizer.state == UIGestureRecognizerStateEnded || gestureRecognizer.state == UIGestureRecognizerStateCancelled){    
   if([gestureRecognizer translationInView:self.view].x == 0){     
    [self.interactiveTransition cancelInteractiveTransition];
    self.interactiveTransition = nil;     
   }else if (per > 0.5) {     
    [ self.interactiveTransition finishInteractiveTransition];
   }else{
     
    [ self.interactiveTransition cancelInteractiveTransition];
   }
   self.interactiveTransition = nil;
  }     
 } else if (gestureRecognizer.state == UIGestureRecognizerStateChanged){
  [self.interactiveTransition updateInteractiveTransition:0.01];
  [self.interactiveTransition cancelInteractiveTransition]; 
 } else if ((gestureRecognizer.state == UIGestureRecognizerStateEnded || gestureRecognizer.state == UIGestureRecognizerStateCancelled)){   
  self.interactiveTransition = nil;
 }  
}

第三步 在為動(dòng)畫添加用戶交互的代理方法里返回UIPercentDrivenInteractiveTransition的實(shí)例

- (id)navigationController:(UINavigationController *)navigationController       interactionControllerForAnimationController:(id) animationController {
 return self.interactiveTransition;
}

如果感覺這篇文章對(duì)您有所幫助,順手點(diǎn)個(gè)喜歡,謝謝啦

代碼放在了GitHub上大家可以下載,當(dāng)然也可以通過本地下載

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

最新評(píng)論

清河县| 汕尾市| 济南市| 汤原县| 宜州市| 淮滨县| 玉树县| 丹巴县| 贵州省| 双峰县| 金昌市| 镇沅| 政和县| 昌江| 高邑县| 宕昌县| 金秀| 鄂伦春自治旗| 广平县| 大兴区| 大英县| 库伦旗| 金沙县| 胶南市| 崇州市| 大连市| 宝丰县| 大足县| 原阳县| 凯里市| 松桃| 厦门市| 信宜市| 三门县| 榆林市| 宁武县| 瑞金市| 随州市| 连平县| 北流市| 永福县|