在导航控制器中设置后退按钮的操作
我试图覆盖导航控制器中后退按钮的默认操作。我已经为自定义按钮提供了一个目标操作。奇怪的是,当通过 backbutton 属性分配它时,它不会注意它们,它只是弹出当前视图并返回到根:
UIBarButtonItem *backButton = [[UIBarButtonItem alloc]
initWithTitle: @"Servers"
style:UIBarButtonItemStylePlain
target:self
action:@selector(home)];
self.navigationItem.backBarButtonItem = backButton;
一旦我通过 leftBarButtonItem
设置它它调用我的操作的 navigationItem
,但是该按钮看起来像一个普通的圆形按钮,而不是带箭头的返回按钮:
self.navigationItem.leftBarButtonItem = backButton;
如何让它在返回根视图之前调用我的自定义操作?有没有办法覆盖默认的后退操作,或者是否有一个方法在离开视图时总是被调用(viewDidUnload
不这样做)?
I'm trying to overwrite the default action of the back button in a navigation controller. I've provided a target an action on the custom button. The odd thing is when assigning it though the backbutton attribute it doesn't pay attention to them and it just pops the current view and goes back to the root:
UIBarButtonItem *backButton = [[UIBarButtonItem alloc]
initWithTitle: @"Servers"
style:UIBarButtonItemStylePlain
target:self
action:@selector(home)];
self.navigationItem.backBarButtonItem = backButton;
As soon as I set it through the leftBarButtonItem
on the navigationItem
it calls my action, however then the button looks like a plain round one instead of the arrowed back one:
self.navigationItem.leftBarButtonItem = backButton;
How can I get it to call my custom action before going back to the root view? Is there a way to overwrite the default back action, or is there a method that is always called when leaving a view (viewDidUnload
doesn't do that)?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(30)
尝试将其放入要检测按下的视图控制器中:
Try putting this into the view controller where you want to detect the press:
我已经实现了 UIViewController-BackButtonHandler 扩展。它不需要子类化任何内容,只需将其放入您的项目中并覆盖
UIViewController
类中的navigationShouldPopOnBackButton
方法:下载示例应用。
I've implemented UIViewController-BackButtonHandler extension. It does not need to subclass anything, just put it into your project and override
navigationShouldPopOnBackButton
method inUIViewController
class:Download sample app.
与阿玛格拉默所说的不同,这是可能的。您必须对您的
navigationController
进行子类化。我在此处解释了所有内容(包括示例代码)。Unlike Amagrammer said, it's possible. You have to subclass your
navigationController
. I explained everything here (including example code).Swift 版本:(
https://stackoverflow.com/a/19132881/826435)
在你的视图控制器中你只需遵循到协议并执行您需要的任何操作:
然后创建一个类,例如
NavigationController+BackButton
,然后复制粘贴以下代码:Swift Version:
(of https://stackoverflow.com/a/19132881/826435)
In your view controller you just conform to a protocol and perform whatever action you need:
Then create a class, say
NavigationController+BackButton
, and just copy-paste the code below:直接做是不可能的。有几种替代方案:
UIBarButtonItem
,如果测试通过,则在点击和弹出时进行验证UITextField
委托方法验证表单字段内容,例如-textFieldShouldReturn:
,在按下键盘上的Return
或Done
按钮后调用第一个选项的缺点问题是无法从自定义栏按钮访问后退按钮的左指箭头样式。所以你必须使用图像或使用常规样式的按钮。
第二个选项很好,因为您可以在委托方法中返回文本字段,因此您可以将验证逻辑定位到发送到委托回调方法的特定文本字段。
It isn't possible to do directly. There are a couple alternatives:
UIBarButtonItem
that validates on tap and pops if the test passesUITextField
delegate method, such as-textFieldShouldReturn:
, which is called after theReturn
orDone
button is pressed on the keyboardThe downside of the first option is that the left-pointing-arrow style of the back button cannot be accessed from a custom bar button. So you have to use an image or go with a regular style button.
The second option is nice because you get the text field back in the delegate method, so you can target your validation logic to the specific text field sent to the delegate call-back method.
由于某些线程原因,@HansPinckaers 提到的解决方案不适合我,但我找到了一种更简单的方法来捕捉后退按钮的触摸,我想将其固定在此处,以防这可以避免数小时的欺骗他人。
技巧非常简单:只需将一个透明的 UIButton 作为子视图添加到 UINavigationBar 中,然后为他设置选择器,就好像它是真正的按钮一样!
这是一个使用 Monotouch 和 C# 的示例,但到 Objective-C 的翻译应该不难找到。
有趣的事实:出于测试目的并为我的假按钮找到合适的尺寸,我将其背景颜色设置为蓝色......并且它显示在后退按钮后面!无论如何,它仍然捕获针对原始按钮的任何触摸。
For some threading reasons, the solution mentionned by @HansPinckaers wasn't right for me, but I found a very easier way to catch a touch on the back button, and I wanna pin this down here in case this could avoid hours of deceptions for someone else.
The trick is really easy : just add a transparent UIButton as a subview to your UINavigationBar, and set your selectors for him as if it was the real button!
Here's an example using Monotouch and C#, but the translation to objective-c shouldn't be too hard to find.
Fun fact : for testing purposes and to find good dimensions for my fake button, I set its background color to blue... And it shows behind the back button! Anyway, it still catches any touch targetting the original button.
=========================== ===============
以异步方式在 Swift5 中使用 UIAlert 构建之前的响应
在您的控制器上
========================================
Building on previous responses with UIAlert in Swift5 in a Asynchronous way
On your controller
此技术允许您更改“后退”按钮的文本,而不会影响任何视图控制器的标题,也不会在动画期间看到后退按钮文本发生变化。
将其添加到调用视图控制器中的 init 方法中:
This technique allows you to change the text of the "back" button without affecting the title of any of the view controllers or seeing the back button text change during the animation.
Add this to the init method in the calling view controller:
最简单的方法
您可以使用 UINavigationController 的委托方法。当按下 VC 的后退按钮时,会调用
willShowViewController
方法。当按下后退按钮时,可以做任何你想做的事情Easiest way
You can use the UINavigationController's delegate methods. The method
willShowViewController
is called when the back button of your VC is pressed.do whatever you want when back btn pressed这是我的 Swift 解决方案。在 UIViewController 的子类中,重写 navigationShouldPopOnBackButton 方法。
Here's my Swift solution. In your subclass of UIViewController, override the navigationShouldPopOnBackButton method.
找到了一个也保留后退按钮样式的解决方案。
将以下方法添加到您的视图控制器中。
现在通过以下方法提供所需的功能:
它所做的只是用透明按钮覆盖后退按钮;)
Found a solution which retains the back button style as well.
Add the following method to your view controller.
Now provide a functionality as needed in the following method:
All it does is to cover the back button with a transparent button ;)
我不相信这是可能的、容易的。我认为解决这个问题的唯一方法是制作您自己的后退按钮箭头图像并将其放置在那里。起初这让我很沮丧,但我明白为什么为了保持一致性,它被排除在外。
您可以通过创建常规按钮并隐藏默认后退按钮来接近(没有箭头):
I don't believe this is possible, easily. The only way I believe to get around this is to make your own back button arrow image to place up there. It was frustrating for me at first but I see why, for consistency's sake, it was left out.
You can get close (without the arrow) by creating a regular button and hiding the default back button:
有一种更简单的方法,只需子类化
UINavigationBar
的委托方法并覆盖ShouldPopItem
方法< /em>.There's an easier way by just subclassing the delegate method of the
UINavigationBar
and override theShouldPopItem
method.这种方法对我有用(但“后退”按钮不会有“<”符号):
This approach worked for me (but the "Back" button will not have the "<" sign):
onegray的解决方案并不安全。根据苹果官方文档,https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/CustomizingExistingClasses/CustomizingExistingClasses.html,
我们应该避免这样做。
“如果类别中声明的方法的名称与原始类中的方法相同,或者与同一类(甚至超类)上的另一个类别中的方法相同,则使用哪个方法实现的行为是未定义的如果您在自己的类中使用类别,那么这不太可能成为问题,但在使用类别向标准 Cocoa 或 Cocoa Touch 类添加方法时可能会导致问题。”
onegray's solution is not safe.According to the official documents by Apple,https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/CustomizingExistingClasses/CustomizingExistingClasses.html,
we should avoid doing that.
"If the name of a method declared in a category is the same as a method in the original class, or a method in another category on the same class (or even a superclass), the behavior is undefined as to which method implementation is used at runtime. This is less likely to be an issue if you’re using categories with your own classes, but can cause problems when using categories to add methods to standard Cocoa or Cocoa Touch classes."
使用斯威夫特:
Using Swift:
这是 Swift 3 版本的 @oneway 的答案,用于在导航栏后退按钮事件被触发之前捕获它。由于
UINavigationBarDelegate
不能用于UIViewController
,因此您需要创建一个委托,当navigationBar
shouldPop
为叫。然后,在您的视图控制器中添加委托功能:
我意识到我们经常想要添加一个警报控制器,以便用户决定是否要返回。如果是这样,您始终可以在
navigationShouldPopOnBackButton()
函数中return false
并通过执行以下操作来关闭视图控制器:Here is Swift 3 version of @oneway's answer for catching navigation bar back button event before it gets fired. As
UINavigationBarDelegate
cannot be used forUIViewController
, you need to create a delegate that will be triggered whennavigationBar
shouldPop
is called.And then, in your view controller add the delegate function:
I've realised that we often want to add an alert controller for users to decide whether they wanna go back. If so, you can always
return false
innavigationShouldPopOnBackButton()
function and close your view controller by doing something like this:Swift 4 iOS 11.3 版本:
这是基于 https://stackoverflow.com/a/34343418/4316579
我不确定扩展何时停止工作,但在撰写本文时(Swift 4),除非您按照如下所述声明 UINavigationBarDelegate 一致性,否则该扩展似乎将不再执行。
希望这可以帮助那些想知道为什么他们的扩展不再有效的人。
Swift 4 iOS 11.3 Version:
This builds on the answer from kgaidis from https://stackoverflow.com/a/34343418/4316579
I am not sure when the extension stopped working, but at the time of this writing (Swift 4), it appears that the extension will no longer be executed unless you declare UINavigationBarDelegate conformity as described below.
Hope this helps people that are wondering why their extension no longer works.
通过使用当前保留为“nil”的目标和操作变量,您应该能够连接保存对话框,以便在“选择”按钮时调用它们。请注意,这可能会在奇怪的时刻触发。
我基本上同意 Amagrammer 的观点,但我认为定制带有箭头的按钮并不难。我只需重命名后退按钮,拍摄屏幕截图,用 Photoshop 处理所需的按钮大小,然后将其作为按钮顶部的图像。
By using the target and action variables that you are currently leaving 'nil', you should be able to wire your save-dialogs in so that they are called when the button is "selected". Watch out, this may get triggered at strange moments.
I agree mostly with Amagrammer, but I don't think it would be that hard to make the button with the arrow custom. I would just rename the back button, take a screen shot, photoshop the button size needed, and have that be the image on the top of your button.
您可以尝试访问 NavigationBars Right Button 项目并设置其选择器属性...这里有一个参考 UIBarButtonItem 参考,如果这确实有效的话,另一件事就是设置导航栏的右侧按钮项到您创建并设置其选择器的自定义 UIBarButtonItem...希望这有帮助
You can try accessing the NavigationBars Right Button item and set its selector property...heres a reference UIBarButtonItem reference, another thing if this doenst work that will def work is, set the right button item of the nav bar to a custom UIBarButtonItem that you create and set its selector...hope this helps
对于需要这样的用户输入的表单,我建议将其作为“模态”而不是导航堆栈的一部分来调用。这样他们就必须处理表单上的业务,然后您可以验证它并使用自定义按钮将其关闭。您甚至可以设计一个导航栏,它看起来与应用程序的其余部分相同,但为您提供更多控制。
For a form that requires user input like this, I would recommend invoking it as a "modal" instead of part of your navigation stack. That way they have to take care of business on the form, then you can validate it and dismiss it using a custom button. You can even design a nav bar that looks the same as the rest of your app but gives you more control.
要拦截“后退”按钮,只需用透明的 UIControl 覆盖它并拦截触摸即可。
To intercept the Back button, simply cover it with a transparent UIControl and intercept the touches.
至少在 Xcode 5 中,有一个简单且相当不错(不完美)的解决方案。在 IB 中,将“栏按钮项”从“实用程序”窗格中拖出,并将其放在导航栏左侧“后退”按钮所在的位置。将标签设置为“返回”。您将有一个功能按钮,可以将其绑定到 IBAction 并关闭 viewController。我正在做一些工作,然后触发展开转场,它工作得很好。
不理想的是这个按钮没有得到 < arrow并没有继承之前的VC头衔,但我认为这是可以管理的。出于我的目的,我将新的“后退”按钮设置为“完成”按钮,因此其目的很明确。
您最终还会在 IB 导航器中看到两个后退按钮,但为了清晰起见,很容易对其进行标记。
At least in Xcode 5, there is a simple and pretty good (not perfect) solution. In IB, drag a Bar Button Item off the Utilities pane and drop it on the left side of the Navigation Bar where the Back button would be. Set the label to "Back." You will have a functioning button that you can tie to your IBAction and close your viewController. I'm doing some work and then triggering an unwind segue and it works perfectly.
What isn't ideal is that this button does not get the < arrow and does not carry forward the previous VCs title, but I think this can be managed. For my purposes, I set the new Back button to be a "Done" button so it's purpose is clear.
You also end up with two Back buttons in the IB navigator, but it is easy enough to label it for clarity.
迅速
Swift
找到了新的方法:
Objective-C
Swift
Found new way to do it :
Objective-C
Swift
@onegray 答案的 Swift 版本
现在,在任何控制器中,只需遵守
RequestsNavigationPopVerification
即可默认采用此行为。Swift version of @onegray's answer
Now in any controller, just conform to
RequestsNavigationPopVerification
and this behaviour is adopted by default.使用 isMovingFromParentViewController
Use
isMovingFromParentViewController
@William 的答案是正确的,但是,如果用户开始滑动返回手势,则会调用 viewWillDisappear 方法,甚至 self 也不会出现在导航堆栈(即,
self.navigationController.viewControllers
不会包含self
),即使滑动未完成且视图控制器未实际弹出。因此,解决方案是:在
viewDidAppear
中禁用滑动返回手势,仅允许使用后退按钮,方法是:或者简单地使用
viewDidDisappear
代码>改为,如下:The answer from @William is correct however, if the user starts a swipe-to-go-back gesture the
viewWillDisappear
method is called and evenself
won't be in the navigation stack (that is,self.navigationController.viewControllers
won't containself
), even if the swipe is not completed and the view controller is not actually popped. Thus, the solution would be to:Disable the swipe-to-go-back gesture in
viewDidAppear
and only allow using the back button, by using:Or simply use
viewDidDisappear
instead, as follows:使用 iOS 16 或更高版本时,您可以使用当前
UIViewController
的navigationItem
属性的backAction
属性来设置自定义后退操作。这是一个例子:When using iOS 16 or newer, you can use the
backAction
property of thenavigationItem
property of the currentUIViewController
to set a custom back action. Here is an example:到目前为止我找到的解决方案不是很好,但它对我有用。考虑到这个答案,我还检查我是否以编程方式弹出:
您必须将该属性添加到您的控制器中,并且在以编程方式弹出之前将其设置为 YES:
The solution I have found so far is not very nice, but it works for me. Taking this answer, I also check whether I'm popping programmatically or not:
You have to add that property to your controller and set it to YES before popping programmatically: