New Features of iOS7 ViewController Transition (2) System View Controller container switching animation --- push pop present dismis, ios7viewcontroller

Source: Internet
Author: User

New Features of iOS7 ViewController Transition (2) System View Controller container switching animation --- push pop present dismis, ios7viewcontroller

@ In the previous chapter, we introduced the major APIs added by iOS7. We can find that they are not dead-end methods. What apple provides to our developers is protocol interfaces, therefore, we can propose to write classes separately to implement various custom effects.

1. Let's take a look at the custom animation class implementing UIViewControllerAnimatedTransitioning.

/*** Custom animation class * implementation protocol ------> @ protocol UIViewControllerAnimatedTransitioning * the interface is responsible for switching the specific content, that is, "What should happen during switching" */@ interface MTHCustomAnimator: NSObject <expiration> @ end @ implementation MTHCustomAnimator // The system provides a switch context. We return the time required for the switch based on the Context Environment (NSTimeInterval) transitionDuration :( id <UIViewControllerContextTransitioning>) transitionContext {return 1.0;} // The main method to complete the container transition animation. Both settings and animations of w are completed in this method-(void) animateTransition :( id <strong>) transitionContext {// can be viewed as destination ViewController UIViewController * toViewController = [transitionContext viewControllerForKey: UITransitionContextToViewControllerKey]; // You can view it as source ViewController UIViewController * fromViewController = [transitionContext viewControllerForKey: UITransitionContextFromViewControll ErKey]; // Add toView to the container [[transitionContext containerView] addSubview: toViewController. view]; toViewController. view. alpha = 0.0; [UIView animateWithDuration: [self transitionDuration: transitionContext] animations: ^ {// There are many animation effects. Here we will show a left offset fromViewController. view. transform = CGAffineTransformMakeTranslation (-320, 0); toViewController. view. alpha = 1.0;} completion: ^ (BOOL finished) {fromViewController. View. transform = CGAffineTransformIdentity; // declare the end of the transition --> remember, do not forget to call completeTransition at the end of the transition: This method [transitionContext completeTransition :! [TransitionContext transitionWasCancelled];}
PS: the two methods in the Protocol show that the preceding two methods require a transfer context parameter, which is an object that complies with the UIViewControllerContextTransitioning protocol. Generally, when we use the system class, the system framework creates a transfer context object for us and passes it to the animation controller.
// MainViewController @ interface MTHMainViewController () <strong, strong> @ property (nonatomic, strong) MTHCustomAnimator * customAnimator; @ property (nonatomic, strong) Comment * minToMaxAnimator; @ property (nonatomic, strong) MTHNextViewController * nextVC; // Interaction Controllers is implemented by following the UIViewControllerInteractiveTransitioning protocol. Controls interactive transfer. @ Property (strong, nonatomic) implements * interactionController; @ end @ implementation MTHMainViewController-(id) initWithNibName :( NSString *) nibNameOrNil bundle :( NSBundle *) implements {self = [super initWithNibName: nibNameOrNil bundle: nibBundleOrNil]; if (self) {// Custom initialization} return self;}-(void) viewDidLoad {[super viewDidLoad]; // Do any additional setup after loading the view. self. navigationItem. title = @ "Demo"; self. view. backgroundColor = [UIColor yellowColor]; // sets the proxy self. navigationController. delegate = self; // sets the transfer animation self. customAnimator = [[MTHCustomAnimator alloc] init]; self. minToMaxAnimator = [PDTransitionAnimator new]; self. nextVC = [[MTHNextViewController alloc] init]; // Present proxy and custom settings _ nextVC. transitioningDelegate = self; _ nextVC. modalPresentationStyle = UIModalPresentationCustom; // Push UIButton * pushButton = [UIButton buttonWithType: UIButtonTypeSystem]; pushButton. frame = CGRectMake (140,200, 40, 40); [pushButton setTitle: @ "Push" forState: UIControlStateNormal]; [pushButton addTarget: self action: @ selector (push) forControlEvents: UIControlEventTouchUpInside]; [self. view addSubview: pushButton]; // Present UIButton * modalButton = [UIButton buttonWithType: UIButtonTypeSystem]; modalButton. frame = CGRectMake (265,500, 50, 50); [modalButton setTitle: @ "Modal" forState: UIControlStateNormal]; [modalButton addTarget: self action: @ selector (modal) forControlEvents: UIControlEventTouchUpInside]; [self. view addSubview: modalButton]; // UIPanGestureRecognizer * panRecognizer = [[externalloc] initWithTarget: self action: @ selector (callback :)]; [self. navigationController. view addGestureRecognizer: panRecognizer];}-(void) push {[self. navigationController pushViewController: _ nextVC animated: YES];}-(void) modal {[self presentViewController: _ nextVC animated: YES completion: nil];} # Two Methods Added by pragma mark-UINavigationControllerDelegate iOS7 // animation effects-(id <strong>) navigationController :( UINavigationController *) navigationController animationControllerForOperation :( strong) operation fromViewController :( UIViewController *) fromVC toViewController :( UIViewController *) toVC {/*** typedef NS_ENUM (NSInteger, UINavigationControllerOperation) {* handle, * UINavigationControllerOperationPush, * handle ,*}; */if (operation = UINavigationControllerOperationPush) {return self. customAnimator;} else {return nil ;}// interaction-(id <UIViewControllerInteractiveTransitioning>) navigationController :( UINavigationController *) navigationController interactionControllerForAnimationController :( id <strong>) animationController {/*** in non-interactive animation effects, this method returns nil * interactive transfer. self-understanding means that you can control it through your own actions (common: gestures, unlike the default push or pop (non-interactive) */return _ interactionController;} # pragma mark-Transitioning Delegate (Modal) // The first two are used for animation-(id <strong>) animationControllerForPresentedController :( UIViewController *) presented presentingController :( UIViewController *) presenting sourceController :( UIViewController *) source {self. minToMaxAnimator. animationType = AnimationTypePresent; return _ minToMaxAnimator;}-(id <UIViewControllerAnimatedTransitioning>) animationControllerForDismissedController :( UIViewController *) dissed {self. minToMaxAnimator. animationType = AnimationTypeDismiss; return _ minToMaxAnimator;} // the last two are used for interaction-(id <strong>) interactionControllerForPresentation :( id <strong>) animator {return _ interactionController ;} -(id <UIViewControllerInteractiveTransitioning>) interactionControllerForDismissal :( id <UIViewControllerAnimatedTransitioning>) animator {return nil ;}
@ The above implementation is non-interactive transfer, which means that the user cannot cancel or control the progress switch in the middle according to the switch mechanism specified by the system. How can this achieve interactive transfer:

UIPercentDrivenInteractiveTransition implements the class of the UIViewControllerInteractiveTransitioning interface. You can use a percentage to control the interactive switching process. In gesture recognition, we only need to tell the current status percentage of the instance of this class, and the system calculates the UI rendering for US based on this percentage and the previously set migration method, very convenient. Several important methods:
-(Void) updateInteractiveTransition :( CGFloat) percentComplete update percentage. Generally, a value is calculated based on the length of Gesture Recognition and then updated. The detailed usage will be shown in the following example.
-(Void) cancelInteractiveTransition reports canceling interaction and returns the status before switching.
-(Void) finishInteractiveTransition: Report the interaction is completed and the status is updated to the switched status.

# Pragma mark-Main Implementation of gesture interaction ---> UIPercentDrivenInteractiveTransition-(void) didClickPanGestureRecognizer :( UIPanGestureRecognizer *) recognizer {UIView * view = self. view; if (recognizer. state = UIGestureRecognizerStateBegan) {// obtain the coordinates of the gesture's touch point CGPoint location = [recognizer locationInView: view]; // when the user slides from the right half, launch the next VC (based on actual needs, whether to push or launch) if (location. x> CGRectGetMidX (view. bounds) & self. navigationController. viewControllers. count = 1) {self. interactionController = [[UIPercentDrivenInteractiveTransition alloc] init]; // [self presentViewController: _ nextVC animated: YES completion: nil];} else if (recognizer. state = UIGestureRecognizerStateChanged) {// obtain the coordinate CGPoint translation = [recognizer translationInView: view] of the gesture offset on The view. // calculate a percentage based on the distance between the fingers and the drag, the animation effect of the switch also follows the percentage CGFloat distance = fabs (translation. x/CGRectGetWidth (view. bounds); // The Interaction controller controls the animation progress [self. interactionController updateInteractiveTransition: distance];} else if (recognizer. state = UIGestureRecognizerStateEnded) {CGPoint translation = [recognizer translationInView: view]; // calculate a percentage based on the distance between the fingers, the animation effect of the switch also follows the percentage CGFloat distance = fabs (translation. x/CGRectGetWidth (view. bounds); // if (distance> 0.5) {[self. interactionController finishInteractiveTransition];} else {[self. interactionController cancelInteractiveTransition];} // It must be set to nil self. interactionController = nil ;}}
@ Finally, I would like to share with you an animation special effect: Send a ViewController switch similar to that of Alibaba Cloud.

@ Implementation PDTransitionAnimator # define Switch_Time 1.2-(NSTimeInterval) transitionDuration :( id <strong>) transitionContext {return Switch_Time;} # define Button_Width 50.f# define Button_Space 10. f-(void) animateTransition :( id <UIViewControllerContextTransitioning>) transitionContext {UIViewController * toViewController = [transitionContext viewControllerForKey: UITran SitionContextToViewControllerKey]; UIViewController * fromViewController = [transitionContext viewControllerForKey: UITransitionContextFromViewControllerKey]; UIView * toView = toViewController. view; UIView * fromView = fromViewController. view; if (self. animationType = AnimationTypeDismiss) {// This method efficiently splits the currently displayed view into a new view. you can use this screenshot to display the view. for example, you may only want to use one animation. After all, it is too costly to use the original view for animation. because it intercepts existing content, this method can only reverse The current status information of the intercepted view should be displayed, but the information to be displayed after the captured view cannot be reflected. however, calling this method is much more efficient than loading a view. UIView * snap = [toView snapshotViewAfterScreenUpdates: YES]; [transitionContext. containerView addSubview: snap]; [snap setFrame: CGRectMake ([UIScreen mainScreen]. bounds. size. width-Button_Width-Button_Space, [UIScreen mainScreen]. bounds. size. height-Button_Width-Button_Space, Button_Width, Button_Width)]; [UIView ani MateWithDuration: [self transitionDuration: transitionContext] animations: ^ {[snap setFrame: [UIScreen mainScreen]. bounds];} completion: ^ (BOOL finished) {[UIView animateWithDuration: 0.5 animations: ^ {[[transitionContext containerView] addSubview: toView]; snap. alpha = 0;} completion: ^ (BOOL finished) {[snap removeFromSuperview]; [transitionContext completeTransition :! [TransitionContext transitionWasCancelled];} else {UIView * snap2 = [toView snapshotViewAfterScreenUpdates: YES]; [transitionContext. containerView addSubview: snap2]; UIView * snap = [fromView snapshotViewAfterScreenUpdates: YES]; [transitionContext. containerView addSubview: snap]; [UIView animateWithDuration: [self transitionDuration: transitionContext] animations: ^ {[snap setFrame: CGRectMake ([UIScreen mainScreen]. bounds. size. width-Button_Width-Button_Space + (Button_Width/2), [UIScreen mainScreen]. bounds. size. height-Button_Width-Button_Space + (Button_Width/2), 0, 0)];} completion: ^ (BOOL finished) {[UIView animateWithDuration: 0.5 animations: ^ {// snap. alpha = 0;} completion: ^ (BOOL finished) {[snap removeFromSuperview]; [snap2 removeFromSuperview]; [transitionContext contai NerView] addSubview: toView]; // do not forget [transitionContext completeTransition :! [TransitionContext transitionWasCancelled] ;}] ;}}
@ Among them, I am not very familiar with the snapshotViewAfterScreenUpdates method. It will be used at the beginning. You can also refer to the following analysis:

Before iOS7, you can take the following steps to obtain a snapshot of a UIView: first create a UIGraphics image context, and then render the view layer to this context to obtain an image, close the image context and display the image in UIImageView. Now we only need a line of code to complete the above steps:

[View snapshotViewAfterScreenUpdates: NO];
This method creates a copy of The UIView. If we want the view to save its current appearance before executing the animation, this method is especially convenient for later use (in an animation, the view may be overwritten or some other changes may occur.
The afterUpdates parameter indicates whether a snapshot is obtained after all effects are applied to the view. For example, if this parameter is set to NO, a snapshot of the current status of the view is immediately obtained. Otherwise, the following code can only get a blank snapshot:
[View snapshotViewAfterScreenUpdates: YES];
[View setAlpha: 0.0];
Because the afterUpdates parameter is set to YES, and the transparency value of the view is set to 0, the method will take a snapshot after the setting is applied to the view, so the screen is empty. And ...... You can take snapshots again ...... Continue snapshot ......

Finally, the main code has been provided. I have uploaded the complete code. If you are interested, you can download it. (alas, CSDN does not support gif dynamic images, my friends support blogs in the blog garden, but I don't like the style of the blog garden. It seems that it is king to get a domain name blog in the future, I will share some of my code to github later)
@ Reprinted please note,

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.