@ Continue with the previous content, this chapter mainly introduces the switch of the view VC on the custom Viewcontroller container. Let's take a look at the container controllers Uinavigationcontroller and Uitabbarcontrolle that the system provides to us. R has an attribute viewcontrollers of type Nsarray, it is obvious that the view VC that needs to switch is stored. Similarly, we define a Containerviewcontroller, is a direct subclass of Uiviewcontroller, used as a container to rely on, the amount, the other attribute definitions see the code, here is not much to say. (PS: I used to do a number of custom view VC switching method, is to place a uiscrollview, and then put all the Childviewcontroller view frame x-coordinate, according to this 320 increment, you can imagine, so bad place, I feel that all VC once loaded on all manifested, and will not be switched into a temporary display and release.
@ lazy, 5 CHILDVC created with storyboard
Containerviewcontroller@interface Ftcontainerviewcontroller () @property (Strong, Nonatomic) Ftphotosenderviewcontroller *photosenderviewcontroller; @property (Strong, nonatomic) Ftvideosenderviewcontroller *videosenderviewcontroller, @property (Strong, nonatomic) Ftfilesenderviewcontroller *filesenderviewcontroller;@p Roperty (Strong, nonatomic) Ftcontactsenderviewcontroller *contactsenderviewcontroller; @property (Strong, Nonatomic) Ftclipboardsenderviewcontroller *clipboardsenderviewcontroller; @property (Strong, nonatomic) UIViewController *selectedviewcontroller; The currently selected Vc@property (Strong, nonatomic) Nsarray *viewcontrollers; CHILDVC array @property (assign, nonatomic) Nsinteger Currentcontrollerindex; Array of currently selected VCs under label @end@implementation ftcontainerviewcontroller#pragma mark-viewlifecycle methods-(void) viewDidLoad{ [Super Viewdidload]; CHILDVC self.Photosenderviewcontroller = [Self.storyboard instantiateviewcontrollerwithidentifier:@] Ftphotosenderviewcontroller "]; Self.videosenderviewcontroller = [Self.storyboard instantiateviewcontrollerwithidentifier:@] Ftvideosenderviewcontroller "]; Self.filesenderviewcontroller = [Self.storyboard instantiateviewcontrollerwithidentifier:@] Ftfilesenderviewcontroller "]; Self.contactsenderviewcontroller = [Self.storyboard instantiateviewcontrollerwithidentifier:@] Ftcontactsenderviewcontroller "]; Self.clipboardsenderviewcontroller = [Self.storyboard instantiateviewcontrollerwithidentifier:@] Ftclipboardsenderviewcontroller "]; Array of storage CHILDVC self.viewcontrollers = @[_photosenderviewcontroller,_videosenderviewcontroller,_ Filesenderviewcontroller,_contactsenderviewcontroller,_clipboardsenderviewcontroller]; The default is subscript 0 VC Self.selectedviewcontroller = self.selectedviewcontroller?: self.viewcontrollers[0]; Self.currentcontrollerindex = 0;}
@ Still, implementation of the Uiviewcontrolleranimatedtransitioning protocol animator class, but inside a change animation effect, the use of iOS7 new spring animation effect:
#import "FTMthTransitionAnimator.h" @implementation ftmthtransitionanimatorstatic cgfloat const kchildviewpadding = 16 ; static CGFloat Const kdamping = 0.5; The damping parameter represents elastic damping, and as the damping values get closer to 0.0, the animation's elasticity effect becomes more pronounced, and if you set the damping value to 1.0, the view animation will not have an elastic effect static CGFloat const kinitialspringvelocity = 0.5; Initialize Spring rate-(nstimeinterval) Transitionduration: (id<uiviewcontrollercontexttransitioning>) TransitionContext {return 1.0;} -(void) Animatetransition: (id<uiviewcontrollercontexttransitioning>) transitioncontext{/** *-ViewControlle Rforkey: We can access the transition through his two viewcontroller. *-Containerview: two x Viewcontroller containerview. *-Initialframeforviewcontroller and Finalframeforviewcontroller are the frames of each viewcontroller at the beginning and end of the transition. */Uiviewcontroller *fromviewcontroller = [Transitioncontext viewcontrollerforkey: Uitransitioncontextfromviewcontrollerkey]; Uiviewcontroller *toviewcontroller = [Transitioncontext viewcontrollerforkey: Uitransitioncontexttoviewcontrollerkey]; [[TraNsitioncontext Containerview] AddSubview:toViewController.view]; ToViewController.view.alpha = 0; BOOL goingright = ([Transitioncontext initialframeforviewcontroller:toviewcontroller].origin.x < [ Transitioncontext finalframeforviewcontroller:toviewcontroller].origin.x); CGFloat transdistance = [Transitioncontext containerview].bounds.size.width + kchildviewpadding; Cgaffinetransform transform = cgaffinetransformmaketranslation (goingright transdistance:-transdistance, 0); Cgaffinetransforminvert reversal ToViewController.view.transform = Cgaffinetransforminvert (transform);//Toviewcontroll Er.view.transform = Cgaffinetransformtranslate (ToViewController.view.transform, goingright? Transdistance:- Transdistance), 0); /** *----------Spring Animation ...-------* Use the timing curve described by the movement of the spring ' animations '. When ' Dampingratio ' is 1 o'clock, the animation will slow down smoothly to its final model value without oscillation. The damping ratio is less than the first to completely stop before it oscillates more and more. The initial speed of the spring can be used to specify the speed at which the object at the end of the simulation spring is moved before it attaches. This is a unit coordinate system, where 1 refers to the animation of the total distance traveled in the second. So, if you change the position of an object by 200PT in this animation, and you want the animation to behave as if the objectBody in motion, before the animation of 100PT/s starts, you will pass 0.5. You will usually want to pass 0 of the speed. */[UIView animatewithduration:[self Transitionduration:transitioncontext] delay:0 usingspringwithdamping:kdamping Initialspringvelocity:kinitialspringvelocity options:0x00 animations:^{fromViewController.view.transform = TRANSFO Rm FromViewController.view.alpha = 0; Cgaffinetransformidentity Reset, Initialize toViewController.view.transform = cgaffinetransformidentity; ToViewController.view.alpha = 1; } completion:^ (BOOL finished) {fromViewController.view.transform = cgaffinetransformidentity; Declaring the transition over--remember, you must not forget to call Completetransition at the end of the transition: this method. [Transitioncontext completetransition:! [Transitioncontext transitionwascancelled]]; }];} @end
The next code is the key to implementing a custom container switch. Typically, when we use a system-built class, the system framework creates a transition context object for us and passes it to the animation controller. But in our case, we need to customize the transition animation, so we need to take responsibility for the system framework and create the transition context object ourselves.
@interface ftmthtransitioncontext:nsobject <uiviewcontrollercontexttransitioning>-(instancetype) Initwithfromviewcontroller: (Uiviewcontroller *) Fromviewcontroller Toviewcontroller: (UIViewController *) Toviewcontroller goingright: (bool) goingright; @property (nonatomic, copy) void (^completionblock) (bool didcomplete); Property (Nonatomic, assign, getter=isanimated) bool animated; @property (nonatomic, assign, getter=isinteractive) bool Interactive Whether interactive @property (nonatomic, strong) Nsdictionary *privateviewcontrollers; @property (nonatomic, assign) CGRect Privatedisappearingfromrect, @property (nonatomic, assign) CGRect privateappearingfromrect; @property (Nonatomic, Assign) CGRect Privatedisappearingtorect, @property (nonatomic, assign) CGRect Privateappearingtorect; @property ( Nonatomic, weak) UIView *containerview; @property (nonatomic, assign) Uimodalpresentationstyle presentationstyle;@ End@implementation ftmthtransitioncontext-(Instancetype) Initwithfromviewcontroller: (UIViewContRoller *) Fromviewcontroller Toviewcontroller: (Uiviewcontroller *) Toviewcontroller goingright: (BOOL) goingRight {if ( self = [Super init]) {Self.presentationstyle = Uimodalpresentationcustom;self.containerview = Fromviewcontroller.view.superview;self.privateviewcontrollers = @{Uitransitioncont Extfromviewcontrollerkey:fromviewcontroller, Uitransitioncontexttoviewcontrollerkey : Toviewcontroller,};//Set The view frame properties which make sense in our Speci Alized Containerviewcontroller context. Views appear from and disappear to the sides, corresponding to where the icon buttons is positioned. So tapping a button to the right of the currently selected, makes the view disappear to the left and the new view appear F Rom the right. The animator object can choose to use this to determine whether the transition should is going left to right, or right to Left, for example.CGFloat traveldistance = (goingright-self.containerview.bounds.size.width:self.containerview.bounds.size.width); Self.privatedisappearingfromrect = Self.privateappearingtorect = Self.containerView.bounds; Self.privatedisappearingtorect = Cgrectoffset (self.containerView.bounds, traveldistance, 0); Self.privateappearingfromrect = Cgrectoffset (self.containerView.bounds,-traveldistance, 0);} return self;} -(CGRect) Initialframeforviewcontroller: (Uiviewcontroller *) Viewcontroller {if (Viewcontroller = = [Self Viewcontrollerforkey:uitransitioncontextfromviewcontrollerkey]) {return self.privatedisappearingfromrect;} else { return self.privateappearingfromrect;}} -(CGRect) Finalframeforviewcontroller: (Uiviewcontroller *) Viewcontroller {if (Viewcontroller = = [Self Viewcontrollerforkey:uitransitioncontextfromviewcontrollerkey]) {return self.privatedisappearingtorect;} else { return self.privateappearingtorect;}} -(Uiviewcontroller *) Viewcontrollerforkey: (NSString *) key {return Self.privateviewconTrollers[key];} -(void) Completetransition: (BOOL) Didcomplete {if (self.completionblock) {self.completionblock (didcomplete);}} Non-interactive, directly returns no, because no interaction is allowed, of course, the progress cancellation is not possible-(BOOL) transitionwascancelled {return no;} Non-interactive, directly do not operate, only to interact, the following 3 protocol methods make sense, can refer to the system to us a defined interactive controller//@interface Uipercentdriveninteractivetransition:nsobject <uiviewcontrollerinteractivetransitioning>-(void) Updateinteractivetransition: (CGFloat) PercentComplete {}- (void) finishinteractivetransition {}-(void) cancelinteractivetransition {} @end
@OK, the preparation is done, in order to imitate the Uiscrollview sliding switch, but because now shows the non-interactive, we define a SWIP (swipe) gesture.
Uiswipegesturerecognizer *leftgesture = [[Uiswipegesturerecognizer alloc] initwithtarget:self action: @selector ( Swapcontroller:)]; [Leftgesture Setdirection:uiswipegesturerecognizerdirectionleft]; [Self.view addgesturerecognizer:leftgesture]; Uiswipegesturerecognizer *rightgesture = [[Uiswipegesturerecognizer alloc] initwithtarget:self action: @selector ( Swapcontroller:)]; [Rightgesture setdirection:uiswipegesturerecognizerdirectionright]; [Self.view Addgesturerecognizer:rightgesture];
How to respond to gestures-(void) Swapviewcontrollers: (Uiswipegesturerecognizer *) swipegesturerecognizer{if ( Swipegesturerecognizer.direction = = Uiswipegesturerecognizerdirectionleft) {if (_currentcontrollerindex < 4) { _currentcontrollerindex++; } NSLog (@ "_currentcontrollerindex =%ld", (long) _currentcontrollerindex); Uiviewcontroller *selectedviewcontroller = Self.viewcontrollers[_currentcontrollerindex]; NSLog (@ "%s__%d__|%@", __function__,__line__,@ "right"); Self.selectedviewcontroller = Selectedviewcontroller; } else if (swipegesturerecognizer.direction = = uiswipegesturerecognizerdirectionright) {NSLog (@ "%s__%d__|%@", __FUN ction__,__line__,@ "left"); if (_currentcontrollerindex > 0) {_currentcontrollerindex--; } Uiviewcontroller *selectedviewcontroller = Self.viewcontrollers[_currentcontrollerindex]; Self.selectedviewcontroller = Selectedviewcontroller; }}//rewrite Selectedviewcontroller's SetteR (void) Setselectedviewcontroller: (Uiviewcontroller *) Selectedviewcontroller{nsparameterassert ( Selectedviewcontroller); [Self _transitiontochildviewcontroller:selectedviewcontroller];_selectedviewcontroller = SelectedViewController;} Toggle operation (Custom, Lenovo I in front of the Article NetEase tab bar switch, the system gives the Transitionfromviewcontroller, is a reason)-(void) _transitiontochildviewcontroller: ( Uiviewcontroller *) toviewcontroller{uiviewcontroller *fromviewcontroller = self.childViewControllers.count > 0? se Lf.childviewcontrollers[0]: nil; if (Toviewcontroller = = Fromviewcontroller) {return; } UIView *toview = Toviewcontroller.view; [Toview Settranslatesautoresizingmaskintoconstraints:yes];toview.autoresizingmask = Uiviewautoresizingflexiblewidth | Uiviewautoresizingflexibleheight;toview.frame = Self.view.bounds; Custom container Switching, Addchildviewcontroller is the key, it guarantees that you want to display the VC can be loaded into the container//and the so-called animation and context, just for the Transition animation effect//Therefore, even if you switch with Uiscrollview, there is no lack of a Ddchildviewcontroller, remember! [Fromviewcontroller willmovetoparentviewcontroller:nIL]; [Self addchildviewcontroller:toviewcontroller];if (!fromviewcontroller) {[Self.view addsubview: Toviewcontroller.view]; [Toviewcontroller Didmovetoparentviewcontroller:self];return;} Animator ftmthtransitionanimator *transitionanimator = [[Ftmthtransitionanimator alloc] init]; Nsuinteger FromIndex = [Self.viewcontrollers Indexofobject:fromviewcontroller]; Nsuinteger Toindex = [Self.viewcontrollers Indexofobject:toviewcontroller]; Context ftmthtransitioncontext *transitioncontext = [[Ftmthtransitioncontext alloc] Initwithfromviewcontroller: Fromviewcontroller toviewcontroller:toviewcontroller goingright: (Toindex > FromIndex)]; transitioncontext.animated = yes;transitioncontext.interactive = No;transitioncontext.completionblock = ^ (BOOL Didcomplete) {//because it is non-interactive, FROMVC can directly remove its parent ' s children controllers Array[fromviewcontroller.view Remo Vefromsuperview]; [Fromviewcontroller Removefromparentviewcontroller]; [Toviewcontroller DidmovetopaRentviewcontroller:self];if ([Transitionanimator respondstoselector: @selector (animationended:)]) {[ Transitionanimator animationended:didcomplete];}; Transition animations need to be based on the transition context, as we are customizing the context, so set [Transitionanimator Animatetransition:transitioncontext] manually;}
Done .
The above shows a non-interactive transition switch for a basic custom container. What about interactive? From above I define gestures as SWIP instead of pan, and you can see that non-interactive transitions do not fully implement the Uiscrollview-like effect of the page. Switch between FROMVC and TOVC in the form of a similar percentage, because we lack an interactive controller. In a custom container, the system is not providing a protocol to return the interactive controller to us, looked up a lot of information, and did not find a clear method, I think, with the implementation of the transition context, Follow the system approach and customize the implementation of the interactive protocol approach. We are going to think about how the system builds up this environment.
The following shows the response of the demo, currently in the study ....
@ Reprint Please specify:[email protected] confused little book
IOS7 new features Viewcontroller transition switch (III) switch---for custom view Controller container non-interactive