SHTransitionBlocks 1.0.1

SHTransitionBlocks 1.0.1

测试已测试
语言语言 Obj-CObjective C
许可证 MIT
发布最后发布2014 年 12 月

Seivan Heidari 维护。



此库作为 SHUIKitBlocks 的组成部分被使用,覆盖了 Foundation、UIKit、CoreLocation、GameKit、MapKit 和 iOS 应用程序架构的许多其他方面,以填补这些方面缺失的部分。


概览

通过 blocks 提供动画过渡和交互式过渡的 API。交互式过渡带有处理手势和进度的 block 辅助工具。所有这些都在 UIViewController 的基础上进行分类,因此与 UINavigationController 和 UITabBarController 配合良好


安装

pod 'SHTransitionBlocks' 

配置

将这些放在指定的文件或您的项目前缀文件中

#import "UIViewController+SHTransitionBlocks.h"

或者

#import "SHTransitionBlocks.h"

SHNavigationControllerBlocks 一起使用

因此,我们将向 navigationControllers 视图的左侧边缘添加一个 pan 手势,用于弹出堆栈。这使得任何在 navigationController 上推入的控制器都可以通过左侧 pan 手势弹出自身。动画本身没有特别之处。

您始终可以查看 示例。只需下载 zip 文件并构建和运行。

 -(void)viewDidLoad; {
  [super viewDidLoad];

我们可以在 UINavigationController 堆栈的第一个视图控制器上添加块,但是这里必须执行 viewDidLoad,但是您可以轻松提取出来(只要取出整个块!)

  [self.navigationController SH_setAnimationDuration:0.5 withPreparedTransitionBlock:^(UIView *containerView, UIViewController *fromVC, UIViewController *toVC, NSTimeInterval duration, id<SHViewControllerAnimatedTransitioning> transitionObject, SHViewControllerAnimationCompletionBlock transitionDidComplete) {

有很多回调变量,让我们来分解它。

  • containerView,包含 fromVC.view 和 toVC.view 的容器
  • fromVC,正在推动的控制器,例如导航堆栈上的第一个视图控制器
  • toVC,在堆栈上被推入的控制器。
  • duration,动画时长,目前为 0.5。也可以按每个上下文设置。
  • transitionObject,包含上下文和反向标志。
  • transitionDidComplete block,动画完成后调用的 block。
    if (transitionObject.isReversed == NO) {
      toVC.view.layer.affineTransform = CGAffineTransformMakeTranslation(CGRectGetWidth(toVC.view.frame), 0);
    }
    else {
      toVC.view.layer.affineTransform = CGAffineTransformMakeTranslation(-CGRectGetWidth(toVC.view.frame), 0);
    }

请注意,我们使用 transitionObject 访问 isReversed 标志来检查弹出或推送

    [UIView animateWithDuration:duration delay:0 options:kNilOptions  animations:^{
      toVC.view.layer.affineTransform = CGAffineTransformIdentity;

      if(transitionObject.isReversed) {
        CGAffineTransform t = CGAffineTransformIdentity;
        t = CGAffineTransformMakeTranslation(CGRectGetWidth(fromVC.view.frame), 0);
        //      fromView.layer.affineTransform = CGAffineTransformScale(t, 0.5, 0.5);
        fromVC.view.layer.affineTransform = t;


      }
      else {
        CGAffineTransform t = CGAffineTransformIdentity;
        t = CGAffineTransformMakeTranslation(-CGRectGetWidth(fromVC.view.frame), 0);
        fromVC.view.layer.affineTransform = t;

      }

没有复杂的事情,只是一个正常的动画。注意我们使用了 duration 变量来进行 UIView Animation。

    } completion:^(BOOL finished) {
      toVC.view.layer.affineTransform = CGAffineTransformIdentity;
      fromVC.view.layer.affineTransform = CGAffineTransformIdentity;
      transitionDidComplete();
    }];

  }];

注意我们如何调用 transitionDidComplete(); 来清理块。

  [self.navigationController SH_setInteractiveTransitionWithGestureBlock:^UIGestureRecognizer *(
  UIScreenEdgePanGestureRecognizer *edgeRecognizer) {
    edgeRecognizer.edges = UIRectEdgeLeft;
    return edgeRecognizer;

我们可以使用跟随 block 的 UIScreenEdgePanGestureRecognizer,或者创建我们自己的并返回它。任何 UIGestureRecognizer 的子类都适用。在我们当前的情况下,我们将其设置为 UIRectEdgeLeft pans,因为我们正在弹出。

  } onGestureCallbackBlock:^void(UIViewController * controller, UIGestureRecognizer *sender, UIGestureRecognizerState state, CGPoint location) {
    UIScreenEdgePanGestureRecognizer * recognizer = (UIScreenEdgePanGestureRecognizer*)sender;
    CGFloat progress = [recognizer translationInView:sender.view].x / (recognizer.view.bounds.size.width * 1.0);
    progress = MIN(1.0, MAX(0.0, progress));

    if (state == UIGestureRecognizerStateBegan) {
      // Create a interactive transition and pop the view controller
      controller.SH_interactiveTransition = [[UIPercentDrivenInteractiveTransition alloc] init];
      [(UINavigationController *)controller popViewControllerAnimated:YES];
    }
    else if (state == UIGestureRecognizerStateChanged) {
      // Update the interactive transition's progress
      [controller.SH_interactiveTransition updateInteractiveTransition:progress];
    }
    else if (state == UIGestureRecognizerStateEnded || state == UIGestureRecognizerStateCancelled) {
      // Finish or cancel the interactive transition
      if (progress > 0.5) {
        [controller.SH_interactiveTransition finishInteractiveTransition];
      }
      else {
        [controller.SH_interactiveTransition cancelInteractiveTransition];
      }

      controller.SH_interactiveTransition = nil;
    }

  }];

稍微复杂一些,但拆解开来,一旦开始手势操作,我们将controller(在我们的例子中,即navigationController)的SH_interactiveTransition设置为UIPercentDrivenInteractiveTransition。我们仅在即将弹出时执行此操作,而不会在任何其他时候执行,因为我们希望在没有任何手势更新时弹出SH_interactiveTransition为nil。请注意,我们会在手势结束后将其设置为nil。

  [self.navigationController SH_setAnimatedControllerBlock:^id<UIViewControllerAnimatedTransitioning>(UINavigationController *navigationController, UINavigationControllerOperation operation, UIViewController *fromVC, UIViewController *toVC) {
    navigationController.SH_animatedTransition.reversed = operation == UINavigationControllerOperationPop;
    return navigationController.SH_animatedTransition;
  }];

在这里,我们使用SHNavigationControllerBlocks功能来实现这里的动画过渡,而不是使用代理回调。一旦创建原型,它也更容易提取出来。与代理相比,使用代码块进行原型设计更方便。

  [self.navigationController SH_setInteractiveControllerBlock:^id<UIViewControllerInteractiveTransitioning>(UINavigationController *navigationController, id<UIViewControllerAnimatedTransitioning> animationController) {
    return navigationController.SH_interactiveTransition;
  }];
}

如果我们当前没有任何正在处理的手势,则navigationController.SH_interactiveTransition将是nil,并发生普通弹出。但是,如果我们正在处理某个手势,则navigationController.SH_interactiveTransition将不是nil,并且会被作为手势进度处理的交互控制器传递。


API

@protocol SHViewControllerAnimatedTransitioning <UIViewControllerAnimatedTransitioning>
@property(nonatomic,assign,getter = isReversed) BOOL reversed;
@property(nonatomic,strong) NSMutableDictionary * userInfo;
@property(nonatomic,readonly) id<UIViewControllerContextTransitioning> transitionContext;
@end

typedef void(^SHTransitionAnimationCompletionBlock)();

typedef void(^SHTransitionPreparedAnimationBlock)(UIView * containerView,
                                                                   UIViewController * fromVC,
                                                                   UIViewController * toVC,
                                                                   NSTimeInterval duration,
                                                                   id<SHViewControllerAnimatedTransitioning> transitionObject,
                                                                   SHTransitionAnimationCompletionBlock transitionDidComplete
                                                                          );

typedef void(^SHTransitionAnimationBlock)(id<SHViewControllerAnimatedTransitioning> transitionObject);

typedef NSTimeInterval(^SHTransitionDurationBlock)(id<SHViewControllerAnimatedTransitioning> transitionObject);

typedef UIGestureRecognizer *(^SHTransitionGestureRecognizerCreationBlock)(UIScreenEdgePanGestureRecognizer * edgeRecognizer);

typedef void(^SHTransitionCallbackGestureRecognizerBlock)(UIViewController * controller,
                                                          UIGestureRecognizer * recognizer,
                                                          UIGestureRecognizerState state,
                                                          CGPoint location
                                                          );


@interface UIViewController (SHTransitionBlocks)

@property(nonatomic,strong, setter = SH_setInteractiveTransition:) UIPercentDrivenInteractiveTransition * SH_interactiveTransition;

-(void)SH_setInteractiveTransitionWithGestureBlock:(SHTransitionGestureRecognizerCreationBlock)theGestureCreateBlock
                            onGestureCallbackBlock:(SHTransitionCallbackGestureRecognizerBlock)theGestureCallbackBlock;

-(id<SHViewControllerAnimatedTransitioning>)SH_animatedTransition;

-(void)SH_setAnimationDuration:(NSTimeInterval)theDuration
   withPreparedTransitionBlock:(SHTransitionPreparedAnimationBlock)theBlock;

-(void)SH_setAnimatedTransitionBlock:(SHTransitionAnimationBlock)theBlock;
-(void)SH_setDurationTransitionBlock:(SHTransitionDurationBlock)theBlock;

@property(nonatomic,readonly) SHTransitionPreparedAnimationBlock SH_blockAnimationDurationWithPreparedTransition;
@property(nonatomic,readonly)  SHTransitionAnimationBlock SH_blockAnimatedTransition;
@property(nonatomic,readonly)  SHTransitionDurationBlock SH_blockDurationTransition;


@end

联系

如果您在项目中使用SHTransitionBlocks,我非常愿意听到您的想法。

电子邮件:[email protected]
推特:@seivanheidari


许可协议

SHTransitionBlocks是由Seivan于2013年创作的,并根据MIT许可协议免费分发。请参阅LICENSE.md文件。