埋め込みナビゲーションコントローラーを使用したポップオーバーでバックナビゲーションのサイズが考慮されない


89

ビューコントローラーの小さな階層を含むUINavigationControllerをホストしているUIPopoverControllerがあります。

私はドキュメントに従い、ビューコントローラーごとに、ビューのポップオーバーコンテキストのサイズを次のように設定しました:

[self setContentSizeForViewInPopover:CGSizeMake(320, 500)];

(サイズはコントローラーごとに異なります)

これは、私が階層内を進んでいくときに期待どおりに機能します。ポップオーバーは、プッシュされたコントローラーに対応するようにサイズ変更を自動的にアニメーション化します。

ただし、ナビゲーションバーの[戻る]ボタンを使用してビュースタックを「戻る」にナビゲートすると、ポップオーバーのサイズは変更されず、最も深いビューに到達したときと同じ大きさのままになります。これは私には壊れているようです。私はポップオーバーがビュースタックをポップするときに設定されるサイズを尊重することを期待します。

何か不足していますか?

ありがとう。


ポップオーバーサイズはどこで設定していますか?ビューコントローラーが表示されるたびに(たとえばviewWillAppear:)リセットしますか?
Ole Begemann

どんなドキュメントをフォローしたのですか?
トムハミング

回答:


94

わかりました、私は同じ問題で苦労していました。上記の解決策はどれもうまく機能しませんでした。そのため、少し調査して、これがどのように機能するかを確認することにしました。これは私が発見したものです:-あなたが設定したときcontentSizeForViewInPopoverビューコントローラーでは、ポップオーバー自体によって変更されることはありません-別のコントローラーに移動しているときにポップオーバーのサイズが変わる場合があります。-別のコントローラーに移動しているときにポップオーバーのサイズが変わると、戻るときにポップオーバーのサイズは復元されません-viewWillAppearでポップオーバーのサイズを変更すると、非常に奇妙なアニメーションが表示されます(ポップオーバー内にpopControllerがあるとしましょう)-私はそれをお勧めしません-私の場合、コントローラー内にハードコードされたサイズを設定してもまったく機能しません-私のコントローラーはときどき大きくなければならないことがあります-コントローラーはサイズについての考えを持っていますが

これらすべての問題の解決策は次のとおりですcurrentSetSizeForPopover。viewDidAppearのサイズをリセットする必要があります。ただし、フィールドですでに設定されているのと同じサイズを設定するとcurrentSetSizeForPopover、ポップオーバーがサイズを変更しないので、注意する必要があります。これを行うには、最初に偽のサイズ(以前に設定されたものとは異なります)を設定してから、適切なサイズを設定します。このソリューションは、コントローラーがナビゲーションコントローラー内にネストされていても機能し、コントローラー間を戻るときにポップオーバーがそのサイズを変更します。

サイズの設定でトリックを実行する次のヘルパーメソッドを使用して、UIViewControllerにカテゴリを簡単に作成できます。


- (void) forcePopoverSize {
    CGSize currentSetSizeForPopover = self.contentSizeForViewInPopover;
    CGSize fakeMomentarySize = CGSizeMake(currentSetSizeForPopover.width - 1.0f, currentSetSizeForPopover.height - 1.0f);
    self.contentSizeForViewInPopover = fakeMomentarySize;
    self.contentSizeForViewInPopover = currentSetSizeForPopover;
}

次に-viewDidAppear、目的のコントローラーでそれを呼び出します。


1
上記のカテゴリは、私がそれを機能させることができる唯一の(健全な)方法です。ありがとう。
RickiG、2011

これは機能します。ポップオーバーが縮小したときに収縮領域でテーブルビューが「黒」にならないようにする方法を理解する必要がありますが、このソリューションでは(最終的に)ポップオーバーを各スタックレベルの正しいサイズに移動できます。ありがとう!
Ben Zotto

2
[UIView beginAnimations:nil context:nil]でラップしました。および[UIView commitAnimations]; -不快感を少なくします。
ダスティン

2
私にとっては、self.contentSizeForViewInPopover = CGSizeZero;を使用しています。行を保存し、同じ効果がありました。どうもありがとう!
rob5408 2013年

self.contentSizeForPopover = CGSizeZero;を追加した場合にのみ、このソリューションを機能させることができました。私がポップしていたVCのviewWillDisappearメソッドで。
LightningStryk

18

iOS 7および8で解決した方法は次のとおりです。

iOS 8では、iOSは、ポップオーバーで必要なビューをpresentingViewControllerビューコントローラーのpresentedViewControllerに暗黙的にラップします。彼らがこれに触れているpopovercontrollerの新機能を説明する2014 WWDCビデオがあります。

とにかく、ナビゲーションコントローラースタック上に表示され、すべて独自のサイズを必要とするビューコントローラーの場合、これらのビューコントローラーは(iOS 8では)このコードを呼び出して、preferredContentSizeを動的に設定する必要があります。

self.presentingViewController.presentedViewController.preferredContentSize = CGSizeMake(320, heightOfTable);

heightOfTableを計算されたテーブルまたはビューの高さに置き換えます。

多くの重複コードを回避し、一般的なiOS 7およびiOS 8ソリューションを作成するために、UITableViewControllerにカテゴリを作成して、viewDidAppearが私のテーブルビューで呼び出されたときにこの作業を実行します。

- (void)viewDidAppear:(BOOL)animated 
{
    [super viewDidAppear:animated];
    [self setPopOverViewContentSize];
}

Category.h:

#import <UIKit/UIKit.h>

@interface UITableViewController (PreferredContentSize)

- (void) setPopOverViewContentSize;

@end

Category.m:

#import "Category.h"

@implementation UITableViewController (PreferredContentSize)

- (void) setPopOverViewContentSize
{
    [self.tableView layoutIfNeeded];
    int heightOfTable = [self.tableView contentSize].height;

    if (heightOfTable > 600)
        heightOfTable = 600;

    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
        if ([[[UIDevice currentDevice] systemVersion] floatValue] < 8.0)
            self.preferredContentSize=CGSizeMake(320, heightOfTable);
        else
            self.presentingViewController.presentedViewController.preferredContentSize = CGSizeMake(320, heightOfTable);
    }
}

@end

presentingViewController作品のヒント。私は、設定された場合preferredContentSizeにはviewDidLoad、間違ったポップオーバーサイズの変更にポップオーバーリード内の別のビューコントローラからナビゲーションバック:奇妙な振る舞いがあります。ゼロのポップオーバーサイズが設定されているように見えますが、サイズは正しいです。このような場合、ポップオーバーは画面全体の高さになります。おそらくこれが事実である理由を知っていますか?私の経験では、オペレーティングシステムでは画面サイズよりも大きいサイズを指定できないため、600ポイントを実装するという制限はありません。
テスト

スタックを上に戻ったときにコードが実行されるように、viewDidLoadではなくviewDidAppearを試してください。
Wesley Filleman 2014

それが私のやり方でした。あなたがこの中に設定されている場合しかし、私は、なぜそれがないでしょう仕事を得ることはありませんviewDidLoad...
テスト

1
残念ながら、それはAppleがビュースタックを書いた方法ではありません。viewControllerがビューから非表示になると、これらのcontentSize値は実際には保持されません。そのため、プッシュまたはポップのいずれかによってビューが前面に表示されるたびに、ポップオーバーを「思い出させる」必要があります。ポップオーバーでこの情報を保持する必要がある場合は、Appleにバグレポートを提出することをお勧めします。
Wesley Filleman 2014

12

これはkrasnykの答えの改善です。
あなたのソリューションは素晴らしいですが、スムーズにアニメーション化されていません。
少し改善すると、素晴らしいアニメーションが得られます:メソッドの

最後の行を削除し- (void) forcePopoverSizeます

- (void) forcePopoverSize {
    CGSize currentSetSizeForPopover = self.contentSizeForViewInPopover;
    CGSize fakeMomentarySize = CGSizeMake(currentSetSizeForPopover.width - 1.0f, currentSetSizeForPopover.height - 1.0f);
    self.contentSizeForViewInPopover = fakeMomentarySize;
}

- (void)viewWillAppear:(BOOL)animatedメソッドに[self forcePopoverSize]を追加します。

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    [self forcePopoverSize];
}

そして最後に- - (void)viewDidAppear:(BOOL)animatedメソッドで目的のサイズを設定します:

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    CGSize currentSetSizeForPopover = self.contentSizeForViewInPopover;
    self.contentSizeForViewInPopover = currentSetSizeForPopover;
}

8

でコンテンツサイズを再度設定する必要がありviewWillAppearます。popovercontrollerのサイズを設定するdelagateメソッドを呼び出す。私も同じ問題を抱えていました。しかし、これを追加すると問題は解決しました。

もう1つ:5未満のベータバージョンを使用している場合、ポップオーバーの管理がより困難になります。彼らはベータ版5からより友好的であるようです。最終版が出ていることは良いことです。;)

お役に立てれば。


私もこれが嫌いです。それも私を捕まえた。アップル:navcontrollerでポップオーバーを指定されたサイズにロックできないのはなぜですか?
Jann

2
コンテンツサイズの設定でviewWillAppearうまくいきませんでした。ポップオーバーのサイズを明示的に設定することは機能しましたが、それはゲットーです。
ベンZotto

@quixoto私はあなたの問題が何であったかはわかりませんが、私はまだ同じものを使用しており、それは完全に機能します。
Madhup Singh Yadav、2010

5

では-(void)viewDidLoadあなたはナビゲーションコントローラで使用しているすべてのビューコントローラ、追加します。

[self setContentSizeForViewInPopover:CGSizeMake(320, 500)];

3

以下からナビゲートされているビューコントローラーのviewWillDisappear:(BOOL)animatedメソッドでサイズをリセットします。

-(void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    CGSize contentSize = [self contentSizeForViewInPopover];
    contentSize.height = 0.0;
    self.contentSizeForViewInPopover = contentSize;
}

次に、ナビゲートされているビューが表示されたら、サイズを適切にリセットします。

-(void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    CGSize contentSize;
    contentSize.width = self.contentSizeForViewInPopover.width;
    contentSize.height = [[self.fetchedResultsController fetchedObjects] count] *  self.tableView.rowHeight;
    self.contentSizeForViewInPopover = contentSize;
}

うーん..リセットは必要ありませんでした。すべてのビューコントローラーのすべてのviewWillAppearにself.contentSizeForViewInPopover = self.view.frame.sizeを配置します。
alones

fetchedResultsController fetchedObjectsには何を入れますか?これを機能させることができません
ジュール

2

iOS 8の場合、次のように機能します。

- (void) forcePopoverSize {
    CGSize currentSetSizeForPopover = self.preferredContentSize;
    CGSize fakeMomentarySize = CGSizeMake(currentSetSizeForPopover.width - 1.0f, currentSetSizeForPopover.height - 1.0f);
    self.preferredContentSize = fakeMomentarySize;
    self.navigationController.preferredContentSize = fakeMomentarySize;
    self.preferredContentSize = currentSetSizeForPopover;
    self.navigationController.preferredContentSize = currentSetSizeForPopover;
}

ところで、これは以前のiOSバージョンと互換性があるはずだと思います...


iOS7 SDKでコンパイルされたiOS8のアプリに問題がありました。これはうまくいきました。
2015年

回転を変更するときにサイズを修正するにwillTransitionToTraitCollectionは、animateAlongsideTransition完了ブロックのでこのメソッドを呼び出します。
ジェバ

2
Well i worked out. Have a look.


Made a ViewController in StoryBoard. Associated with PopOverViewController class.


import UIKit

class PopOverViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        self.preferredContentSize = CGSizeMake(200, 200)

        self.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Done, target: self, action: "dismiss:")

    }

    func dismiss(sender: AnyObject) {
        self.dismissViewControllerAnimated(true, completion: nil)
    }
}




See ViewController:


//
//  ViewController.swift
//  iOS8-PopOver
//
//  Created by Alvin George on 13.08.15.
//  Copyright (c) 2015 Fingent Technologies. All rights reserved.
//

import UIKit

class ViewController: UIViewController, UIPopoverPresentationControllerDelegate
{
    func showPopover(base: UIView)
    {
        if let viewController = self.storyboard?.instantiateViewControllerWithIdentifier("popover") as? PopOverViewController {


            let navController = UINavigationController(rootViewController: viewController)
            navController.modalPresentationStyle = .Popover

            if let pctrl = navController.popoverPresentationController {
                pctrl.delegate = self

                pctrl.sourceView = base
                pctrl.sourceRect = base.bounds

                self.presentViewController(navController, animated: true, completion: nil)
            }
        }
    }

    override func viewDidLoad(){
        super.viewDidLoad()
    }

    @IBAction func onShow(sender: UIButton)
    {
        self.showPopover(sender)
    }

    func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
        return .None
    }
}


Note: The func showPopover(base: UIView) method should be placed before ViewDidLoad. Hope it helps !

1

私にとって、このソリューションは機能します。これは、UITableViewControllerを拡張する私のビューコントローラからのメソッドであり、UINavigationControllerのルートコントローラです。

-(void)viewDidAppear:(BOOL)animated {
     [super viewDidAppear:animated];
     self.contentSizeForViewInPopover = self.tableView.bounds.size;
}

ナビゲーションスタックにプッシュするView Controllerのコンテンツサイズを設定することを忘れないでください

- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath{
    dc = [[DetailsController alloc] initWithBookmark:[[bookmarksArray objectAtIndex:indexPath.row] retain] bookmarkIsNew:NO];
    dc.detailsDelegate = self;
    dc.contentSizeForViewInPopover = self.contentSizeForViewInPopover;
    [self.navigationController pushViewController:dc animated:YES]; 
 }

1

あなたがアサンブラーを想像できるなら、私はこれが少し良いと思います:

-(void)forcePopoverSize {
    CGSize currentSetSizeForPopover = self.contentSizeForViewInPopover;
    self.contentSizeForViewInPopover = CGSizeMake(0、0);
    self.contentSizeForViewInPopover = currentSetSizeForPopover;
}

2
CGSizeZero代わりに自分で作成して使用することをおCGSizeMake(0,0)
勧め

1

受け入れ答えは、私は自分自身のサブクラス作成していた何をしたかのiOS 8で正常に動作していないUINavigationControllerというポップオーバーで使用するためのメソッドをオーバーライドしてpreferredContentSize、このように:

- (CGSize)preferredContentSize {
    return [[self.viewControllers lastObject] preferredContentSize];
}

さらに、forcePopoverSize(@ krasnykによって実装されたメソッド)を呼び出す代わりに、viewDidAppear前述のナビゲーション(ポップオーバー)のデリゲートとしてviewController(ポップオーバーを表示)を設定し、次のように(強制メソッドが実行する動作)を行うことにしました。

-(void)navigationController:(UINavigationController *)navigationController
      didShowViewController:(UIViewController *)viewController 
                   animated:(BOOL)animated  

渡されたのデリゲートメソッドviewController。重要なことの1つforcePopoverSizeは、UINavigationControllerDelegateそのアニメーションをスムーズにする必要がない場合はメソッドで実行しても問題ない場合は、そのままにしておいてくださいviewDidAppear


なぜ投票しないのですか?多分ちょうど不一致とは異なるいくつかのフィードバック:)
JulianKrólOct

こんにちは@JulianKról、あなたはこのstackoverflow.com/questions/28112617/…を見ていただけますか、私は同じ問題を抱えています。
ランジット、2015年

おかげで、これは私を助けました。コメントの先頭で、問題は、navigationController preferredContentSizeとvisibleVC preferredContentSizeを更新する必要があることを明確にしたい場合があります。したがって、両方を直接設定することもできます。
Michael Kernahan、2015

0

同じ問題に直面していましたが、viewWillAppearまたはviewWillDisappearメソッドでcontentsizeを設定したくありません。

AirPrintController *airPrintController = [[AirPrintController alloc] initWithNibName:@"AirPrintController" bundle:nil];
airPrintController.view.frame = [self.view frame];
airPrintController.contentSizeForViewInPopover = self.contentSizeForViewInPopover;
[self.navigationController pushViewController:airPrintController animated:YES];
[airPrintController release];

そのコントローラーをnavigationControllerにプッシュする前に、そのコントローラーのcontentSizeForViewInPopoverプロパティを設定します


0

私はviewdidappearに以下を入れることで運がありました:

[self.popoverController setPopoverContentSize:self.contentSizeForViewInPopover animated:NO];

異なるサイズのポップオーバーをプッシュ/ポップする場合、これはうまくアニメーションしないかもしれませんが。しかし、私の場合、完全に機能します!


0

あなたがしなければならないすべてはです:

-popOvers contentViewのviewWillAppearメソッドに、以下のスニペットを追加します。ロード時にpopOverのサイズを最初に指定する必要があります。

CGSize size = CGSizeMake(width,height);
self.contentSizeForViewInPopover = size;

0

最初はpopoverContentSize = CGSizeMake(320、600)のポップオーバーコントローラーでこの問題がありましたが、そのContentViewController(UINavigationController)をナビゲートすると大きくなります。

navコントローラーはカスタムUITableViewControllersをプッシュおよびポップするだけだったので、私のカスタムテーブルビューコントローラークラスのviewDidLoadでself.contentSizeForViewInPopover = CGSizeMake(320、556)を設定しました

少ない44ピクセルは、Navコントローラーのナビゲーションバーを考慮に入れるためのもので、もう問題はありません。


0

これを、ポップオーバー内にプッシュするすべてのビューコントローラーに配置します。

CGSize currentSetSizeForPopover = CGSizeMake(260, 390);
CGSize fakeMomentarySize = CGSizeMake(currentSetSizeForPopover.width - 1.0f,
                                      currentSetSizeForPopover.height - 1.0f);
self.contentSizeForViewInPopover = fakeMomentarySize;
self.contentSizeForViewInPopover = currentSetSizeForPopover;

viewwillAppearメソッドで、currentSetSizeForPopoverで希望のサイズを設定します。
alok、2013年

0

同じ問題に直面し、UIPopoverControllerのinitが配置される前にコンテンツビューのサイズをナビゲーションコントローラーとビューコントローラーに設定することで修正しました。

     CGSize size = CGSizeMake(320.0, _options.count * 44.0);
    [self setContentSizeForViewInPopover:size];
    [self.view setFrame:CGRectMake(0.0, 0.0, size.width, size.height)];
    [navi setContentSizeForViewInPopover:size];

    _popoverController = [[UIPopoverController alloc] initWithContentViewController:navi];

0

これらはどれもうまくいかなかったので、私は別のソリューションを提供したいのですが...

私はこれを実際に使っていますhttps://github.com/nicolaschengdev/WYPopoverController

最初にポップアップを呼び出すときは、これを使用します。

if ([sortTVC respondsToSelector:@selector(setPreferredContentSize:)]) {
   sortTVC.preferredContentSize = CGSizeMake(popoverContentSortWidth,
        popoverContentSortHeight);
}
else 
{
   sortTVC.contentSizeForViewInPopover = CGSizeMake(popoverContentSortWidth, 
        popoverContentSortHeight);
}

次に、そのポップアップでこれを使用します。

-(void)viewWillAppear:(BOOL)animated {
  [super viewWillAppear:YES];

  if ([self respondsToSelector:@selector(setPreferredContentSize:)]) {
    self.preferredContentSize = CGSizeMake(popoverContentMainWidth, 
        popoverContentMainheight);
  }
  else 
  {
    self.contentSizeForViewInPopover = CGSizeMake(popoverContentMainWidth, 
        popoverContentMainheight);
  }
}

-(void)viewDidDisappear:(BOOL)animated {
 [super viewDidDisappear:YES];

self.contentSizeForViewInPopover = CGSizeZero;

}

次に、子ビューについて繰り返します...


0

これは、iOS7でこれを行うための正しい方法です。ナビゲーションスタックの各ビューコントローラーのviewDidLoadで優先コンテンツサイズを設定します(一度だけ実行)。次に、viewWillAppearでポップオーバーコントローラーへの参照を取得し、そこでcontentSizeを更新します。

-(void)viewDidLoad:(BOOL)animated
{
    ...

    self.popoverSize = CGSizeMake(420, height);
    [self setPreferredContentSize:self.popoverSize];
}

-(void)viewWillAppear:(BOOL)animated
{
    ...

    UIPopoverController *popoverControllerReference = ***GET REFERENCE TO IT FROM SOMEWHERE***;
    [popoverControllerReference setPopoverContentSize:self.popoverSize];
}

0

@krasnykソリューションは以前のiOSバージョンではうまく機能しましたが、iOS8では機能しませんでした。次の解決策は私のために働いた。

    - (void) forcePopoverSize {
        CGSize currentSetSizeForPopover = self.preferredContentSize;
       //Yes, there are coupling. We need to access the popovercontroller. In my case, the popover controller is a weak property in the app's rootVC.
        id mainVC = [MyAppDelegate appDelegate].myRootVC;
        if ([mainVC valueForKey:@"_myPopoverController"]) {
            UIPopoverController *popover = [mainVC valueForKey:@"_myPopoverController"];
            [popover setPopoverContentSize:currentSetSizeForPopover animated:YES];
        }
    }

これは最善の解決策ではありませんが、機能します。

新しいUIPopoverPresentationControllerにもサイズ変更の問題があります:(。


1
多分代わりにAppDelegateプロパティからビューコントローラに到達する(クリーナーのようです)私の解決策を検討
ジュリアンKról

はい、これは私の既存のコードベースを変更することなく、最も迅速なソリューションでした。Btw vl try ur solution
Clement Prem 2014年

0

preferredContentSizeNavigationController のプロパティを設定する必要がありますviewWillAppear

-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.navigationController.preferredContentSize = CGSizeMake(320, 500);}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.