web-dev-qa-db-ja.com

ナビゲーションコントローラーが埋め込まれたポップオーバーは、バックナビゲーションのサイズを考慮しません

UINavigationControllerをホストするUIPopoverControllerがあります。これには、View Controllerの小さな階層が含まれています。

私はドキュメントに従って、各View Controllerについて、ビューのポップオーバーコンテキストサイズを次のように設定しました:

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

(コントローラーごとに異なるサイズ)

階層内を前方に移動すると、期待どおりに機能します。ポップオーバーは、プッシュされたコントローラーに対応するサイズ変更を自動的にアニメーション化します。

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

何か不足していますか?

ありがとう。

88
Ben Zotto

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

すべての痛みの解決策は次のとおりです。viewDidAppearでcurrentSetSizeForPopoverのサイズをリセットする必要があります。ただし、フィールドcurrentSetSizeForPopoverに既に設定されているサイズと同じサイズを設定する場合、ポップオーバーはサイズを変更しません。これを実現するには、最初に偽のサイズ(前に設定したサイズとは異なる)を設定し、その後適切なサイズを設定します。このソリューションは、コントローラーがNavigation Controller内にネストされていても機能し、コントローラー間をナビゲートするときにPopoverのサイズが適宜変更されます。

サイズを設定するトリックを行う次のヘルパーメソッドを使用して、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で呼び出します。

92
krasnyk

IOS 7および8でそれを解決した方法は次のとおりです。

IOS 8では、iOSは、ポップオーバーで必要なビューをpresentingViewControllerビューコントローラのpresentedViewControllerに静かにラップします。 2014年のWWDCビデオでは、popovercontrollerの新機能について説明しています。

とにかく、Navigation Controllerスタックに表示されるView Controllerがすべて独自のサイズ設定を必要とする場合、これらのView Controllerは(iOS 8で)このコードを呼び出してpreferredContentSizeを動的に設定する必要があります。

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

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

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

- (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
18
Wesley Filleman

これは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;
}
_
12
adnako

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

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

お役に立てれば。

8

Navigation Controllerで使用しているすべてのView Controllerの-(void)viewDidLoadに、以下を追加します:

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

ナビゲートされているView Controllerの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;
}
3
Greg C
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 !
2
A.G

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バージョンと互換性があるはずだと思います...

2
Zeroid

受け入れられた答え はiOS 8では正常に動作しません。私がしたことは、そのポップオーバーで使用するUINavigationControllerのサブクラスを作成し、このメソッドpreferredContentSizeをオーバーライドすることでした。方法:

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

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

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

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

1
Julian Król

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

-(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
Koteg

あなたがアサンブラーを想像できるなら、私はこれがわずかに優れていると思います:

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

これはiOS7でこれを行う正しい方法です。NavigationStackの各View Controllerの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
anders

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

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

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

NavigationControllerのpreferredContentSizeプロパティをviewWillAppearに設定する必要があります。

-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.navigationController.preferredContentSize = CGSizeMake(320, 500);}

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

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

44個少ないピクセルは、Navコントローラーのnavバーを説明するためのものであり、もう問題はありません。

0
leukosaima

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

     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
Tomasz Dubik

これをポップオーバー内にプッシュするすべてのView Controllerに入れます

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

@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にもサイズ変更の問題があります:(。

0
Clement Prem

Viewdidappearに以下を配置することで、私は幸運に恵まれました。

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

ただし、異なるサイズのポップオーバーをプッシュ/ポップする場合、これはうまくアニメーション化されない場合があります。しかし、私の場合、完全に動作します!

0
Chris

これらのどれも私のために働いていなかったので、私は別のソリューションを提供したいだけです...

私は実際にこれで使用しています 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
Jules

私は同じ問題に直面していましたが、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
Vikas Sawant