120 iphone xcode objective-c ios
我需要在导航栏上按下后退按钮(返回上一屏幕,返回父视图)按钮时执行一些操作.
是否有一些方法可以实现捕获事件并触发一些操作以在屏幕消失之前暂停和保存数据?
eli*_*lon 303
更新:根据一些评论,原始答案中的解决方案似乎在iOS 8+的某些情况下不起作用.如果没有进一步的细节,我无法验证实际情况.
对于那些在那种情况下的人来说,还有另一种选择.通过覆盖可以检测何时弹出视图控制器willMove(toParentViewController:).其基本思想是,当一个视图控制器被弹出parent是nil.
有关更多详细信息,请查看"实现容器视图控制器".
从iOS 5开始,我发现处理这种情况的最简单方法是使用新方法- (BOOL)isMovingFromParentViewController:
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
if (self.isMovingFromParentViewController) {
// Do your stuff here
}
}
Run Code Online (Sandbox Code Playgroud)
- (BOOL)isMovingFromParentViewController 当您在导航堆栈中推送和弹出控制器时,这是有意义的.
但是,如果要呈现模态视图控制器,则应使用- (BOOL)isBeingDismissed:
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
if (self.isBeingDismissed) {
// Do your stuff here
}
}
Run Code Online (Sandbox Code Playgroud)
如本问题所述,您可以将两个属性组合在一起:
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
if (self.isMovingFromParentViewController || self.isBeingDismissed) {
// Do your stuff here
}
}
Run Code Online (Sandbox Code Playgroud)
其他解决方案依赖于a的存在UINavigationBar.我更喜欢这种方法,因为它从触发事件的动作(即按下后退按钮)中解除了执行所需的任务.
WCB*_*rne 91
虽然viewWillAppear()和viewDidDisappear() 被当返回按钮被窃听叫,它们也被称为在其他时间.有关详细信息,请参阅答案的结尾.
在willMoveToParentViewController(_:)OR 的帮助下从VC的父节点(NavigationController)中删除VC时,最好检测后退按钮didMoveToParentViewController()
如果parent为nil,则视图控制器将从导航堆栈弹出并被解除.如果parent不是nil,则将其添加到堆栈并显示.
// Objective-C
-(void)willMoveToParentViewController:(UIViewController *)parent {
[super willMoveToParentViewController:parent];
if (!parent){
// The back button was pressed or interactive gesture used
}
}
// Swift
override func willMove(toParent parent: UIViewController?) {
super.willMove(toParent: parent)
if parent == nil {
// The back button was pressed or interactive gesture used
}
}
Run Code Online (Sandbox Code Playgroud)
换出willMove的didMove检查self.parent做工作后视图控制器被驳回.
请注意,如果您需要进行某种异步保存,检查父级不允许您"暂停"转换.为此,您可以实现以下功能.唯一的缺点就是你失去了花哨的iOS风格/动画后退按钮.此处还要注意交互式滑动手势.使用以下方法处理此案例.
var backButton : UIBarButtonItem!
override func viewDidLoad() {
super.viewDidLoad()
// Disable the swipe to make sure you get your chance to save
self.navigationController?.interactivePopGestureRecognizer.enabled = false
// Replace the default back button
self.navigationItem.setHidesBackButton(true, animated: false)
self.backButton = UIBarButtonItem(title: "Back", style: UIBarButtonItemStyle.Plain, target: self, action: "goBack")
self.navigationItem.leftBarButtonItem = backButton
}
// Then handle the button selection
func goBack() {
// Here we just remove the back button, you could also disabled it or better yet show an activityIndicator
self.navigationItem.leftBarButtonItem = nil
someData.saveInBackground { (success, error) -> Void in
if success {
self.navigationController?.popViewControllerAnimated(true)
// Don't forget to re-enable the interactive gesture
self.navigationController?.interactivePopGestureRecognizer.enabled = true
}
else {
self.navigationItem.leftBarButtonItem = self.backButton
// Handle the error
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果你没有得到这个viewWillAppear viewDidDisappear问题,让我们来看一个例子吧.假设您有三个视图控制器:
让我们按照detailVC你的方式跟随listVC,settingsVC然后回到listVC
List> Detail(push detailVC)Detail.viewDidAppear< - 出现
Detail> Settings(push settingsVC)Detail.viewDidDisappear< - 消失
当我们返回...
设置>详细信息(pop settingsVC) Detail.viewDidAppear< - 出现
详细信息>列表(pop detailVC)Detail.viewDidDisappear< - 消失
请注意,viewDidDisappear多次调用,不仅在返回时,而且在向前时.对于可能需要的快速操作,但对于更复杂的操作(如网络调用保存),可能不会.
Xar*_*mer 16
第一种方法
- (void)didMoveToParentViewController:(UIViewController *)parent
{
if (![parent isEqual:self.parentViewController]) {
NSLog(@"Back pressed");
}
}
Run Code Online (Sandbox Code Playgroud)
第二种方法
-(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)
我已经和这个问题玩了两天了.IMO最好的方法就是创建扩展类和协议,如下所示:
@protocol UINavigationControllerBackButtonDelegate <NSObject>
/**
* Indicates that the back button was pressed.
* If this message is implemented the pop logic must be manually handled.
*/
- (void)backButtonPressed;
@end
@interface UINavigationController(BackButtonHandler)
@end
@implementation UINavigationController(BackButtonHandler)
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item
{
UIViewController *topViewController = self.topViewController;
BOOL wasBackButtonClicked = topViewController.navigationItem == item;
SEL backButtonPressedSel = @selector(backButtonPressed);
if (wasBackButtonClicked && [topViewController respondsToSelector:backButtonPressedSel]) {
[topViewController performSelector:backButtonPressedSel];
return NO;
}
else {
[self popViewControllerAnimated:YES];
return YES;
}
}
@end
Run Code Online (Sandbox Code Playgroud)
这是有效的,因为每次弹出视图控制器时UINavigationController都会收到调用navigationBar:shouldPopItem:.在那里我们检测是否按下了背部(任何其他按钮).您唯一需要做的就是在视图控制器中实现协议,在该控制器中按下后退.
backButtonPressedSel如果一切正常,请记住手动弹出视图控制器.
如果你已经有子类UINavigationViewController并且已经实现了,navigationBar:shouldPopItem:请不要担心,这不会干扰它.
您可能还有兴趣禁用后退手势.
if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
}
Run Code Online (Sandbox Code Playgroud)
小智 7
您可以使用后退按钮回调,如下所示:
- (BOOL) navigationShouldPopOnBackButton
{
[self backAction];
return NO;
}
- (void) backAction {
// your code goes here
// show confirmation alert, for example
// ...
}
Run Code Online (Sandbox Code Playgroud)
对于 swift 版本,您可以在全局范围内执行类似的操作
extension UIViewController {
@objc func navigationShouldPopOnBackButton() -> Bool {
return true
}
}
extension UINavigationController: UINavigationBarDelegate {
public func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {
return self.topViewController?.navigationShouldPopOnBackButton() ?? true
}
}
Run Code Online (Sandbox Code Playgroud)
在下面一个视图控制器中放置要控制后退按钮操作的位置:
override func navigationShouldPopOnBackButton() -> Bool {
self.backAction()//Your action you want to perform.
return true
}
Run Code Online (Sandbox Code Playgroud)
这适用于iOS 9.3.x with Swift:
override func didMoveToParentViewController(parent: UIViewController?) {
super.didMoveToParentViewController(parent)
if parent == self.navigationController?.parentViewController {
print("Back tapped")
}
}
Run Code Online (Sandbox Code Playgroud)
与此处的其他解决方案不同,这似乎并未意外触发.
那些声称这行不通的人被误认为:
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if self.isMovingFromParent {
print("we are being popped")
}
}
Run Code Online (Sandbox Code Playgroud)
很好 那么,是什么导致了这个事实却没有呢?
问题似乎是由于不同方法的错误实现导致的,即willMove(toParent:)忘记调用的实现super。
如果您在willMove(toParent:)未调用的情况下实施super,那么self.isMovingFromParentwill将无法false使用viewWillDisappear。它没有失败;你把它弄坏了。
| 归档时间: |
|
| 查看次数: |
120482 次 |
| 最近记录: |