问题 使用MonoTouch的UINavigationController和UINavigationBarDelegate.ShouldPopItem()
当点击UINavigationBar的后退按钮(由UINavigationController控制)时,如何弹出UIAlertView?在某些情况下,我想问用户“你确定吗?”问题的类型,以便他可以中止操作并保持当前视图或弹出导航堆栈并转到父视图。
我发现最吸引人的方法是在UINavigationBar的Delegate上覆盖ShouldPopItem()。
现在,这里有一个非常相似的问题: iphone navigationController:在退出当前视图之前等待uialertview响应
还有一些类似性质的其他问题,例如:
检查UIViewController是否即将从导航堆栈中弹出?
和 如何判断在UINavigationControllerStack中按下后退按钮的时间
所有这些状态“子类UINavigationController”作为可能的答案。
然后有一个像子类UINavigationController一样读取通常不是一个好主意:
Monotouch:UINavigationController,覆盖initWithRootViewController
该 苹果文档 还要说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并在可能弹出导航堆栈之前等待它的结果?
8710
2018-06-20 15:24
起源
答案:
这篇文章有点旧,但如果你仍然对解决方案感兴趣(尽管仍然涉及子类化):
这实现了“你确定要退出吗?”按下后退按钮时发出警报,从这里的代码修改: 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 as它的一部分逻辑。)
7
2017-09-17 09:58
答案:
这篇文章有点旧,但如果你仍然对解决方案感兴趣(尽管仍然涉及子类化):
这实现了“你确定要退出吗?”按下后退按钮时发出警报,从这里的代码修改: 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 as它的一部分逻辑。)
7
2017-09-17 09:58
作为参考,我放弃后采取的路线 ShouldPopItem()
是用一个替换后退按钮 UIBarButtonItem
有自定义 UIButton
如此分配 CustomView
。该 UIButton
精心设计看起来像原始后退按钮使用两个图像为正常和按下状态。最后,需要隐藏原始后退按钮。
对于它应该做的事情来说,代码太多了。所以是的,谢谢Apple。
BTW:另一种可能性是创造一个 UIButton
随着秘密 UIButtonType
101(实际上是后退按钮)但我避免了这个,因为它可能会在以后的任何iOS版本中中断。
3
2017-09-19 06:11
仅覆盖 UINavigationBarDelegate
方法 UINavigationController
子类,它应该只是工作。当您从代码中推送或弹出视图控制器时,不仅在按下后退按钮时,还要小心调用协议方法。这是因为它们是按下/弹出通知而非按钮按下动作。
3
2017-09-17 13:15
Xamarin确实提供了 IUINavigationBarDelegate
界面允许你实现 UINavigationBarDelegate
作为您的自定义的一部分 UINavigationController
类。
但是接口不需要 ShouldPopItem
方法得以实施。所有界面都添加了相应的 Protocol
属性为类,因此可以用作 UINavigationBarDelegate
。
所以另外你需要添加 ShouldPopItem
对班级的声明如下:
[Export ("navigationBar:shouldPopItem:")]
public bool ShouldPopItem (UINavigationBar navigationBar, UINavigationItem item)
{
}
3
2017-10-30 23:26
我已将此解决方案与本机Obj-C解决方案合并。这是我目前正在处理iOS中取消BACK按钮的方式
似乎可以通过这种方式处理NavigationBar的shouldPopItem方法:
- 子类UINavigationController
- 使用IUINavigationBarDelegate标记自定义UINavigationController
使用“导出”属性添加此方法
[导出(“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;
}
0
2017-08-13 14:10