Popover dengan pengontrol navigasi tertanam tidak menghargai ukuran di navigasi belakang


89

Saya memiliki UIPopoverController yang menghosting UINavigationController, yang berisi hierarki kecil pengontrol tampilan.

Saya mengikuti dokumen dan untuk setiap pengontrol tampilan, saya mengatur ukuran konteks popover tampilan seperti ini:

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

(ukuran berbeda untuk setiap pengontrol)

Ini berfungsi seperti yang diharapkan saat saya menavigasi ke depan dalam hierarki - popover secara otomatis menganimasikan perubahan ukuran agar sesuai dengan pengontrol yang didorong.

Namun, saat saya menavigasi "Kembali" melalui tumpukan tampilan melalui tombol Kembali pada bilah navigasi, munculan tidak mengubah ukuran-- ukurannya tetap sebesar tampilan terdalam yang dicapai. Ini tampaknya rusak bagi saya; Saya berharap popover menghormati ukuran yang diatur saat muncul melalui tumpukan tampilan.

Apakah saya melewatkan sesuatu?

Terima kasih.


Di mana Anda menyetel ukuran popover? Apakah Anda menyetel ulang setiap kali pengontrol tampilan ditampilkan (mis. Dalam viewWillAppear:)?
Ole Begemann

Dokumentasi apa yang Anda ikuti?
Tom Hamming

Jawaban:


94

Oke, saya sedang berjuang dengan masalah yang sama. Tidak ada solusi di atas yang berhasil untuk saya, itulah sebabnya saya memutuskan untuk melakukan sedikit penyelidikan dan mencari tahu cara kerjanya. Inilah yang saya temukan: - Saat Anda menyetelcontentSizeForViewInPopoverdi pengontrol tampilan Anda, itu tidak akan diubah oleh popover itu sendiri - meskipun ukuran popover dapat berubah saat menavigasi ke pengontrol yang berbeda. - Ketika ukuran popover akan berubah saat menavigasi ke pengontrol yang berbeda, sementara kembali, ukuran popover tidak mengembalikan - Mengubah ukuran popover di viewWillAppear memberikan animasi yang sangat aneh (misalkan Anda popController di dalam popover) - Saya tidak akan merekomendasikannya - Bagi saya pengaturan ukuran hardcode di dalam pengontrol tidak akan berfungsi sama sekali - pengontrol saya harus terkadang besar terkadang kecil - pengontrol yang akan menampilkan mereka memiliki gagasan tentang ukurannya.

Solusi untuk semua rasa sakit itu adalah sebagai berikut: Anda harus mengatur ulang ukuran currentSetSizeForPopoverin viewDidAppear. Tetapi Anda harus berhati-hati, ketika Anda akan mengatur ukuran yang sama seperti yang telah ditetapkan di lapangan currentSetSizeForPopovermaka popover tidak akan mengubah ukuran. Agar ini terjadi, pertama-tama Anda dapat mengatur ukuran palsu (yang akan berbeda dari yang ditetapkan sebelumnya) diikuti dengan mengatur ukuran yang sesuai. Solusi ini akan berfungsi bahkan jika pengontrol Anda bersarang di dalam pengontrol navigasi dan popover akan mengubah ukurannya sesuai ketika Anda akan menavigasi kembali di antara pengontrol.

Anda dapat dengan mudah membuat kategori di UIViewController dengan metode helper berikut yang akan melakukan trik dengan menyetel ukuran:


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

Kemudian panggil saja di -viewDidAppearpengontrol yang diinginkan.


1
Kategori di atas adalah satu-satunya cara (waras) saya untuk membuatnya berhasil. Terima kasih.
RickiG

Ini bekerja. Saya perlu mencari cara untuk menjaga agar tampilan tabel tidak menjadi "hitam" di area yang berkontraksi saat popover menyusut, tetapi solusi ini (akhirnya!) Benar-benar memungkinkan popover berpindah ke ukuran yang benar untuk setiap tingkat tumpukan. Terima kasih!
Ben Zotto

2
Saya membungkusnya dalam [UIView beginAnimations: nil context: nil]; dan [UIView commitAnimations]; - membuatnya tidak terlalu menggelegar.
Dustin

2
Bagi saya, menggunakan self.contentSizeForViewInPopover = CGSizeZero; menyelamatkan garis dan memiliki efek yang sama. Terimakasih banyak!
rob5408

Saya hanya bisa mendapatkan solusi ini untuk bekerja jika saya menambahkan self.contentSizeForPopover = CGSizeZero; dalam metode viewWillDisappear saya dari VC tempat saya muncul.
LightningStryk

18

Inilah cara saya menyelesaikannya untuk iOS 7 dan 8:

Di iOS 8, iOS secara diam-diam menggabungkan tampilan yang Anda inginkan dalam popover ke dalam pengontrol tampilan presentingViewController yang disajikan. Ada video WWDC 2014 yang menjelaskan apa yang baru dengan popovercontroller di mana mereka menyentuh ini.

Bagaimanapun, untuk pengontrol tampilan yang disajikan pada tumpukan pengontrol navigasi yang semuanya menginginkan ukurannya sendiri, pengontrol tampilan ini perlu (di bawah iOS 8) untuk memanggil kode ini untuk secara dinamis menyetel PreferensiContentSize:

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

Ganti heightOfTable dengan tabel yang dihitung atau tinggi tampilan.

Untuk menghindari banyak kode duplikat dan untuk membuat solusi umum iOS 7 dan iOS 8, saya membuat kategori di UITableViewController untuk melakukan pekerjaan ini ketika viewDidAppear dipanggil dalam tampilan tabel saya:

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

Tip Anda dengan presentingViewControllerkarya. Jika saya mengatur preferredContentSizedi viewDidLoadada perilaku aneh: Menavigasi kembali dari pengontrol tampilan lain di popover mengarah ke perubahan ukuran popover yang salah. Tampaknya ukuran popover nol telah disetel, tetapi ukurannya benar. Dalam kasus seperti itu, popover mengambil seluruh tinggi layar. Apakah Anda mungkin tahu mengapa ini terjadi? Saya tidak memiliki batasan dengan 600 poin yang diterapkan karena menurut pengalaman saya, sistem operasi tidak mengizinkan Anda menentukan ukuran yang lebih tinggi dari ukuran layar.
menguji

Coba viewDidAppear alih-alih viewDidLoad sehingga kode dieksekusi saat Anda menavigasi kembali tumpukan.
Wesley Filleman

Itulah cara saya mengambil. Tapi saya tidak mengerti mengapa itu tidak akan berhasil jika Anda mengatur ini di viewDidLoad...
menguji

1
Sayangnya bukan itu cara Apple menulis view stack. Nilai contentSize ini tidak benar-benar bertahan setelah viewController disembunyikan dari tampilan. Itulah mengapa Anda harus "mengingatkan" popover setiap kali ada tampilan yang muncul di latar depan baik dengan push atau pop. Rekomendasi saya adalah mengajukan laporan bug ke Apple jika menurut Anda popover harus menyimpan informasi ini.
Wesley Filleman

12

Ini merupakan perbaikan dari jawaban krasnyk .
Solusi Anda bagus, tetapi tidak dianimasikan dengan mulus.
Sedikit perbaikan memberikan animasi yang bagus:

Hapus baris terakhir dalam - (void) forcePopoverSizemetode:

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

Masukkan [self forcePopoverSize] ke dalam - (void)viewWillAppear:(BOOL)animatedmetode:

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

    [self forcePopoverSize];
}

Dan akhirnya - atur ukuran yang diinginkan dalam - (void)viewDidAppear:(BOOL)animatedmetode:

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

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

8

Anda perlu mengatur kembali ukuran konten viewWillAppear. Dengan memanggil metode delagate di mana Anda menyetel ukuran popovercontroller. Saya juga memiliki masalah yang sama. Tetapi ketika saya menambahkan ini, masalah terpecahkan.

Satu hal lagi: jika Anda menggunakan versi beta kurang dari 5. Maka popovers lebih sulit untuk dikelola. Mereka tampaknya lebih ramah dari versi beta 5. Ada baiknya versi final sudah keluar. ;)

Semoga ini membantu.


Aku juga benci ini. Itu menangkap saya juga. Apple: Mengapa kita tidak bisa mengunci popover dengan navcontroller ke ukuran yang ditentukan ?!
Jann

2
Menyetel ukuran konten viewWillAppeartidak berhasil untuk saya. Mengatur ukuran popover secara eksplisit berhasil, tapi itu ghetto.
Ben Zotto

@quixoto Saya tidak tahu apa masalah Anda, tetapi saya masih menggunakan hal yang sama dan berfungsi dengan sempurna.
Madhup Singh Yadav

5

Di -(void)viewDidLoaddari semua pengontrol tampilan yang Anda gunakan di pengontrol navigasi, tambahkan:

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

3

Saya mengatur ulang ukuran dalam metode animasi viewWillDisappear: (BOOL) dari pengontrol tampilan yang sedang dinavigasi kembali dari:

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

Kemudian saat tampilan yang dinavigasi kembali muncul, saya mengatur ulang ukurannya dengan tepat:

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

Hmm .. reset tidak diperlukan. Saya meletakkan self.contentSizeForViewInPopover = self.view.frame.size di semua viewWillAppear dari semua pengontrol tampilan.
Sendirian

Apa yang akan saya masukkan untuk fetchedResultsController fetchedObjects? Tidak bisa membuat ini bekerja
Jules

2

Untuk iOS 8, pekerjaan berikut ini:

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

BTW saya pikir, ini harus kompatibel dengan versi iOS sebelumnya ...


Saya memiliki masalah dengan aplikasi di iOS8 yang dikompilasi dengan iOS7 sdk. Ini berhasil, terima kasih.
Mendaki

Untuk memperbaiki ukuran saat mengubah rotasi, panggil metode ini di willTransitionToTraitCollection, di animateAlongsideTransitionblok penyelesaian.
Geva

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

Bagi saya solusi ini berhasil. Ini adalah metode dari pengontrol tampilan saya yang memperluas UITableViewController dan merupakan pengontrol root untuk UINavigationController.

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

Dan jangan lupa untuk mengatur ukuran konten untuk pengontrol tampilan yang akan Anda dorong ke tumpukan navigasi

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

jika Anda bisa membayangkan assambler, saya pikir ini sedikit lebih baik:

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

2
bahkan lebih baik akan menggunakan CGSizeZerodaripada membuatnya sendiri diCGSizeMake(0,0)
Julian Król

1

The jawaban yang diterima tidak bekerja dengan baik dengan iOS 8. Apa yang saya lakukan adalah menciptakan subclass saya sendiri UINavigationControlleruntuk digunakan dalam popover itu dan menimpa metode preferredContentSizedengan cara ini:

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

Selain itu, alih-alih memanggil forcePopoverSize(metode yang diterapkan oleh @krasnyk) di viewDidAppearsaya memutuskan untuk mengatur viewController (yang menampilkan popover) sebagai delegasi untuk navigasi yang disebutkan sebelumnya (dalam popover) dan melakukan (metode gaya apa) di:

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

mendelegasikan metode untuk lulus viewController. Satu hal penting, melakukan forcePopoverSizedalam suatu UINavigationControllerDelegatemetode baik-baik saja jika Anda tidak membutuhkan animasi yang mulus jika demikian, biarkan saja viewDidAppear.


kenapa tidak memilih? mungkin beberapa umpan balik berbeda dari hanya perselisihan :)
Julian Król

halo @ JulianKról, dapatkah Anda melihat stackoverflow.com/questions/28112617/… ini , saya memiliki masalah yang sama.
Ranjit

Terima kasih, ini membantu saya. Mungkin ingin memperjelas di bagian atas komentar Anda bahwa masalahnya adalah Anda perlu memperbarui navigationController preferContentSize serta visibleVC preferenceContentSize. Jadi pengaturan keduanya langsung berfungsi juga.
Michael Kernahan

0

Saya menghadapi masalah yang sama, tetapi Anda tidak ingin menyetel ukuran konten dalam metode viewWillAppear atau viewWillDisappear.

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];

setel properti contentSizeForViewInPopover untuk pengontrol itu sebelum mendorong pengontrol itu ke navigationController


0

Saya beruntung dengan meletakkan yang berikut ini di viewdidappear:

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

Meskipun ini mungkin tidak dianimasikan dengan baik jika Anda mendorong / memunculkan popovers dengan ukuran berbeda. Tapi dalam kasus saya, bekerja dengan sempurna!


0

Yang harus Anda lakukan adalah:

-Dalam metode viewWillAppear dari popOvers contentView, tambahkan cuplikan yang diberikan di bawah ini. Anda harus menentukan ukuran popOver pertama kali saat dimuat.

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

0

Saya mengalami masalah ini dengan pengontrol popover yang popoverContentSize = CGSizeMake (320, 600) di awal, tetapi akan menjadi lebih besar saat menavigasi melalui ContentViewController (sebuah UINavigationController).

Pengontrol nav hanya mendorong dan memunculkan UITableViewControllers kustom, jadi dalam viewDidLoad kelas pengontrol tampilan tabel kustom saya, saya mengatur self.contentSizeForViewInPopover = CGSizeMake (320, 556)

44 piksel lebih sedikit diperhitungkan untuk bilah navigasi pengontrol Nav, dan sekarang saya tidak memiliki masalah lagi.


0

Letakkan ini di semua pengontrol tampilan yang Anda dorong di dalam popover

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

dalam metode viewwillAppear. dan currentSetSizeForPopover mengatur ukuran yang Anda inginkan.
alok

0

Menghadapi masalah yang sama dan memperbaikinya dengan mengatur ukuran tampilan konten ke pengontrol navigasi dan pengontrol tampilan sebelum init dari UIPopoverController ditempatkan.

     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

Saya hanya ingin menawarkan solusi lain, karena tidak ada yang berhasil untuk saya ...

Saya sebenarnya menggunakannya dengan https://github.com/nicolaschengdev/WYPopoverController ini

Saat Anda pertama kali memanggil popup Anda, gunakan ini.

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

Kemudian di popup itu gunakan ini.

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

}

Kemudian ulangi untuk tampilan anak ...


0

Ini adalah cara yang benar di iOS7 untuk melakukan ini, Setel ukuran konten yang disukai di viewDidLoad di setiap pengontrol tampilan di tumpukan navigasi (hanya dilakukan sekali). Kemudian di viewWillAppear dapatkan referensi ke pengontrol popover dan perbarui contentSize di sana.

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

Solusi @krasnyk bekerja dengan baik di versi iOS sebelumnya tetapi tidak berfungsi di iOS8. Solusi berikut berhasil untuk saya.

    - (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];
        }
    }

Ini bukan solusi terbaik, tetapi berhasil.

UIPopoverPresentationController baru juga memiliki masalah pengubahan ukuran :(.


1
mungkin alih-alih mencapai pengontrol tampilan dari properti AppDelegate pertimbangkan solusi saya (tampaknya lebih bersih)
Julian Król

Ya, ini adalah solusi tercepat tanpa mengubah basis kode saya yang ada. Btw vl coba solusimu
Clement Prem

0

Anda perlu menyetel preferredContentSizeproperti NavigationController di viewWillAppear:

-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.navigationController.preferredContentSize = CGSizeMake(320, 500);}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.