Cara menampilkan popover dengan benar di iOS 8


118

Saya mencoba menambahkan UIPopoverView ke aplikasi Swift iOS 8 saya, tetapi saya tidak dapat mengakses properti PopoverContentSize, karena popover tidak muncul dalam bentuk yang benar. kode saya:

var popover: UIPopoverController? = nil 

    func addCategory() {

    var newCategory = storyboard.instantiateViewControllerWithIdentifier("NewCategory") as UIViewController
    var nav = UINavigationController(rootViewController: newCategory)
    popover = UIPopoverController(contentViewController: nav)
    popover!.setPopoverContentSize(CGSizeMake(550, 600), animated: true)
    popover!.delegate = self
    popover!.presentPopoverFromBarButtonItem(self.navigationItem.rightBarButtonItem, permittedArrowDirections: UIPopoverArrowDirection.Any, animated: true)
}

keluaran:

masukkan deskripsi gambar di sini

Ketika saya melakukan hal yang sama melalui UIPopoverPresentationController, saya masih belum menyelesaikannya. ini kode saya:

func addCategory() {

    var popoverContent = self.storyboard.instantiateViewControllerWithIdentifier("NewCategory") as UIViewController
    var nav = UINavigationController(rootViewController: popoverContent)
    nav.modalPresentationStyle = UIModalPresentationStyle.Popover
    var popover = nav.popoverPresentationController as UIPopoverPresentationController
    popover.delegate = self
    popover.popoverContentSize = CGSizeMake(1000, 300)
    popover.sourceView = self.view
    popover.sourceRect = CGRectMake(100,100,0,0)

    self.presentViewController(nav, animated: true, completion: nil)

}

Saya mendapatkan hasil yang sama persis.

Bagaimana cara menyesuaikan ukuran popover saya? Bantuan apa pun akan sangat dihargai!


Ada video WWDC di situs pengembang yang disebut "A Look Inside Presentation Controllers". Ini menjelaskan cara menggunakan UIPopoverPresentationController
Wextux

Saya telah mengedit pertanyaan saya sesuai dengan video apel mengenai pengontrol-overpresentation UI, tetapi tidak ada yang berubah! apakah Anda mungkin melihat sesuatu yang harus saya ubah tentang ini? Terima kasih atas masukannya!
Joris416

Jawaban:


148

Oke, teman serumah melihatnya dan menemukan jawabannya:

 func addCategory() {

    var popoverContent = self.storyboard?.instantiateViewControllerWithIdentifier("NewCategory") as UIViewController
    var nav = UINavigationController(rootViewController: popoverContent)
    nav.modalPresentationStyle = UIModalPresentationStyle.Popover
    var popover = nav.popoverPresentationController
    popoverContent.preferredContentSize = CGSizeMake(500,600)
    popover.delegate = self
    popover.sourceView = self.view
    popover.sourceRect = CGRectMake(100,100,0,0)

    self.presentViewController(nav, animated: true, completion: nil)

}

Itu caranya.

Anda tidak lagi berbicara dengan popover itu sendiri, Anda berbicara dengan pengontrol tampilan di dalamnya untuk menyetel ukuran konten, dengan memanggil properti preferredContentSize


15
Mungkin menyatakan yang sudah jelas, tetapi ini tidak hanya terkait dengan cepat. Saya juga harus melakukan ini di aplikasi obj-c saya :)
Kevin R

4
Komentar lain pada kode - Anda dapat menggunakan "let" daripada "var". Apple merekomendasikannya untuk kasus di mana Anda tidak perlu menetapkan ulang nilainya.
EPage_Ed

3
Ini disadap di GM untuk iPhone. Jika Anda mencoba menyajikan saat simulator dalam mode potret, itu selalu dalam layar penuh. Jika Anda memutar ke lanskap, itu menjadi popover. Jika Anda memutar kembali ke potret, itu tetap popover.
jjxtra

1
Solusinya adalah menyiapkan popover SEBELUM memanggil presentViewController. Ini adalah kebalikan dari contoh Apple di mana mereka secara eksplisit memberitahu Anda untuk mengatur popover SETELAH memanggil presentViewController.
jjxtra

1
@PsychoDad dapatkah kamu memberikan tautan ke solusi yang kamu sebutkan. Saya masih terjebak pada "saat simulator dalam mode potret, selalu layar penuh". Terima kasih
Nishant

53

Sebenarnya jauh lebih sederhana dari itu. Di storyboard, Anda harus membuat viewcontroller yang ingin digunakan sebagai popover dan membuat kelas viewcontroller seperti biasa. Buat segue seperti yang ditunjukkan di bawah ini dari objek yang ingin Anda buka popovernya, dalam hal ini UIBarButtonbernama "Config".

masukkan deskripsi gambar di sini

Dalam "ibu viewcontroller", implementasikan metode UIPopoverPresentationControllerDelegatedan delegasi:

func popoverPresentationControllerDidDismissPopover(popoverPresentationController: UIPopoverPresentationController) {
    //do som stuff from the popover
}

Ganti prepareForSequemetode seperti ini:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
     //segue for the popover configuration window
    if segue.identifier == "yourSegueIdentifierForPopOver" {
        if let controller = segue.destinationViewController as? UIViewController {
            controller.popoverPresentationController!.delegate = self
            controller.preferredContentSize = CGSize(width: 320, height: 186)
        }
    }
}

Dan Anda sudah selesai. Dan sekarang Anda dapat memperlakukan tampilan popover seperti tampilan lainnya, yaitu. tambahkan bidang dan apa yang tidak! Dan Anda mendapatkan pengontrol konten dengan menggunakan popoverPresentationController.presentedViewControllermetode di UIPopoverPresentationController.

Juga di iPhone Anda harus menimpa

func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {

        return UIModalPresentationStyle.none
    } 

28

Saya menemukan contoh lengkap bagaimana membuat ini semua bekerja sehingga Anda selalu dapat menampilkan popover tidak peduli perangkat / orientasi https://github.com/frogcjn/AdaptivePopover_iOS8_Swift .

Kuncinya adalah mengimplementasikan UIAdaptivePresentationControllerDelegate

func adaptivePresentationStyleForPresentationController(PC: UIPresentationController!) -> UIModalPresentationStyle {
    // This *forces* a popover to be displayed on the iPhone
    return .None
}

Kemudian perluas contoh di atas (dari Imagine Digital):

nav.popoverPresentationController!.delegate = implOfUIAPCDelegate

Saya menggunakan UIPopoverPresentationControllerDelegate
onmyway133

3
Benar, UIPopoverPresentationControllerDelegate memperluas UIAdaptivePresentationControllerDelegate. Jadi, menurut definisi, keduanya berisi metode 'adaptivePresentationStyleForPresentationController'. Saya menyediakan antarmuka dasar karena metode ini didokumentasikan dalam dokumen API Apple.
David Hunt

1
Perhatikan bahwa ini adalah perilaku yang tidak terdokumentasi. Doc mengatakan metode delegasi ini harus mengembalikan "salah satu UIModalPresentationFullScreenatau UIModalPresentationOverFullScreen". Lebih lanjut, "Jika Anda tidak mengimplementasikan metode ini atau mengembalikan gaya apa pun selain UIModalPresentationFullScreenatau UIModalPresentationOverFullScreen, pengontrol presentasi menyesuaikan gaya presentasi ke UIModalPresentationFullScreengaya."
Tom

1
Dokumentasi saat ini menyarankan bahwa mulai iOS 8.3 dan seterusnya Anda harus menggunakan - adaptivePresentationStyleForPresentationController: traitCollection: dan gaya yang dikembalikan harus "UIModalPresentationFullScreen, UIModalPresentationOverFullScreen, UIModalPresentationFormSheet, atau UIModalPresentationNone."
Dale

25

Swift 2.0

Yah, aku berhasil. Coba lihat. Membuat ViewController di StoryBoard. Terkait dengan kelas PopOverViewController.

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

Lihat ViewController:

//  ViewController.swift

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

Catatan: Metode func showPopover (base: UIView) harus ditempatkan sebelum ViewDidLoad. Semoga membantu!


hai @Alvin, saya akan memunculkan tampilan dari anotasi peta. jadi saya melakukan hal yang sama seperti Anda. perbedaannya adalah bahwa saya akan mengisi tableviewcontroller daripada view. Sekarang masalahnya bukan mengenai metode delegasi. "PopoverPresentationControllerDidDismissPopover". ketika saya menutup pengontrol. Bisakah kamu menolong ? (pertanyaan tidak terkait dengan pos)
Subin K Kuriakose

1
Mengapa showPopover(base: UIView)metode harus ditempatkan sebelumnya viewDidLoad()?
Eimantas

15

Di iOS9, UIPopoverController disusutkan. Jadi dapat menggunakan kode di bawah ini untuk versi Objective-C di atas iOS9.x,

- (IBAction)onclickPopover:(id)sender {
UIStoryboard *sb = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
UIViewController *viewController = [sb instantiateViewControllerWithIdentifier:@"popover"];

viewController.modalPresentationStyle = UIModalPresentationPopover;
viewController.popoverPresentationController.sourceView = self.popOverBtn;
viewController.popoverPresentationController.sourceRect = self.popOverBtn.bounds;
viewController.popoverPresentationController.permittedArrowDirections = UIPopoverArrowDirectionAny;
[self presentViewController:viewController animated:YES completion:nil]; }

Pertanyaan tersebut secara khusus menanyakan Swift, bukan Objective-C.
Eric Aya

8

Di sini saya Mengonversi Kode Swift "Joris416" ke Objective-c,

-(void) popoverstart
{
    ViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:@"PopoverView"];
    UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:controller];
    nav.modalPresentationStyle = UIModalPresentationPopover;
    UIPopoverPresentationController *popover = nav.popoverPresentationController;
    controller.preferredContentSize = CGSizeMake(300, 200);
    popover.delegate = self;
    popover.sourceView = self.view;
    popover.sourceRect = CGRectMake(100, 100, 0, 0);
    popover.permittedArrowDirections = UIPopoverArrowDirectionAny;
    [self presentViewController:nav animated:YES completion:nil];
}

-(UIModalPresentationStyle) adaptivePresentationStyleForPresentationController: (UIPresentationController * ) controller
{
    return UIModalPresentationNone;
}

Ingatlah untuk MENAMBAHKAN
UIPopoverPresentationControllerDelegate, UIAdaptivePresentationControllerDelegate


Pertanyaan tersebut secara khusus menanyakan Swift, bukan Objective-C.
Eric Aya

4

Ini paling baik dijelaskan di blog iOS8 Day-by-Day

Singkatnya, setelah Anda menyetel modalPresentationStyle UIViewController ke .Popover, Anda bisa mendapatkan UIPopoverPresentationClass (kelas iOS8 baru) melalui properti popoverPresentationController pengontrol.


3

Saya membuat jawaban cepat versi Objective-C dari Imagine Digitals di atas. Saya rasa saya tidak melewatkan apa pun karena tampaknya berfungsi dalam pengujian awal, jika Anda melihat sesuatu, beri tahu saya, dan saya akan memperbaruinya

-(void) presentPopover
{
    YourViewController* popoverContent = [[YourViewController alloc] init]; //this will be a subclass of UIViewController
    UINavigationController* nav =  [[UINavigationController alloc] initWithRootViewController:popoverContent];
    nav.modalPresentationStyle = UIModalPresentationPopover;
    UIPopoverPresentationController* popover = nav.popoverPresentationController;
    popoverContent.preferredContentSize = CGSizeMake(500,600);
    popover.delegate = self;
    popover.sourceRect = CGRectMake(100,100,0,0); //I actually used popover.barButtonItem = self.myBarButton;

    [self presentViewController:nav animated:YES completion:nil];
}

Saya pikir Anda tertinggal popover.sourceView = self.view;
ghr

Pertanyaan tersebut secara khusus menanyakan Swift, bukan Objective-C.
Eric Aya

4
Saya menyadarinya, tetapi google membawa Anda ke sini bahkan jika Anda mencari tujuan-C. Begitulah cara saya berakhir di sini.
narco

3

dua sen saya untuk xcode 9.1 / swift 4.

class ViewController: UIViewController, UIPopoverPresentationControllerDelegate {

    override func viewDidLoad(){
        super.viewDidLoad()

        let when = DispatchTime.now() + 0.5

        DispatchQueue.main.asyncAfter(deadline: when, execute: { () -> Void in
            // to test after 05.secs... :)
            self.showPopover(base: self.view)

        })

}


func showPopover(base: UIView) {
    if let viewController = self.storyboard?.instantiateViewController(withIdentifier: "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.present(navController, animated: true, completion: nil)
        }
    }
}


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

func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle{
    return .none
}

dan bereksperimen dalam:

func adaptivePresentationStyle ...

    return .popover

atau: return .pageSheet .... dan seterusnya ..


2

Implementasikan UIAdaptivePresentationControllerDelegate di Viewcontroller Anda. Kemudian tambahkan:

func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle{
    return .none
}

1

Berikut ini adalah panduan yang cukup lengkap tentang cara mengkonfigurasi dan menampilkan popovers. https://www.appcoda.com/presentation-controllers-tutorial/

Singkatnya, implementasi yang layak (dengan beberapa pembaruan dari sintaks artikel asli untuk Swift 4.2 ), untuk kemudian dipanggil dari tempat lain, akan menjadi seperti berikut:

func showPopover(ofViewController popoverViewController: UIViewController, originView: UIView) {
    popoverViewController.modalPresentationStyle = UIModalPresentationStyle.popover
    if let popoverController = popoverViewController.popoverPresentationController {
        popoverController.delegate = self
        popoverController.sourceView = originView
        popoverController.sourceRect = originView.bounds
        popoverController.permittedArrowDirections = UIPopoverArrowDirection.any
    }
    self.present(popoverViewController, animated: true)
}

Banyak dari hal ini sudah tercakup dalam jawaban dari @mmc, tetapi artikel ini membantu menjelaskan beberapa elemen kode yang digunakan, dan juga menunjukkan bagaimana kode dapat diperluas.

Ini juga memberikan banyak detail tambahan tentang penggunaan delegasi untuk menangani gaya presentasi untuk iPhone vs. iPad, dan untuk memungkinkan penutupan popover jika ditampilkan dalam layar penuh. Sekali lagi, diperbarui untuk Swift 4.2 :

func adaptivePresentationStyle(for: UIPresentationController) -> UIModalPresentationStyle {
    //return UIModalPresentationStyle.fullScreen
    return UIModalPresentationStyle.none
}

func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
    if traitCollection.horizontalSizeClass == .compact {
        return UIModalPresentationStyle.none
        //return UIModalPresentationStyle.fullScreen
    }
    //return UIModalPresentationStyle.fullScreen
    return UIModalPresentationStyle.none
}

func presentationController(_ controller: UIPresentationController, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController? {
    switch style {
    case .fullScreen:
        let navigationController = UINavigationController(rootViewController: controller.presentedViewController)
        let doneButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.done, target: self, action: #selector(doneWithPopover))
        navigationController.topViewController?.navigationItem.rightBarButtonItem = doneButton
        return navigationController
    default:
        return controller.presentedViewController
    }
}

// As of Swift 4, functions used in selectors must be declared as @objc
@objc private func doneWithPopover() {
    self.dismiss(animated: true, completion: nil)
}

Semoga ini membantu.


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.