5

現在の向きをサポートしていないビュー コントローラーにポップするときに、UINavigationControllerDelegate メソッドが呼び出されない。

アプリのルート ビュー コントローラー (ストーリーボードの初期ビュー コントローラー) として UINavigationController があります。

向きのためにこれを使用して ViewController A をプッシュするとします。

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

したがって、ランドスケープ モードはサポートされていません。その上で、別の ViewController をコードでプッシュしましょう。

@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

ここで、iPhone を縦向きにして、ビュー コントローラー B を A の上にプッシュし、何らかのタッチ イベントを介して、ナビゲーション バーの「戻る」ボタンをタッチすると、すべて問題なく、デリゲート メソッドが呼び出されます (そこでいくつかのことを行います)。 )。

しかし、ビュー B を表示しているときに、横向きに回転してから戻るボタンを押すと、それらのデリゲート メソッドは呼び出されません!! メソッドが時々呼び出され、他のメソッドが呼び出されない場合、 UINavigationController のデリゲートを設定するポイントは何ですか? 確かに私は何か間違ったことをしています。

デリゲートを AppDelegate や MainView などの他のクラスに配置しようとしましたが、何も変わりません。

何か案は ?

デモコードはこちら: git://github.com/malaba/NavBarTest.git

上記のように変更された、基本的なマスター/ディテール テンプレートから。

私のポイントを示す方法は?手順は次のとおりです。

  1. マスター ビュー (+ 右上) にいくつかの行を追加します。
  2. 行をタップして詳細ビューに移動します
  3. ログイン出力の表示を参照してください
  4. 戻るボタン (「Master」というラベルが付いています) を押すと、再びログが表示されます。

詳細ビューで iPhone (またはシミュレーター) を回転させてみてから、「戻る」とログが表示されません。

4

2 に答える 2

2

こんにちは、このアイデアを見るまで、これは私にとっても難しい問題でした: http://www.hanspinckaers.com/custom-action-on-back-button-uinavigationcontroller

NavigationController と TopViewController の両方の向きが同じ場合、IOS は以下のコード (モノタッチ) を使用して次の呼び出しシーケンスを作成します。

  • SomeTopViewController ViewWillDisappear
  • WillShowViewController viewController: 新しい TopViewController
  • SomeTopViewController ViewDidDisappear
  • DidShowViewController viewController: 新しい TopViewController

NavigationController と TopViewController の向きが異なる場合、説明したように NavigationController デリゲートは呼び出されませんしたがって、呼び出しシーケンスは次のようになります。

  • SomeTopViewController ViewWillDisappear
  • SomeTopViewController ViewDidDisappear

次のコードは、NavigationController の PopViewControllerAnimated をオーバーライドして、ios 呼び出しシーケンスを再現します。

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);
    }
  } );
}

}

于 2012-04-25T11:58:12.433 に答える
1

Kasparの回答によると、これが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

それは動作します。

どう思いますか ?そして、バグレポートに記入する必要がありますか?

于 2012-05-03T09:44:06.113 に答える