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!

Joris416
sumber
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

Joris416
sumber
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
    } 
pengguna1700737
sumber
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
David Hunt
sumber
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!

AG
sumber
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]; }
Vijay
sumber
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

pengguna2941395
sumber
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.

Clafou
sumber
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];
}
narco
sumber
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 ..

ingconti
sumber
2

Implementasikan UIAdaptivePresentationControllerDelegate di Viewcontroller Anda. Kemudian tambahkan:

func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle{
    return .none
}
Nyakiba
sumber
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.

TheNeil
sumber
0

Bagi yang ingin belajar!

Saya membuat proyek Open Source untuk mereka yang ingin belajar dan menggunakan tampilan Popover untuk tujuan lain. Anda dapat menemukan proyeknya di sini. https://github.com/tryWabbit/KTListPopup

KTListNewResize

tryKuldeepTanwar
sumber