当点击UINavigationBar的后退按钮(由UINavigationController控制)时,如何弹出UIAlertView?在某些情况下,我想问用户“你确定吗?”问题的类型,以便他可以中止操作并保持当前视图或弹出导航堆栈并转到父视图。
我发现最吸引人的方法是在UINavigationBar的委托上覆盖ShouldPopItem()。
现在,这里有一个非常相似的问题:iphone navigationController : wait for uialertview response before to quit the current view
还有一些类似性质的其他问题,例如: Checking if a UIViewController is about to get Popped from a navigation stack? 和How to tell when back button is pressed in a UINavigationControllerStack
所有这些都将“子类UINavigationController”作为可能的答案。
然后有一个像子类UINavigationController一样的读取通常不是一个好主意: Monotouch: UINavigationController, override initWithRootViewController
apple docs也说UINavigationController不是要被子类化的。
其他一些人声称在使用UINavigationController时甚至无法覆盖ShouldPopItem(),因为它不允许将自定义/子类UINavigationBarDelegate分配给UINavigationBar。
我的子类化尝试都没有奏效,我的自定义代表没有被接受。
我还在某处读过可能在我的自定义UINavigationController中实现ShouldPopItem(),因为它将自己指定为其UINavigationBar的Delegate。
没什么大惊讶,这没用。 UINavigationController的子类如何知道属于UINavigationBarDelegate的Methods。它被拒绝:“找不到合适的方法来覆盖”。删除已编译的“override”关键字,但完全忽略该方法(如预期的那样)。我认为,使用Obj-C可以实现几个协议(类似于C#AFAIK中的接口)来实现这一点。不幸的是,UINavigationBarDelegate不是一个接口而是MonoTouch中的一个类,所以这似乎是不可能的。
我在这里很丢失。当UINavigationBar由UINavigationController控制时,如何在UINavigationBar的Delegate上覆盖ShouldPopItem()?或者有没有其他方法可以弹出UIAlertView并在可能弹出导航堆栈之前等待它的结果?
答案 0 :(得分:7)
这篇文章有点陈旧,但如果您仍然对解决方案感兴趣(但仍涉及子类化):
这实现了“你确定要退出吗?”按下后退按钮时发出警报,从此处的代码进行修改:http://www.hanspinckaers.com/custom-action-on-back-button-uinavigationcontroller/
如果在CustomNavigationController中实现UINavigationBarDelegate,则可以使用shouldPopItem方法:
CustomNavigationController.h:
#import <Foundation/Foundation.h>
@interface CustomNavigationController : UINavigationController <UIAlertViewDelegate, UINavigationBarDelegate> {
BOOL alertViewClicked;
BOOL regularPop;
}
@end
CustomNavigationController.m:
#import "CustomNavigationController.h"
#import "SettingsTableController.h"
@implementation CustomNavigationController
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item {
if (regularPop) {
regularPop = FALSE;
return YES;
}
if (alertViewClicked) {
alertViewClicked = FALSE;
return YES;
}
if ([self.topViewController isMemberOfClass:[SettingsTableViewController class]]) {
UIAlertView * exitAlert = [[[UIAlertView alloc] initWithTitle:@"Are you sure you want to quit?" message:nil delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Yes", nil] autorelease];
[exitAlert show];
return NO;
}
else {
regularPop = TRUE;
[self popViewControllerAnimated:YES];
return NO;
}
}
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0) {
//Cancel button
}
else if (buttonIndex == 1) {
//Yes button
alertViewClicked = TRUE;
[self popViewControllerAnimated:YES];
}
}
@end
“regularPop”bool的奇怪逻辑是因为某些原因只是在shouldPopItem上返回“YES”而只弹出导航栏,而不是与navBar关联的视图 - 为此,你必须直接调用popViewControllerAnimated(然后调用shouldPopItem作为其逻辑的一部分。)
答案 1 :(得分:3)
作为参考,我在放弃ShouldPopItem()
后采取的路线是将后退按钮替换为UIBarButtonItem
,其中UIButton
已分配为CustomView
。 UIButton
被制作成看起来像原始后退按钮,使用两个图像用于正常和按下状态。最后,需要隐藏原始后退按钮。
过多的代码应该做什么。所以是的,谢谢Apple。
BTW:另一种可能性是使用秘密UIButton
101(实际上是后退按钮)创建UIButtonType
,但我避免使用它,因为它可能会在以后的任何iOS版本中中断。
答案 2 :(得分:3)
仅覆盖UINavigationBarDelegate
子类中的UINavigationController
个方法,它应该可以正常工作。当您从代码中推送或弹出视图控制器时,不仅在按下后退按钮时,还要小心调用协议方法。这是因为它们是按下/弹出通知而非按钮按下操作。
答案 3 :(得分:3)
Xamarin确实提供了IUINavigationBarDelegate
界面,允许您将UINavigationBarDelegate
作为自定义UINavigationController
课程的一部分来实施。
然而,接口不需要实现ShouldPopItem
方法。所有界面都会将相应的Protocol
属性添加到类中,以便可以将其用作UINavigationBarDelegate
。
因此,您需要将ShouldPopItem
声明添加到类中,如下所示:
[Export ("navigationBar:shouldPopItem:")]
public bool ShouldPopItem (UINavigationBar navigationBar, UINavigationItem item)
{
}
答案 4 :(得分:0)
我已将此解决方案与本机Obj-C解决方案合并。这是我目前正在处理取消iOS中的BACK按钮的方式
似乎可以用这种方式处理NavigationBar的shouldPopItem方法:
使用“导出”属性
添加此方法[导出(“navigationBar:shouldPopItem:”)] public bool ShouldPopItem(UINavigationBar navigationBar,UINavigationItem item) { }
现在你可以在ShoulPopItem方法中处理弹出。一个例子是创建一个像这样的接口
public interface INavigationBackButton
{
// This method should return TRUE to cancel the "back operation" or "FALSE" to allow normal back
bool BackButtonPressed();
}
然后使用此界面标记需要处理后退按钮的UIViewController。实现类似这样的东西
public bool BackButtonPressed()
{
bool needToCancel = // Put your logic here. Remember to return true to CANCEL the back operation (like in Android)
return needToCancel;
}
然后在你的ShouldPopItem实现中有这样的东西 坦克:https://github.com/onegray/UIViewController-BackButtonHandler/blob/master/UIViewController%2BBackButtonHandler.m
[Export("navigationBar:shouldPopItem:")]
public bool ShouldPopItem(UINavigationBar navigationBar, UINavigationItem item)
{
if (this.ViewControllers.Length < this.NavigationBar.Items.Length)
return true;
bool shouldPop = true;
UIViewController controller = this.TopViewController;
if (controller is INavigationBackButton)
shouldPop = !((INavigationBackButton)controller).BackButtonPressed();
if (shouldPop)
{
//MonoTouch.CoreFoundation.DispatchQueue.DispatchAsync
CoreFoundation.DispatchQueue.MainQueue.DispatchAsync(
() =>
{
PopViewController(true);
});
}
else
{
// Workaround for iOS7.1. Thanks to @boliva - http://stackoverflow.com/posts/comments/34452906
foreach (UIView subview in this.NavigationBar.Subviews)
{
if(subview.Alpha < 1f)
UIView.Animate(.25f, () => subview.Alpha = 1);
}
}
return false;
}