Intercept the navigation Controller system back button click Pop and right Slide pop event

Source: Internet
Author: User

A few days ago looked at @ Luan Cloth an article: Custom Backbarbuttonitem, in the follow-up when I expanded some, writing this article is to summarize what they write, convenient to look at the easy to see, but also their own iOS one year time, Hope to write something to practice practiced hand, there is hope to share to everyone, hope that we discuss together, put forward valuable comments and more simple implementation. The overall effect is as follows:

At the same time by the @j_ rain easy to learn the--ios use runtime Custom controller pop gesture animation, so we will be implemented in two ways.

Implementation ideas

Each navigationcontroller comes with a navigationbar, a Navigationcontroller manages a viewcontroller stack, which can be managed better than a viewcontroller, Each viewcontroller corresponds to a navigationitem, and these navigationitem are rendered by Navigationbar.

If we customize the Leftbarbuttonitem of a viewcontroller Navigationitem, we can pass in the target and action when we instantiate the Leftbarbuttonitem. So that we can get to the clicked event, however, if we are not customized, but the system is backbarbuttonitem, at this time, we do not have the opportunity to pass the SEL type of action, then we have no way to directly implement this action.

Next we point to uibarbuttonitem this class inside go, see can find some clues, first found the two goods:

This means that as soon as we get a Uibarbuttonitem object, we can get the SEL through KVC, or we can assign the value by KVC (in fact, the Uibarbuttonitem class also provides these two properties.) III). So we hurried to the Uinavigationitem class to see, found four of the content shown.

Surprise came too suddenly, when we used, only to find this backbarbuttonitem forever nil (anyway I was looking for half a day, found that this item is nil, if you find, please tell me), such as (I am in viewdidappear interrupt point debugging, The result is nil):

Before I explored the method, through Luan's article, we know that each Uinavigationbar has four proxy methods, two of which need to return a bool value, these two methods determine whether to push,pop a navigationitem (generally speaking, A navigationitem corresponds to a viewcontroller). The system defaults to setting this delegate of Navigationbar to the Navigationcontroller that owns it (here, I suddenly think of another idea, I don't know if it works, for everyone to finish this article, I will put the idea I just thought to the end of the article , we hope to be verified together). That is to say, Navigationcontroller is the implementation of these methods or a few of them (because these proxy methods are @optional optional method, so may not be fully implemented, specifically not explored, but Navigationbar: Shouldpopitem: Must have been realized, don't believe? Look back), now we have to do is how to re-replace the default implementation of the system with our implementation, note that Navigationbar:shouldpopitem: the completion of the signature is:

- (BOOL)navigationbar:(uinavigationbar*)Navigationbar Shouldpopitem :(uinavigationitem*)item;

Returns a bool value, so we want to replace the default implementation of the system, we should return a bool value, and in order to be more perfect, we should not completely overwrite the implementation of the system, but just where we need to return no, we return no, and any other time, we should return to the default implementation of the system, It's more perfect. Here are two ideas for implementation.

Implemented by subclasses

The first approach is to use subclasses to overload the parent class's methods, directly on the code, and then explain why.

We pulled a. h file and defined a protocol. There is a method in this protocol, this method returns a bool value, if you read the above idea, this is a way we will be used to implement whether the pop. Well, this agreement will be put here first, we'll use it later.

Here we define a new subclass of Uinavigationcontroller called Yynavigationcontroller, and let it overload the Navigationbar:shouldpopitem of the parent class: method.

In this way, we can use this subclass to intercept the system to return the event of the button's ability, not anxious, we first to see how this subclass specific use, and then the implementation process.

We wrote this in appdelegate:

Nav's root view controller is root, then push a yysecondviewcontroller, and we give this attempt to the Controller object called second. If this second wants to have the ability to intercept the events of the system back button, simply do two things:

1, abide by the agreement we defined at the beginning, like this

2. Implement the Proxy method in our agreement, like this

The implementation here is, we pop up the warning box, and then return no, so that when we click on the System Back button, we do not directly do pop.

Ok, next, we'll comb through the above process. We click on the system's Back button, which is the way the program goes to line 35th in Figure 7. Go down this way, we first take out the navigation controller in the stack of VC, (the 40th to 42nd line, skip, and then say the role later) and then we see whether it implements the protocol we define, if it does not implement the Protocol (indicating that the VC does not have to do to intercept the system back button of the event of the plan), The result of jumping directly to 52 rows, return the default implementation of the system, that is, the implementation of the Uinavigationcontroller class (parent class), tune super the same name method. If the implementation of this Protocol, then the VC has this idea, so call the protocol in the method (line 45th), if someone returns no, we will give navigationbar to convey this meaning (line 49th), said VC temporarily don't want pop, This is Navigationbar will not pop. If the VC returns Yes, we return to the default implementation of the system (line 46th).

Everyone think of this process, originally Navigationbar do not know whether pop, so asked Navigationcontroller,navigationcontroller have their own default implementation, and the outside world has no relationship. And now we define the sub-class, Inherit Navigationcontroller, so that, navigationbar do not know whether the pop, ask this subclass, and this subclass of the practice is to first look at the top of his stack this VC has changed the system default implementation of this plan (compliance protocol) , if not, returns the default implementation of the Navigationcontroller (parent class), and if so, we will specifically ask it to make a decision if the VC returns YES (indicating that it is supported for pop, so we return to the default implementation). If not, we will mainly VC, directly return No.

Very simple, isn't there? There is still a problem, Uinavigationcontroller interface does not emit Navigationbar:shouldpopitem: This method interface (in fact, this is just a navigationcontroller to implement a protocol, is not placed in the interface), so we can not directly call super in the subclass of this method, compile will error. In order to solve this problem, we have used a few tricks (this does not know to call it a small skill is not appropriate?) ), which is the 12th to 22nd line of work in Figure 7.

We have added a category for Uinavigationcontroller. This method was added for Uinavigationcontroller, but it was not implemented in the category, so that the Uinavigationcontroller's already implemented private method burst out. If this method is implemented in this category, it is not certain which implementation is called when it is called. We take a slow look at the analysis, we put Navigationbar:shouldpopitem: Method called a method, will uinavigationcontroller called a class. There was a default implementation of a method in Class A. Except that the a method is not exposed in the Class A interface. Instead of adding a category to Class A, the class interface adds a method without implementation, and we know that the call method in OC is called by the method name comparison (superficial), so this is the equivalent of a private method in Class A that leaks out of the class interface, That is, the private method can be invoked externally through this classified interface. Again, if we implement this method in the classification, the implementation in the classification will eventually be added to the list of methods in Class A. So by the time you tune a method, the Class A method list has two implementations, which is uncertain. So we only declare it in the interface, but not the implementation.

But the implementation is empty, the compiler will give a (hateful) warning, this is we can use three macro to tell the compiler somewhere please do not emit that type of warning. The first sentence of these three words is called Push, the third game is called pop. Their middle code will not warn you. There are many caveats, and we need to tell the compiler what kind of warning it is. So how do we know the type of the warning, see:

That way you can get rid of those (annoying) warnings. PS: (personal feeling, unless it is determined that this is not an error, do not directly see the warning to do so).

This is finished, say a small place, we are in second (remember second is what?) Look back at Figure 10) before returning to No, we pop up the warning box and let's look at the proxy method of the warning box.

Line 77th is clicked to leave the button on this page and 87 lines is clicked to discard the edit buttons. Why not put it in one? This is all about personal hobbies, I'm here to talk about my idea, 74 lines of the method is alertview as long as a BTN click on the callback, and 78~79 line of the specific practice is to let the gray "<" indicator button to restore color, so the faster the better. The 84-line method is called when the Alertview disappears, because the 89-row operation is pop, which returns to the previous page, so I don't want it to be time-driven, so we click Discard Edit button to see Alertview disappear, followed by pop animation. This is all a small problem, and another problem is that when we do the 89th row of pop operations, you guess what? This is a pop operation. Oh, did you think of it? Well, you think, the program will still go to our subclass of Navigationbar:shouldpopitem: Method, that is, figure 7 of 35 rows. If at this time we get nav in the stack top of that VC or we this VC words, it is circulating Ah, pop does not go out. Fortunately after I verify, if is directly write pop statement, let Nav to pop, then get the nav stack top VC is ... (for example, if Nav's VC stack has two VCs, the first one is root, the second is second.) This is the second page if you click on the system's Back button, which is in Figure 7 of the 35 line of the proxy method to get the stack top VC is second, and if the direct code write pop operation, then get the top VC is root. That is, as long as the code to write a pop operation, the system will be directly the top-level VC is second out of the stack, and then callback, so this is the top level we get to the VC is root. However, either way, the item in the parameter is second item. Have you tested it yet? If not, hurry up, impress more deeply, the interview has miraculous impact oh ~).

It's unclear why Apple is doing so, but it just lets us separate the pop operation by clicking on the system Backbarbuttonitem or code to write the pop operation instructions (I guess Apple was deliberately left to let us do this). So the 40~42 line in Figure 7 is to do this thing. If this parameter Navigationitem with the top-level VC Navigationitem is not a word, say the name is handwritten pop code, we directly let it return to the system default implementation (that is, the implementation of the parent class). PS: I just tested it. If the 41st line returns no, the magic effect will occur, followed by the operation will collapse, so I think this here will not return to no situation, I we can let 41 lines directly return yes, which will reduce a little bit of the cost of a little bit (I am such a extreme person, hey ~).

Well, the first of these details of the implementation is understood, the second implementation is similar, but there are more exciting places to start immediately

Method Swizzling Implementation

If you are unfamiliar with the Word method swizzling, you can read this blog first. Congratulations on your return to the real world, if you read the blog feel a lot of concepts do not know how to understand, it does not matter, look at my next explanation, I will let you know what you should know.

This is a copy of the code that just opened, and we need to pay attention to the following points in the code.

1. We have added a category called Yyshouldpopextention to Uinavigationcontroller. 2, we introduced the runtime header file (line 10th). 3, note the 21st line and 22 lines, the entire code is to the two SEL corresponding implementation to replace. Which means that when you encounter this piece of code,

We implemented the Yy_viewdidload method in the yyshouldpopextention classification of Uinavigationcontroller, and Uinavigationcontroller has viewdidload methods in this class. Because there's a code like that in Figure 13. We have replaced the implementation of these two methods. What do you mean, when the system normally goes to the Uinavigationcontroller Viewdidload method, the actual call is the code in Figure 14, the beginning of 72 lines, and the 72nd line of code, it seems recursive, But it is the viewdidload of the original implementation, so it is not recursive. Keep this in mind.

To do this brings great benefits, first of all we guarantee to go 72 lines of method, the original default implementation can be called to, and will give us space, let us insert our own code. such as 75~77 line. To give a little example, if we take the operation of the program as a stream flowing through your front door, originally your yard with the creek water do not make the river, who all ignore who, suddenly one day, you whim, in the creek Channel opened a mouth, and the small stream guide your home yard, Then a round and the small stream from the mouth not far into the original channel. In this way, in the creek, it seems to be quite right, because the original it to go to the channel, not because in your home yard to turn a lap, less a lap or how, but still all go. And in the view, you do have access to the creek channel, for example, if you put a little poison in the stream, the lower stream of the animals drink the small stream will die. The program is the same, after you do so, the program is going to go to the original method will go, it does not seem to be wrong, but Ken that will because you fill in a few lines of code, affecting the results of the program after the operation.

OK, this is done, you guess what I'm going to say? You guessed it, since can do so, of course we can use this method to Uinavigationcontroller Navigationbar:shouldpopitem: the implementation of our own can not be replaced.

We can do this first:

Then this:

And there's a new protocol here that I've defined:

I believe you can read Figure 16, and figure 17 can also understand how this protocol is used. It is also important to note that the code in Figure 16, which is the same as 98 lines, is not recursive, but rather the uinavigationcontroller implementation of the invocation.

OK, intercept the system back button problem solved, but there is a problem, if it is from the left edge of the screen start to the right swipe gesture will also pop, what about the pop? This decision to see your app needs, if you also need to pop up a warning box to ask if pop instead of to let the user because accidentally slipped the page pop caused by the loss of the filled content, please continue to follow me.

The first thing you need to know is that Uinavigationcontroller's right-slip gesture is a @property (nonatomic,readonly) that works by using one of its properties uigesturerecognizer* Interactivepopgesturerecognizerns_available_ios (7_0); This is the attribute, it is a subclass of Uigesturerecognizer (more details, please see I pushed the article on the homepage just started to push the second blog), of course, Uigesturerecognizer has a delegate object, One of the important proxy methods is whether the gesture started? If we intercept this method, we can control whether the gesture has started.

But the delegate object of this gesture is not our current Navigationcontroller, but the object of a private class of type _uinavigationinteractivetransition.

We want to intercept this method, we can make interactivepopgesturerecognizer this gesture delegate set to the current Navigationcontroller. 18 line 76th. But our principle is not to discard the original implementation of the system, we do not want to stop this gesture when the world returns to the implementation of the system, so it is more perfect. So we first set up the original delegate as the associated object to save it. such as line 74th. Note that the last parameter, which represents memory management semantics, is assign (why, I'm not sure here, just intuitively, because it was assign when it was saved in Interactivepopgesturerecognizer, So now still using assign, anyway temporarily verify feasible). Now that we have the Interactivepopgesturerecognizer delegate pointing to self (the current navigationcontroller) in line 76, we have to implement the Proxy method in There's nothing to say.

Why do we have to achieve these three agents? Answer, because the original delegate can only respond to these three agents, not the words of the pro can pass the Respondstoselector: personally test (more hands Oh ~), so we have the spirit of a few write, a lot of writing principles, will be realized.

We focus on the first method because the latter two return the default implementations. When you see the first one, you should smile, this method indicates whether the gesture should start by returning a bool value. So let's start by judging that this gesture is our current Navigationcontroller interactivepopgesturerecognizer gesture, and other gestures say otherwise. If this is the gesture, we still take to the top of the VC, see here VC is willing to stop the pop when this gesture occurs, if there is, we look at its decision such as and, if return no, the description block, if this VC returns Yes, indicating this time it chooses not to block, then we call the system implementation.

Sub-class can also be implemented, here is not much to say, we can automatically try to do, not write a few lines of code.

The last of these words is somewhat rough, but presumably everyone can understand. If there's something that doesn't understand or is controversial, we'll discuss it together.

Compare the features of these two implementations:

(Just on behalf of my opinion, please add)

1, sub-class This method is good we just to the specific navigationcontroller with this need to add the method call step. But for projects that have been framed, it is not very friendly to change the shelves.

2, this method takes all, as long as the project has this classification, will be in each NAV. It will also take effect on the nav, which does not require this demand.

So the specific use of, but also you.

Some self-feeling controversial places:

The first is the protocol in Figure 17, which is defined as two protocols, one for each protocol, or one for a protocol, two things that are the same thing. What we said earlier is that this agreement indicates that a VC has no intention to stop the pop, so to speak, it seems to be indeed placed in an agreement on it. Now let's see, since we're talking about one thing, let's think about merging two methods into one line. In fact, as long as the arguments on the following line. I don't know what you like more than that? That's what I feel right now, this is supposed to follow the demand, you cross your needs, intercept the return button and the intercept gesture are together, and they are always together, so they are one thing that can be written in an agreement. If the requirement may be that the page needs to intercept gestures, without intercepting the button, another intercept button without blocking gestures, and possibly two of them are intercepted. So that's two things that need to be written in two protocols.

There is another place where I always feel that this agreement should be written as a separate document. Because it is not a commission agreement, we also think about how to deal with this problem better.

Say the Xiaoguanzi I just started selling.

Is there a third way to implement, if a VC need to implement the interception system return button, we can be pushed to the nav in this VC stack, the Navigationbar delegate set as this VC, and then in its out of the stack when set to NAV. In this case, if you encounter a problem, if the original Navigationbar delegate is not nav, after you so a get, finally to the nav, so it is wrong. So we need this VC after being push to save the original delegate, then the Navigationbar delegate set to VC himself, and then immediately after the pop delegate set to the original delegate; I don't know if it's difficult to achieve , we are interested to try.

Intercept the navigation Controller system back button click Pop and right Slide pop event

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.