Objective
Apple added a pop gesture to the navigation controller after IOS7, as long as the finger is sliding at the edge of the screen, the current controller's view will follow your finger, and when the user has let go, the system will determine whether the finger is being dragged out to determine if the controller's pop operation is to be performed.
Nav_pop_origin.gif
The idea of this operation is very good, but the system gives us the scope must be the left edge of the screen can be triggered, so that the actual use of some products will be inconvenient, so some apps take the whole screen to respond to this gesture and pop animation or the system is original, so it is really convenient to operate a lot.
Nav_pop_custom.gif
At first, we must have a question, to add a gesture to the controller's view and then drag the controller's view to change its frame is not it? Yes, the idea of adding gestures is correct. However, by ourselves to change the position of the controller view is more troublesome, attentive friends must have found that our custom pop gesture above the navigation bar is also in line with your gesture dragged and changed, so this will also need to be responsible for the navigation bar animation, and there is a key issue, if you drag the view alone, The view below will be black and black, because the controller's push and pop levels are managed by the system.
Nav_pop_failed.gif
Therefore, although it is possible to go this way, it will be more difficult to achieve. So how do you achieve this effect? Today we will provide two sets of implementation solutions.
[1]
Scenario One: Customizing the Uiviewcontrollerinteractivetransitioning object to implement the navigation controller proxy method.
This is Apple's official recommended practice, as described in WWDC 218-custom transitions Using View controllers.
Although this scheme is difficult to achieve, but the animation is relatively flexible, you can achieve this effect,
Nav_pop_cube.gif
can also have this effect.
Nav_pop_flip.gif
In fact, this drag process belongs to the navigation controller animation, so we need to rewrite Uinavigationcontroller's two proxy methods, Navigationcontroller:animationcontrollerforoperation: Fromviewcontroller:toviewcontroller: (name is very long below is called Method 1) and
Navigationcontroller:interactioncontrollerforanimationcontroller: (Method 2).
Explain what they do, Method 1 is what Apple provides to us to rewrite transitions between controllers (pop or push). Method 2 You can understand that Apple allows us to return an interactive object to manage the completion of transitions between controllers in real time, through which we can let the controller transition animation interact with the user (note that if Method 1 returns nil, Method 2 is not called, that is, Only our custom animations can interact with the controller.
Let's take a look at the implementation process. To make it easier for everyone to understand, I'll try to write the most clear notes in the demo.
At the same time, we use the simplest code to implement, at the end of this article I will give the demo in this example to provide a relatively reasonable wording.
First, in Method 1, we return an object that adheres to the Uiviewcontrolleranimatedtransitioning protocol, which is a custom animated object, and we name it popanimation, which implements two methods in this class to customize the transition animation.
Screen shot 2015-03-28 pm 6.49.05.png
Looking again at Method 2, we need to return an object that complies with the UIVIEWCONTROLLERINTERACTIVETRANSITIONING protocol (hint that these two protocols are easy to confuse, be aware of the distinction, one is responsible for animation, one is responsible for the interaction process), Apple already has a class that specializes in this function, it's called uipercentdriveninteractivetransition, and of course you can customize a class like this. We can understand its role in this way: The animation that was returned in Method 1 before is decomposed by the system for user interaction during execution, and is controlled by the animation completion of the interactive process. Let's take a look at how to use it. (For the Controller view to drag, we add a drag gesture to the controller's view, in the drag method we manipulate the object)
Screen shot 2015-03-29 pm 12.33.59.png
The last two ways to rewrite the navigation bar in the View controller.
Screen shot 2015-03-29 pm 12.37.51.png
There are two points not to forget:
- Sets the agent for the navigation controller to the current controller.
- Add gestures to the controller.
OK, so we're done with this process.
Nav_pop_own.gif
[2]
Scenario Two: RUNTIME+KVC
To understand this, you need to have some knowledge of the runtime, will involve private variables, private methods of access, but it is relatively simple and interesting, if you are interested in continue to look. About runtime knowledge, in the future I will share the blog, friends please look forward to.
To make it easier for you to read the code below, we need to understand the system's gesture first.
Before we learned that this gesture belonged to Uinavigationcontroller, we jumped into its header file to see if we could find a clue. The idea is correct, indeed there is a gesture called Interactivepopgesturerecognizer. The property is ReadOnly, which means we can't change it to a custom gesture, but we can set enable=no. OK, now that you have found it, print it and see what gesture it is.
Screen shot 2015-03-26 pm 5.17.35.png
Through log, we see that he belongs to the class Uiscreenedgepangesturerecognizer (which I have not used before), it inherits from Uipangesturerecognizer, appears after IOS7, is specifically handling the type of gesture triggered at the edge of the screen, and only one property is called edges, which sets its trigger edge (top, bottom, left, right, all). See here some friends will think, directly change its edges for all can? It has been experimentally learned that this property is useless, it can only be used to trigger the edge, set to all the meaning is four direction of the edge will be triggered, and used to do the controller pop gesture only the left edge.
Let's keep looking at its log. In addition to printing its class, the console prints its trigger target:_uinavigationinteractivetransition (this is a private class that appears to be specifically used for interactive animation of the navigation controller), and the action: Handlenavigationtransition (This is a private method of it), all we have to do is create a new uipangesturerecognizer and let it trigger the same gesture as the system, This requires the runtime to obtain the target and action of the system gesture.
So how do you get the target? At first I used KVC want to directly get the target of this gesture, the program crashed, originally it didn't have such a property. So what I can think of is, first use runtime to traverse all of its member variables to see how the system stores this property,
Screen shot 2015-03-29 pm 3.25.02.png
With log we can see that Uigesturerecognizer has a property called _targets, which is of type Nsmutablearray.
Screen shot 2015-03-29 pm 3.25.09.png
It is an array to store each target-action, so you can dynamically increase the gesture trigger object. So what is the storage of every target-action? To understand this we get the name of this property "_targets" to get it through KVC, and then print it out.
Screen shot 2015-03-29 pm 3.33.54.png
Screen shot 2015-03-29 pm 3.34.01.png
As you can see, because the system has rewritten its description method, we have no way of printing to get what type this object is. Since we cannot print, we use breakpoints to debug, to see its true type,
Screen shot 2015-03-29 pm 3.37.32.png
We see that each target-action is stored in a class like Uigesturerecognizertarget, which is also a private class.
There is a reason why Apple has privatized many of the classes, and it is not useful to have this class in peacetime, and one of their purposes is to avoid exposing developers to useless classes that affect encapsulation. So in the design of the class, still want to learn from Apple.
Look directly at the code below.
We add this code to the viewdidload of the controller, and it only needs to be executed once.
Screen shot 2015-03-29 pm 4.07.48.png Optimization
This demo I will provide to you, the following simple procedure to optimize the idea.
Optimization Point one: For the scheme one, in fact, the navigation controller should not be the proxy method and gesture processing method to the view controller, because this code is not part of a view controller, but the global navigation controller, so we should refer to Apple's design idea: A new object specifically to manage the interaction process, This class we call navigationinteractivetransition.
Optimization Point two: Then look at the previous viewdidload only execute once code, in fact, written here is not appropriate, the same, this code does not belong to a controller, the optimization scheme is to create a new navigation controller, This code is written in the viewdidload of the navigation controller and does not require dispatch once.
Optimization Point three: Because our custom gestures are added to a private view, this view is a global, so when this controller is the root controller, our gestures are still in effect, which is equivalent to the root controller to do a pop operation, which will cause an error nested pop Animation can result in corrupted navigation bar. The cause of this error is another, if our pop animation is executing, and then to trigger a gesture, will cause the navigation controller and navigation bar animation confusion. To avoid the problem we need to be the proxy of the gesture, to determine whether the current controller is the root controller and whether the pop or push animation is executing (the variable is private and needs to be obtained with KVC).
Screen shot 2015-03-30 pm 5.06.24.png
After the final optimization, the view controller can write nothing, want to use this effect, as long as the use of our custom navigation controller can be, the advantage is that gesture animation and controller completely decoupled, and do not have to addgesture each controller.
To recommend a warehouse https://github.com/nst/iOS-Runtime-Headers, this warehouse can be transferred to all the Apple private method header files, quite powerful.
Finally put this demo address: https://github.com/zys456465111/CustomPopAnimation (when used, switch project scheme will be able to switch different programs.) For scenario two, only the class of the navigation controller is required. )
Thank you, easy to learn the series will continue, I will try to write more easily understandable articles, so that development is easy to get up?
Original link: http://www.jianshu.com/p/d39f7d22db6c
[1]: program one.?
[2]: Scenario two.?
iOS uses runtime custom controller pop gesture Animation (classic)