2012-04-24 9 views
5

UINavigationControllerDelegate métodos no invocados al mostrar a un controlador de vista que no admite la orientación actual.UINavigationControllerDelegate métodos no llamados (código de demostración en github)

Tengo un UINavigationController como controlador de vista raíz de mi aplicación (controlador de vista inicial en mi Storyboard).

Digamos que empujo una ViewController A con esta orientación:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { 
    return (interfaceOrientation == UIInterfaceOrientationPortrait); 
} 

De ahí que no son compatibles con cualquier modo de paisaje. Además de eso vamos a empujar otra ViewController con código:

@interface B : UIViewController <UINavigationControllerDelegate> 
@end 

@implementation B 
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { 
    return YES; // any orientation supported 
} 

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate]; 
    UINavigationController *nc = (UINavigationController*)appDelegate.window.rootViewController; 
    nc.delegate = self; 
} 

- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated { 
    // not always called... 
} 

- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated { 
    // not always called... 
} 
@end 

Ahora bien, si tengo mi iPhone en el retrato y empujo vista controlador B en la parte superior de A, a través de algún suceso táctil, a continuación, toque el botón "atrás" en la barra de navegación, todo está bien y se llaman los métodos de delegado (hago algunas cosas ahí).

Pero si, cuando estoy viendo la vista B, giro a horizontal, y luego presiono el botón Atrás, esos métodos de delegado no se llaman !! ¿Cuál es el punto de establecer un delegado para el UINavigationController si los métodos se llaman a veces pero no a otro? Seguramente estoy haciendo algo mal.

Intento poner al delegado en otra clase, como AppDelegate o mi MainView, nada cambia.

¿Alguna idea?

código de demostración aquí:git://github.com/malaba/NavBarTest.git

partir de una plantilla básica Maestro-Detalle, modificado al igual que anteriormente.

¿Cómo mostrar mi punto? Aquí está el paso a paso-:

  1. Añadir alguna línea en la vista maestra (la parte superior + derecha)
  2. continuación, toque una línea para ir a la vista de detalles
  3. Ver Acceder salida a aparecer
  4. Botón Volver atrás (etiquetado como "Maestro"), nuevamente se muestra el registro.

Ahora intenta girar el iPhone (o simulador) en la vista de detalles, y luego ir "atrás" y ver ningún registro aparecer ?!

Respuesta

1

por respuesta de Kaspar, aquí está mi código en Obj-C.

.h:

@interface ProperNavigationController : UINavigationController 

@end 

@interface ProperNavigationControllerDelegate : NSObject <UINavigationControllerDelegate> 
@property (assign, nonatomic) BOOL wasCalled; 
@end 

.m:

#import "ProperNavigationController.h" 

@interface ProperNavigationController() 
@property (strong, nonatomic) id<UINavigationControllerDelegate> oldDelegate; 
@property (strong, nonatomic) ProperNavigationControllerDelegate *myDelegate; 
@end 

@implementation ProperNavigationController 
@synthesize oldDelegate = _oldDelegate; 
@synthesize myDelegate = _myDelegate; 

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    self.oldDelegate = self.delegate; 
    self.myDelegate = [ProperNavigationControllerDelegate new]; 
    self.delegate = self.myDelegate; 
} 

- (UIViewController *)popViewControllerAnimated:(BOOL)animated { 
    self.myDelegate.wasCalled = FALSE; 

    UIViewController *vc = [super popViewControllerAnimated:animated]; 

    if (!self.myDelegate.wasCalled) { 
     // if iOS did not call the delegate handler then we must do it 
     [self.myDelegate navigationController:self willShowViewController:self.topViewController animated:animated]; 
     [self.myDelegate navigationController:self didShowViewController:self.topViewController animated:animated]; 
    } 

    return vc; 
} 

@end 

@implementation ProperNavigationControllerDelegate 
@synthesize wasCalled = _wasCalled;  // flag that we use to track whether iOS calls the handlers or we have to 

- (id)init { 
    if (self = [super init]) { 
     _wasCalled = FALSE; 
    } 
    return self; 
} 

- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated { 
    ProperNavigationController *nc = (ProperNavigationController *)navigationController; 
    [nc.oldDelegate navigationController:navigationController willShowViewController:viewController animated:animated]; 
    self.wasCalled = TRUE; // signal that we have been called 
} 

- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated { 
    ProperNavigationController *nc = (ProperNavigationController *)navigationController; 
    [nc.oldDelegate navigationController:navigationController didShowViewController:viewController animated:animated]; 
} 

@end 

que funcione.

¿Qué opinas? ¿Y deberíamos completar un informe de error?

2

Hola, éste fue un tema difícil para mí también, hasta que vi esta idea: http://www.hanspinckaers.com/custom-action-on-back-button-uinavigationcontroller

Cuando tanto el NavigationController y la TopViewController tienen la misma orientación continuación IOS crea la secuencia de llamada siguiente utilizando el código de abajo (MonoTouch)

  • SomeTopViewController ViewWillDisappear
  • WillShowViewController viewController: la nueva TopViewController
  • SomeTopViewController ViewDidDisappear
  • DidShowViewController viewController: la nueva TopViewController

Cuando el NavigationController y la TopViewController tienen diferentes orientaciones continuación, el delegado NavigationController es no llamado como usted describió. Por lo tanto, la secuencia de llamada es:

  • SomeTopViewController ViewWillDisappear
  • SomeTopViewController ViewDidDisappear

El código siguiente reproduce el IOS llaman secuencia reemplazando el NavigationController' PopViewControllerAnimated:

public class MyNavigationControllerDelegate : UINavigationControllerDelegate { 
    public MyNavigationControllerDelegate() : base() {} 

    public bool WasCalled {get;set;} // flag that we use to track whether iOS calls the handlers or we have to 

    public override void WillShowViewController(UINavigationController navigationController, UIViewController viewController, bool animated) { 
    Console.WriteLine("WillShowViewController viewController: {0}", viewController.GetType()); 
    WasCalled = true; // signal that we have been called 
    //.….. do your stuff 
    } 

    public override void DidShowViewController(UINavigationController navigationController, UIViewController viewController, bool animated) { 
    Console.WriteLine("DidShowViewController viewController: {0}", viewController.GetType()); 
    //.….. do your stuff 
    } 
} 

public partial class MyNavigationController : UINavigationController { 
    MyNavigationControllerDelegate navigationControllerDelegate; 

    public override void ViewDidLoad() { 
    base.ViewDidLoad(); 
    navigationControllerDelegate = new MyNavigationControllerDelegate(viewSelectionControl); 
    Delegate = navigationControllerDelegate; 
    } 

public override UIViewController PopViewControllerAnimated(bool animated) { 
    Console.WriteLine("PopViewControllerAnimated TopViewController.GetType: {0}", TopViewController.GetType()); 
    navigationControllerDelegate.WasCalled = false; // reset flag before we start the popsequence 

    UIViewController ctrl = base.PopViewControllerAnimated(animated); 

    AppDelegate.MainWindow.BeginInvokeOnMainThread(delegate { 
    if(!navigationControllerDelegate.WasCalled) { // if iOS did not call the delegate handler then we must do it 
     Delegate.WillShowViewController(this, TopViewController, animated); 
     navigationControllerDelegate.WasCalled = false; // reset flag to be used in the next DidShowViewController step of the popsequence 
     } 
    }); 

    Thread t = new Thread(() => RunPop(animated)); 
    tt.Start(); 

    return ctrl; 
} 

void RunPop(bool animated) { 
    Thread.Sleep(500); 
    AppDelegate.MainWindow.BeginInvokeOnMainThread(delegate { 
    if(!navigationControllerDelegate.WasCalled) { // if iOS did not call the delegate handler then we must do it 
     Delegate.DidShowViewController(this,TopViewController,animated); 
    } 
    }); 
} 

}

+1

¿Qué es este lenguaje? Obj-C++ ?? Estoy traduciendo ahora ... – malaba

+0

Es C#, usando MonoTouch. –

Cuestiones relacionadas