Nam*_*tha 99 callback back uinavigationcontroller uinavigationitem ios
我已将视图推到导航控制器上,当我按下后退按钮时,它会自动转到上一个视图.我想在按下后退按钮之前做一些事情,然后再将视图弹出堆栈.哪个是后退按钮回调功能?
ymu*_*tlu 162
William Jockusch的回答用简单的技巧解决了这个问题.
-(void) viewWillDisappear:(BOOL)animated {
if ([self.navigationController.viewControllers indexOfObject:self]==NSNotFound) {
// back button was pressed. We know this is true because self is no longer
// in the navigation stack.
}
[super viewWillDisappear:animated];
}
Run Code Online (Sandbox Code Playgroud)
Bla*_*ank 83
在我看来,最好的解决方案.
- (void)didMoveToParentViewController:(UIViewController *)parent
{
if (![parent isEqual:self.parentViewController]) {
NSLog(@"Back pressed");
}
}
Run Code Online (Sandbox Code Playgroud)
但它只适用于iOS5 +
roo*_*ell 27
覆盖后退按钮可能更好,这样您就可以在弹出视图之前处理事件,例如用户确认.
在viewDidLoad中创建一个UIBarButtonItem并将self.navigationItem.leftBarButtonItem设置为传递给它的sel
- (void) viewDidLoad
{
// change the back button to cancel and add an event handler
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:@”back”
style:UIBarButtonItemStyleBordered
target:self
action:@selector(handleBack:)];
self.navigationItem.leftBarButtonItem = backButton;
[backButton release];
}
- (void) handleBack:(id)sender
{
// pop to root view controller
[self.navigationController popToRootViewControllerAnimated:YES];
}
Run Code Online (Sandbox Code Playgroud)
然后你可以做一些事情,如提升UIAlertView来确认动作,然后弹出视图控制器等.
或者,不是创建新的后退按钮,而是可以符合UINavigationController委托方法,以便在按下后退按钮时执行操作.
yus*_*024 11
也许为时已晚,但我之前也想要相同的行为。我采用的解决方案在目前 App Store 上的其中一款应用程序中运行良好。由于我还没有看到有人使用类似的方法,所以我想在这里分享一下。此解决方案的缺点是它需要子类化UINavigationController
。虽然使用Method Swizzling可能有助于避免这种情况,但我并没有走那么远。
所以,默认的后退按钮实际上是由UINavigationBar
. 当返回按钮,用户水龙头,UINavigationBar
要求其委托是否应该弹出的顶部UINavigationItem
通过调用navigationBar(_:shouldPop:)
。UINavigationController
实际上实现了这一点,但它没有公开声明它采用UINavigationBarDelegate
(为什么!?)。要拦截此事件,请创建 的子类UINavigationController
,声明其符合UINavigationBarDelegate
并实现navigationBar(_:shouldPop:)
。true
如果应弹出顶部项目,则返回。false
如果它应该留下就回来。
有两个问题。第一个是您必须在某个时候调用 的UINavigationController
版本navigationBar(_:shouldPop:)
。但是UINavigationBarController
没有公开声明它符合UINavigationBarDelegate
,尝试调用它会导致编译时错误。我采用的解决方案是使用 Objective-C 运行时直接获取实现并调用它。请让我知道是否有人有更好的解决方案。
另一个问题是如果用户点击后退按钮,navigationBar(_:shouldPop:)
则首先调用popViewController(animated:)
。如果通过调用弹出视图控制器,则顺序相反popViewController(animated:)
。在这种情况下,我使用布尔值来检测是否popViewController(animated:)
在之前被调用,navigationBar(_:shouldPop:)
这意味着用户已经点击了后退按钮。
另外,我做了一个扩展,UIViewController
让导航控制器询问视图控制器是否应该在用户点击后退按钮时弹出它。视图控制器可以返回false
并执行任何必要的操作并popViewController(animated:)
稍后调用。
class InterceptableNavigationController: UINavigationController, UINavigationBarDelegate {
// If a view controller is popped by tapping on the back button, `navigationBar(_:, shouldPop:)` is called first follows by `popViewController(animated:)`.
// If it is popped by calling to `popViewController(animated:)`, the order reverses and we need this flag to check that.
private var didCallPopViewController = false
override func popViewController(animated: Bool) -> UIViewController? {
didCallPopViewController = true
return super.popViewController(animated: animated)
}
func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {
// If this is a subsequence call after `popViewController(animated:)`, we should just pop the view controller right away.
if didCallPopViewController {
return originalImplementationOfNavigationBar(navigationBar, shouldPop: item)
}
// The following code is called only when the user taps on the back button.
guard let vc = topViewController, item == vc.navigationItem else {
return false
}
if vc.shouldBePopped(self) {
return originalImplementationOfNavigationBar(navigationBar, shouldPop: item)
} else {
return false
}
}
func navigationBar(_ navigationBar: UINavigationBar, didPop item: UINavigationItem) {
didCallPopViewController = false
}
/// Since `UINavigationController` doesn't publicly declare its conformance to `UINavigationBarDelegate`,
/// trying to called `navigationBar(_:shouldPop:)` will result in a compile error.
/// So, we'll have to use Objective-C runtime to directly get super's implementation of `navigationBar(_:shouldPop:)` and call it.
private func originalImplementationOfNavigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {
let sel = #selector(UINavigationBarDelegate.navigationBar(_:shouldPop:))
let imp = class_getMethodImplementation(class_getSuperclass(InterceptableNavigationController.self), sel)
typealias ShouldPopFunction = @convention(c) (AnyObject, Selector, UINavigationBar, UINavigationItem) -> Bool
let shouldPop = unsafeBitCast(imp, to: ShouldPopFunction.self)
return shouldPop(self, sel, navigationBar, item)
}
}
extension UIViewController {
@objc func shouldBePopped(_ navigationController: UINavigationController) -> Bool {
return true
}
}
Run Code Online (Sandbox Code Playgroud)
在你的视图控制器中,实现shouldBePopped(_:)
. 如果你没有实现这个方法,默认行为将是在用户点击后退按钮时立即弹出视图控制器,就像往常一样。
class MyViewController: UIViewController {
override func shouldBePopped(_ navigationController: UINavigationController) -> Bool {
let alert = UIAlertController(title: "Do you want to go back?",
message: "Do you really want to go back? Tap on \"Yes\" to go back. Tap on \"No\" to stay on this screen.",
preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "No", style: .cancel, handler: nil))
alert.addAction(UIAlertAction(title: "Yes", style: .default, handler: { _ in
navigationController.popViewController(animated: true)
}))
present(alert, animated: true, completion: nil)
return false
}
}
Run Code Online (Sandbox Code Playgroud)
你可以在这里查看我的演示。
我最终得到了这个解决方案.当我们点击后退按钮viewDidDisappear方法调用时.我们可以通过调用返回true的isMovingFromParentViewController选择器来检查.我们可以传回数据(使用Delegate).hope这可以帮助某人.
-(void)viewDidDisappear:(BOOL)animated{
if (self.isMovingToParentViewController) {
}
if (self.isMovingFromParentViewController) {
//moving back
//pass to viewCollection delegate and update UI
[self.delegateObject passBackSavedData:self.dataModel];
}
}
Run Code Online (Sandbox Code Playgroud)
这是检测此问题的正确方法.
- (void)willMoveToParentViewController:(UIViewController *)parent{
if (parent == nil){
//do stuff
}
}
Run Code Online (Sandbox Code Playgroud)
在推送视图时也会调用此方法.所以检查parent == nil是用于从堆栈弹出视图控制器
对于"BEFORE弹出堆栈视图":
- (void)willMoveToParentViewController:(UIViewController *)parent{
if (parent == nil){
NSLog(@"do whatever you want here");
}
}
Run Code Online (Sandbox Code Playgroud)
有一种比询问viewControllers更合适的方法。您可以使控制器成为具有back按钮的navigationBar的委托。这是一个例子。在要处理按下后退按钮的控制器的实现中,告诉它它将实现UINavigationBarDelegate协议:
@interface MyViewController () <UINavigationBarDelegate>
Run Code Online (Sandbox Code Playgroud)
然后在初始化代码中的某处(可能在viewDidLoad中)使控制器成为其导航栏的委托:
self.navigationController.navigationBar.delegate = self;
Run Code Online (Sandbox Code Playgroud)
最后,实现shouldPopItem方法。当按下后退按钮时,此方法将被调用。如果堆栈中有多个控制器或导航项,则可能要检查弹出了哪些导航项(item参数),以便仅在期望时进行自定义操作。这是一个例子:
-(BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item
{
NSLog(@"Back button got pressed!");
//if you return NO, the back button press is cancelled
return YES;
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
106565 次 |
最近记录: |