2011-10-13 8 views
15

私はUIStoryboardPopoverSegueを使ってiOS 5 iPadアプリのポップオーバーを提示しています。 Segueはうまく機能しますが、ボタンを含むツールバーはポップオーバーコントローラーのパススルービューですので、ボタンを押し続けるとポップオーバーが多く表示されます。私はUIPopoverControllerを自分で作成して追跡していないので(ストーリーボードがそれを行っているので)、ボタンが再びタッチされたときに私はそれを却下することはできません。他に誰かがこれにぶつかっていますか?私はAppleにバグがありますが、回答はありませんでした。UIStoryboardPopoverSegueボタンのタッチで複数のウィンドウを開く

EDIT:私は以下の答えを使ってこれを解決しました。ここで私が使用し終わったコードです。 currentPopoverは私のビューコントローラクラスの__weak ivarです。コントローラが終了すると自動的にnilに落ちます。

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{ 
    if([segue isKindOfClass:[UIStoryboardPopoverSegue class]]){ 
     // Dismiss current popover, set new popover 
     [currentPopover dismissPopoverAnimated:YES]; 
     currentPopover = [(UIStoryboardPopoverSegue *)segue popoverController]; 
    } 
} 
+0

あなたの編集のおかげで、問題の洗練されたソリューション! – shapecatcher

答えて

2

あなたはprepareForSegueクラスメソッドでUIStoryboardPopoverSegueクラスの一部として渡さpopoverControllerプロパティへの参照を格納する必要があります。それにアクセスするには

、このような呼び出し元のビューコントローラでオーバー乗る方法:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 
{ 
    // The Storyboard Segue is named popover in this case: 
    if ([segue.identifier compare:@"popover"] == NSOrderedSame) { 
     // segue.popoverController is only present in popover segue's 
     // self.seguePopoverController is a UIPopoverController * property. 
     self.seguePopoverController = segue.popoverController; 
    } 
} 

その後、あなたは、通常の方法でそれを消すことができます。

+0

私はAppleからもう少し自動化されたものを望んでいましたが、これはうまくいきます。興味のある人のためにオリジナルの投稿に使ったコードを追加しました。 –

+0

すごい!このアプローチは、iOS 8.2搭載のiPads上で動作するiOS 7用にコンパイルされたコードでクラッシュします。ポップオーバーを解除するには、巻き戻しセグを使用する必要があります。ありがとうりんご。 – SpaceDog

0

これも良いです。

@interface ViewController : UIViewController <UIPopoverControllerDelegate> { 
    UIPopoverController * seguePopoverController; 
} 

@property (strong) UIPopoverController * seguePopoverController; 

@end 

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 
{ 
    if (self.seguePopoverController) { 
     [self.seguePopoverController dismissPopoverAnimated:NO]; 
     self.seguePopoverController = nil; 
    } 

    // The Storyboard Segue is named popover in this case: 
    if ([[segue identifier] isEqualToString:@"popover"]) { 

     UIStoryboardPopoverSegue* popSegue = (UIStoryboardPopoverSegue*)segue; 
     UIPopoverController *thePopoverController = [popSegue popoverController]; 
     thePopoverController.delegate = self; 
     self.seguePopoverController = thePopoverController; 

    } 
} 

- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController 
{ 
    self.seguePopoverController = nil; 
} 
+0

質問に追加したコードを使用すると、弱いivarが自動的にnilに落ち、そのコードの束が必要なくなります。あなたが別のポップオーバーセグを追加し、それを "ポップオーバー"という名前に忘れると、コードトップが機能します。 –

7

ソリューションCoryにはいくつかの視覚的な問題があります。

2つのオプションが考えられます。単純に、ポップオーバーを表示するボタンのアクションを削除または変更します。

オプション1、ボタンのアクションへのポインタを保持し、ポップオーバーが提示されたら、アクションをnilに設定します。 popoverの解雇時に元のアクションにリセットされます。

この方法では、ポップオーバーは1回しか表示されず、期待どおりに解除されます。

第2のオプションは、ポップオーバーが表示されているときにボタンをタップすると、ポップオーバーが解除されるように、ボタンの機能を変更することです。

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 
    { 

     action = [sender action]; 
     target = [sender target]; 

     [sender setTarget:self]; 
     [sender setAction:@selector(dismiss:)]; 

     self.currentPopover = [(UIStoryboardPopoverSegue *)segue popoverController]; 
     self.currentPopover.delegate = self; 
    } 

-(void)dismiss:(id)sender 
{ 
    [self.navigationItem.rightBarButtonItem setAction:action]; 
    [self.navigationItem.rightBarButtonItem setTarget:target]; 
    ////or 
// [sender setAction:action]; 
// [sender setTarget:target]; 
    [self.currentPopover dismissPopoverAnimated:YES]; 
} 


    -(BOOL)popoverControllerShouldDismissPopover:(UIPopoverController *)popoverController 
    { 
     [self.navigationItem.rightBarButtonItem setAction:action]; 
     [self.navigationItem.rightBarButtonItem setTarget:target]; 

     return YES; 
    } 
+0

Robertのソリューションは私にとって完璧に機能します。私はこれがUISplitViewControllerでこのテクニックを実装する方法だと思います。 アドオンだけで、2つのivarsを追加する必要があります。 SELアクション。 id targer; ; 乾杯! – Raunak

+0

優秀!私がこれに追加する唯一のものは別のivar:id myPopButtonで、これをprepareForSegueで設定します:myPopButton = sender;この方法で、複数のボタンを参照することができます(ツールバーから呼び出されると、 'frinstance')。 'dismiss'と 'popoverControllerShouldDismissPopover'メソッドでは、以下を呼び出します。[myPopButton setAction:action];および[myPopButton setTarget:target];これを試してみて、それはうまくいきます(iOS SDK 6.0)。 – mpemburn

2

このソリューションには視覚的な問題もありますが、私の単純なケースではありません。私の場合、popoverはちょうど助けを表示していました。私は、ボタンバーボタンが2回押されたとき(オリジナルと新しく作成されたボタンの両方)、ポップオーバービューコントローラを閉じる(ARC付きの)以下をまとめました。

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 
{ 
    if([segue isKindOfClass:[UIStoryboardPopoverSegue class]]) 
    { 
     UIStoryboardPopoverSegue *popoverSegue  = (id)segue; 
     UIPopoverController  *popoverController = popoverSegue.popoverController; 

     if(m_popoverController.popoverVisible) 
     { 
      [m_popoverController dismissPopoverAnimated:NO]; 
      dispatch_async(dispatch_get_main_queue(), ^{ 
       [popoverController dismissPopoverAnimated:YES]; 
      }); 
      m_popoverController = nil; 
     } 
     else 
      m_popoverController = popoverController;   
    }  
} 

は、私はまた、それは

UIPopoverController *m_popoverController; 
3

は単にUIBarButtonItemIBAction経由での接続クラスのメンバ変数を必要としないのdealloc

- (void)dealloc 
{ 
    if(m_popoverController.popoverVisible) 
     [m_popoverController dismissPopoverAnimated:YES]; 
} 

にいくつかのクリーンアップを追加しました。インタフェースビルダーに設定itendifierを使用する:

UIPopoverController *currentPopoverController; 

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 
    if ([[segue identifier] isEqualToString:@"aSegueIdentifier"]) 
     currentPopoverController = [(UIStoryboardPopoverSegue *)segue popoverController]; 
} 

currentPopoverControllerヘッダファイルに定義されたインスタンス変数であり:

-(IBAction)barButtonItemPressed:(id)sender { 
    if (currentPopoverController && currentPopoverController.popoverVisible) { 
     [currentPopoverController dismissPopoverAnimated:YES]; 
     currentPopoverController = nil; 
    } else { 
     [self performSegueWithIdentifier:@"aSegueIdentifier" sender:sender]; 
    } 
} 

sequeから新しいUIPopoverCOntrollerの参照を取得します

重要:Sequeのアンカープロパティは、対応するUIBarButtonItemに設定する必要があります。

+0

'currentPopoverController'のデリゲートnilを' didDismiss'で参照しないように設定しない限り、ここでも複数のpopoversの問題が発生します。 [私の推奨する回避策](http://stackoverflow.com/a/10238581/957768)はこれとほとんど同じですが、私は 'currentPopoverController'を弱参照にしています。それは自動的に' nil''dを取得しますポップオーバーが却下された方法の – rickster

2

私は1つの場所で一緒にすべてを保持し、静的な弱い変数を、使用することを好む:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 
{ 
    if ([[segue identifier] isEqualToString:@"showSomething"]) { 
     static __weak UIPopoverController* currentPopover = nil; 
     [currentPopover dismissPopoverAnimated:NO]; 
     currentPopover = [(UIStoryboardPopoverSegue *)segue popoverController]; 
     // ... 
    } 
} 

ビューコントローラの複数のインスタンスを持ってしようとしているとき、別の余分な変数を追加する理由は(ありません?)、このようにしてif()ブロックごとに余分な変数を追加することができます。

+0

賢い解決策 – Nektarios

1

6月14日

問題の編集をありがとう。パフォーマンスとバッテリの懸念を避け、View Controllerを破棄して再作成するときにFlashを防ぐために、ポップオーバーの2番目のインスタンスがポップするのを防ぐ方法については、ビューコントローラを破棄して再作成するのではなく、

//place in view controller (tested iOS6+, iPad, iPhone) 
__weak UIPopoverController *popover; 
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 
    if([segue isKindOfClass:[UIStoryboardPopoverSegue class]] 
     && [segue.identifier isEqualToString:@"mySegue"]) //remember to change "mySegue" 
      popover = [(UIStoryboardPopoverSegue *)segue popoverController]; 
} 
- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender { 
    if ([identifier isEqualToString:@"mySegue"]) //remember to change "mySegue" 
     return !popover; 
    else 
     return YES; 
} 
added checks to: http://stackoverflow.com/a/10238581/1705353 
+1

私はそれが好きです。私の元の投稿の編集のコードをshouldPerformコードと組み合わせると、編集コードよりも視覚的に少し楽しいものになります。 –

関連する問題