Skip to content

apadalko/APTransitionDirector

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

18 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

APTransitionDirector

APTransitionDirector

Example Usage

You could use director in one of this ways

  • Basical Usage (for interactive and staic trasitions)
  • category (APTransitions) & APTransitionProtocol (for static transitions)
  • category (APTransitions) & blocks (for static transitions) - not implemented yet
  • category (APRuleInteractiveTransitions) & APTransitionRule (for interactive transitions)
  • category (APInteractiveTransitions) (for interactive transitions, the same as pervious but faster to implement) - not inplemented yet and more...

Basical Usage

The main class is APTransitionDirector - its responds of all trasition protocols that iOS have:

<UIViewControllerAnimatedTransitioning,UINavigationControllerDelegate,UIViewControllerInteractiveTransitioning,UITabBarControllerDelegate,UIViewControllerTransitioningDelegate>

its super fast to create u own transition, even with basical usage(see the category usage below):

APTransitionDirector * director=[[APTransitionDirector alloc]init];
director.animBlock=^(APTransitionDirector * director ,void(^comlitBlock)() ){

};
self.navigationController.delegate=director;
[self.navigationController pushViewController:[[BUViewController alloc] init] animated:YES]
self.navigationController.delegate=nil;

Now you have the animation block ,where u could use any animations that u want,to get all needed views use the APFastAcces category of APTransitionDirector. Lets Add Some Cool Animations:

//BURootViewController.m
APTransitionDirector * director=[[APTransitionDirector alloc]init];
director.animDuration=0.5; //animation duration for director
director.animBlock=^(APTransitionDirector * director ,void(^comlitBlock)() ){
    //getting all needed views
    UIView* toView = [director toView];
    UIView* fromView= [director fromView];
    UIView *  containerView=  [director containerView];
   //presetup
    [containerView insertSubview:toView aboveSubview:fromView];
    [toView setFrame:CGRectMake(containerView.frame.size.width, toView.frame.origin.y, toView.frame.size.width, toView.frame.size.height)];
    fromView.transform=CGAffineTransformMakeScale(1.0, 1.0);
    //animation block
    [UIView animateWithDuration:director.animDuration delay:0 usingSpringWithDamping:0.8 initialSpringVelocity:0.1 options:UIViewAnimationOptionCurveEaseIn
    animations:^{
        [toView setCenter:CGPointMake(containerView.frame.size.width/2, toView.center.y)];
        fromView.transform=CGAffineTransformMakeScale(0.9, 0.9);
        } completion:^(BOOL finished) {
            fromView.transform=CGAffineTransformMakeScale(1.0, 1.0);
  //dont forget to call the complition block
            comlitBlock();
    }];

};
self.navigationController.delegate=director;
[self.navigationController pushViewController:viewController animated:YES]
self.navigationController.delegate=nil;

Pls note: When u use non interactive animations dont forget to call the complitBlock Also u could use @property (nonatomic)float animDuration; to make all things clear.

Ok,Great! But we could make it better by adding some interactive transitions. Let add EdgePanGesture to our navigationController:

//BURootViewController.m
UIScreenEdgePanGestureRecognizer * panGesture = [[UIScreenEdgePanGestureRecognizer alloc]initWithTarget:self action:@selector(screenPan:)];
[panGesture setDelegate:self];
panGesture.edges=UIRectEdgeLeft;
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
[self.navigationController.view addGestureRecognizer:panGesture];

and the screenPan Method:

//BURootViewController.m
- (void)screenPan:(UIGestureRecognizer*)pan {
    CGPoint location = [pan locationInView:self.view];
    static CGPoint firstTouch;
    static float fullDistance=0;
    static APTransitionDirector * animDirector=nil;

    switch (pan.state) {
        case UIGestureRecognizerStateBegan:
        {

            fullDistance=self.navigationController.view.frame.size.width;
            firstTouch=location;

            animDirector=[[APTransitionDirector alloc]init];
            animDirector.interactive=YES;
            animDirector.animDuration=0.33;
            [self.navigationController setDelegate:animDirector];

            animDirector.animBlock=^(APTransitionDirector * director,void(^comlitBlock)() ){

                UIView* toView = [director toView];
                UIView* fromView= [director fromView];
                UIView *  containerView=  [director containerView];

                [containerView insertSubview:toView belowSubview:fromView];
                toView.transform=CGAffineTransformMakeScale(1.0, 1.0);
                [toView setFrame:containerView.bounds];


                toView.transform=CGAffineTransformMakeScale(0.9, 0.9);

                [ UIView animateWithDuration:director.animDuration
                    animations:^{

                    [fromView setFrame:CGRectMake(fromView.frame.size.width, fromView.frame.origin.y, fromView.frame.size.width, fromView.frame.size.height)];
                    toView.transform=CGAffineTransformMakeScale(1.0, 1.0);

                }completion:^(BOOL finished) {

                }];
            };
            [self.navigationController popViewControllerAnimated:YES];
            break;
        case  UIGestureRecognizerStateChanged:
        {
            //update percent for every step
            [animDirector setPercent:location.x/fullDistance];
            break;
        }
        case UIGestureRecognizerStateCancelled:
        case UIGestureRecognizerStateEnded: {

            BOOL didComplete=NO;
            if (pan.state==UIGestureRecognizerStateEnded){
            didComplete = (location.x/fullDistance)>0.5?YES:NO;
            }

            //and end interactive transition at state ended or canceled
            [animDirector endInteractiveTranscation:didComplete complition:^{

            }];
            animDirector = nil;
            self.navigationController.delegate = nil;

            break;
        }
        default: {

            break;
        }

    }
  }

}

So the main things that u should do:

  • set director as interactive animDirector.interactive=YES;
  • update director percent [animDirector setPercent:location.x/fullDistance];
  • run director interactive endingMethod: [animDirector endInteractiveTranscation:didComplete complition:^{}];

That looks nice but wee need some more, lets use the @property (copy)UpdateBlock interactiveUpdateBlock, so we could create unique interactive transaction :

  • Let add new method that will create maskLayer to "fromView"
-(void)addMaskToView:(UIView*)view withPosition:(CGPoint)maskPosition{
    CAShapeLayer * maskLayer;
    if (!view.layer.mask) {
        maskLayer=[CAShapeLayer layer];
        view.layer.mask=maskLayer;
        maskLayer.fillRule=kCAFillRuleEvenOdd;
    }else{
        maskLayer=(CAShapeLayer*)view.layer.mask;
    }
        CGMutablePathRef path=CGPathCreateMutable();
        CGPathAddRect(path, nil, view.bounds);
        CGPathAddEllipseInRect(path, nil, CGRectMake(-28, maskPosition.y, 44, 44));
        maskLayer.path=path;
        CGPathRelease(path);
}
  • make some updates in our UIGestureRecognizerStateEnded and UIGestureRecognizerStateChanged:
//.....
case  UIGestureRecognizerStateChanged:
{

    animDirector.interactiveUpdateBlock=^(APTransitionDirector*director){
    UIView* fromView= [director fromView];
    [self addMaskToView:fromView withPosition:location];
    };
    //update percent for every step
    [animDirector setPercent:location.x/fullDistance];
    break;
}

case UIGestureRecognizerStateCancelled:
case UIGestureRecognizerStateEnded: {

    BOOL didComplete=NO;
    if (pan.state==UIGestureRecognizerStateEnded){
        didComplete = (location.x/fullDistance)>0.5?YES:NO;
    }   

        //and end interactive transition at state ended or canceled
    [animDirector endInteractiveTranscation:didComplete complition:^(APTransitionDirector*director){
    [director fromView].layer.mask=nil;

    }];
    animDirector = nil;
    self.navigationController.delegate = nil;
    break;
}
....

Ok, so now u have nice interactive and static transition.This code is in examples as well (BasicUsage-NavigationController) u also could check some others examples there,like Basic Usage with TabbarController and ViewController. Basic Usage NavigationController

As u maybe noticed there are a little bit of extra code.To avoid this u could use APTransitionProtocol and animDirector.delegate=someObject; Its pretty easy to use, u could see this in BasicUsage(APTransitionProtocol)-NavigationController. As well u didnt need always to call animDirector=nil or self.navigationController=nil ,its up to you.(see the asicUsage(APTransitionProtocol)-NavigationController example)

Category (APTransitions) & APTransitionProtocol

About

APTransitionDirector

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published