วิธีการนำเสนอป๊อปโอเวอร์อย่างถูกต้องใน iOS 8


118

ฉันกำลังพยายามเพิ่ม UIPopoverView ในแอป Swift iOS 8 แต่ฉันไม่สามารถเข้าถึงคุณสมบัติ PopoverContentSize ได้เนื่องจากป๊อปโอเวอร์ไม่แสดงในรูปทรงที่ถูกต้อง รหัสของฉัน:

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

เอาท์พุท:

ใส่คำอธิบายภาพที่นี่

เมื่อฉันทำสิ่งเดียวกันผ่าน UIPopoverPresentationController ฉันก็ยังทำไม่เสร็จ นี่คือรหัสของฉัน:

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)

}

ฉันได้ผลลัพธ์เดียวกันแน่นอน

ฉันจะปรับแต่งขนาดของป๊อปโอเวอร์ได้อย่างไร ความช่วยเหลือใด ๆ จะได้รับการชื่นชมอย่างมาก!


มีวิดีโอ WWDC ในไซต์ของนักพัฒนาที่เรียกว่า "A Look Inside Presentation Controllers" ซึ่งจะอธิบายวิธีใช้ UIPopoverPresentationController
Wextux

ฉันได้แก้ไขคำถามของฉันตามวิดีโอของ Apple เกี่ยวกับ UIpopoverpresentationctontroller แต่ไม่มีอะไรเปลี่ยนแปลง! คุณอาจเห็นอะไรที่ฉันควรเปลี่ยนแปลงเกี่ยวกับเรื่องนี้หรือไม่? ขอบคุณสำหรับข้อมูล!
จอริส 416

คำตอบ:


148

เอาล่ะเพื่อนร่วมบ้านมาดูและคิดออก:

 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)

}

นั่นคือวิธี

คุณไม่ได้พูดคุยกับ popover อีกต่อไปคุณคุยกับตัวควบคุมมุมมองที่อยู่ภายในเพื่อกำหนดขนาดเนื้อหาโดยเรียกคุณสมบัติ preferredContentSize


15
อาจระบุได้ชัดเจน แต่สิ่งนี้ไม่ได้เกี่ยวข้องกับความรวดเร็ว ฉันต้องทำสิ่งนี้ในแอป obj-c ของฉันด้วย :)
Kevin R

4
ความคิดเห็นอื่นเกี่ยวกับรหัส - คุณสามารถใช้ "let" แทน "var" ได้ Apple ขอแนะนำสำหรับกรณีที่คุณไม่จำเป็นต้องกำหนดค่าใหม่
EPage_Ed

3
นี่คือบั๊กใน GM สำหรับ iPhone หากคุณพยายามนำเสนอในขณะที่เครื่องจำลองอยู่ในแนวตั้งเครื่องจำลองจะเต็มหน้าจอเสมอ ถ้าคุณหมุนเป็นแนวนอนมันจะกลายเป็นป๊อปโอเวอร์ หากคุณหมุนกลับไปที่แนวตั้งอีกครั้งมันจะยังคงเป็นป๊อปโอเวอร์
jjxtra

1
วิธีแก้ปัญหาคือการตั้งค่าป็อปโอเวอร์ก่อนที่จะเรียกใช้ presentViewController นี่เป็นสิ่งที่ตรงกันข้ามกับตัวอย่างของ Apple ที่พวกเขาบอกอย่างชัดเจนให้คุณตั้งค่าป๊อปโอเวอร์หลังจากเรียกใช้ presentViewController
jjxtra

1
@PsychoDad ได้โปรดให้ลิงค์ไปยังโซลูชันนี้ที่คุณกล่าวถึง ฉันยังคงติดอยู่ที่ "ในขณะที่เครื่องจำลองอยู่ในแนวตั้งมันจะเต็มหน้าจอเสมอ" ขอบคุณ
Nishant

53

จริงๆแล้วมันง่ายกว่านั้นมาก ในสตอรีบอร์ดคุณควรสร้างวิวคอนโทรลเลอร์ที่คุณต้องการใช้เป็นป็อปโอเวอร์และสร้างคลาสวิวคอนโทรลเลอร์สำหรับมันตามปกติ ทำการต่อตามที่แสดงด้านล่างจากออบเจ็กต์ที่คุณต้องการเปิดป็อปโอเวอร์ในกรณีนี้UIBarButtonชื่อ "Config"

ใส่คำอธิบายภาพที่นี่

ใน "mother viewcontroller" ให้ใช้UIPopoverPresentationControllerDelegateและ delegate method:

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

แทนที่prepareForSequeวิธีการดังนี้:

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

และคุณทำเสร็จแล้ว และตอนนี้คุณสามารถใช้มุมมองป็อปโอเวอร์เป็นมุมมองอื่น ๆ ได้เช่น เพิ่มช่องและอะไรไม่! และคุณได้รับตัวควบคุมเนื้อหาโดยใช้popoverPresentationController.presentedViewControllerวิธีการในไฟล์UIPopoverPresentationController.

นอกจากนี้บน iPhone คุณจะต้องเขียนทับ

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

        return UIModalPresentationStyle.none
    } 

28

ผมพบว่าเป็นตัวอย่างที่สมบูรณ์แบบของวิธีการที่จะได้รับนี้ทั้งหมดในการทำงานเพื่อให้คุณสามารถเสมอแสดง popover ไม่ว่าอุปกรณ์ / ปฐมนิเทศhttps://github.com/frogcjn/AdaptivePopover_iOS8_Swift

กุญแจสำคัญคือการนำ UIAdaptivePresentationControllerDelegate ไปใช้

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

จากนั้นขยายตัวอย่างด้านบน (จาก Imagine Digital):

nav.popoverPresentationController!.delegate = implOfUIAPCDelegate

ฉันใช้ UIPopoverPresentationControllerDelegate
onmyway133

3
ถูกต้อง UIPopoverPresentationControllerDelegate ขยาย UIAdaptivePresentationControllerDelegate ดังนั้นตามความหมายทั้งสองมีวิธีการ 'adaptivePresentationStyleForPresentationController' ฉันให้อินเทอร์เฟซพื้นฐานเนื่องจากเป็นที่ที่บันทึกวิธีการไว้ในเอกสาร API ของ Apple
David Hunt

1
โปรดสังเกตว่านี่เป็นพฤติกรรมที่ไม่มีเอกสาร เอกสารกล่าวว่าวิธีการของผู้รับมอบสิทธิ์นี้จะต้องกลับมา "อย่างใดอย่างหนึ่งUIModalPresentationFullScreenหรือUIModalPresentationOverFullScreen" นอกจากนี้ "หากคุณไม่ใช้วิธีนี้หรือส่งคืนรูปแบบอื่นใดที่ไม่ใช่UIModalPresentationFullScreenหรือUIModalPresentationOverFullScreenตัวควบคุมการนำเสนอจะปรับรูปแบบการนำเสนอให้เป็นUIModalPresentationFullScreenสไตล์นั้น"
ทอม

1
เอกสารปัจจุบันแนะนำว่าตั้งแต่ iOS 8.3 เป็นต้นไปคุณควรใช้ - adaptivePresentationStyleForPresentationController: traitCollection: และสไตล์ที่ส่งคืนนั้นต้องเป็น "UIModalPresentationFullScreen, UIModalPresentationOverFullScreen, UIModalPresentationFormSheet หรือ UIModalPresentationNone"
Dale

25

Swift 2.0

ฉันทำงานได้ดี ได้ดู. สร้าง ViewController ใน StoryBoard เชื่อมโยงกับคลาส 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)
    }
}      

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

หมายเหตุ: ควรวางเมธอด func showPopover (ฐาน: UIView) ไว้ก่อน ViewDidLoad หวังว่าจะช่วยได้!


สวัสดี @Alvin ฉันจะแสดงมุมมองจากคำอธิบายประกอบแผนที่ ฉันก็ทำเช่นเดียวกับที่คุณทำ ความแตกต่างคือกำลังจะเติม tableviewcontroller แทนมุมมอง ตอนนี้ปัญหาไม่ได้กดปุ่ม delegate method "popoverPresentationControllerDidDismissPopover" เมื่อฉันปิดตัวควบคุม คุณสามารถช่วย? (คำถามไม่เกี่ยวข้องกับโพสต์)
Subin K Kuriakose

1
ทำไมshowPopover(base: UIView)ต้องวางวิธีการไว้ก่อนviewDidLoad()?
Eimantas

15

ใน iOS9 UIPopoverController คิดค่าเสื่อมราคา ดังนั้นสามารถใช้โค้ดด้านล่างสำหรับ Objective-C เวอร์ชันเหนือ 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]; }

คำถามนี้ถามเฉพาะสำหรับ Swift ไม่ใช่สำหรับ Objective-C
Eric Aya

8

ที่นี่ฉันแปลง Swift Code "Joris416" เป็น 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;
}

อย่าลืมเพิ่ม
UIPopoverPresentationControllerDelegate, UIAdaptivePresentationControllerDelegate


คำถามนี้ถามเฉพาะสำหรับ Swift ไม่ใช่สำหรับ Objective-C
Eric Aya

4

สิ่งนี้อธิบายได้ดีที่สุดในบล็อก iOS8 แบบวันต่อวัน

ในระยะสั้นเมื่อคุณตั้งค่า modalPresentationStyle ของ UIViewController เป็น. Popover แล้วคุณจะได้รับ UIPopoverPresentationClass (คลาส iOS8 ใหม่) ผ่านคุณสมบัติ popoverPresentationController ของคอนโทรลเลอร์


3

ฉันสร้างคำตอบที่รวดเร็ว Imagine Digitals เวอร์ชัน Objective-C ข้างต้น ฉันไม่คิดว่าฉันพลาดอะไรเพราะดูเหมือนว่าจะทำงานภายใต้การทดสอบเบื้องต้นหากคุณพบบางสิ่งแจ้งให้เราทราบเราจะอัปเดตให้

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

ฉันคิดว่าคุณออกไปแล้ว popover.sourceView = self.view;
ghr

คำถามนี้ถามเฉพาะสำหรับ Swift ไม่ใช่สำหรับ Objective-C
Eric Aya

4
ฉันตระหนักดี แต่ google นำคุณมาที่นี่แม้ว่าคุณจะค้นหาวัตถุประสงค์ -C ก็ตาม นั่นคือสิ่งที่ฉันลงเอยที่นี่
narco

3

สองเซ็นต์ของฉันสำหรับ 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
}

และทดลองใน:

func adaptivePresentationStyle ...

    return .popover

หรือ: return. pageSheet .... และอื่น ๆ ..


2

ใช้ UIAdaptivePresentationControllerDelegate ใน Viewcontroller ของคุณ จากนั้นเพิ่ม:

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

1

ต่อไปนี้มีคำแนะนำที่ครอบคลุมเกี่ยวกับวิธีกำหนดค่าและนำเสนอป๊อปโอเวอร์ https://www.appcoda.com/presentation-controllers-tutorial/

โดยสรุปการใช้งานที่เป็นไปได้ (พร้อมการอัปเดตบางส่วนจากไวยากรณ์ของบทความต้นฉบับสำหรับSwift 4.2 ) ซึ่งจะถูกเรียกจากที่อื่นจะเป็นดังนี้:

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

มีคำตอบมากมายในคำตอบจาก @mmc อยู่แล้ว แต่บทความนี้ช่วยอธิบายองค์ประกอบโค้ดบางส่วนที่ใช้และยังแสดงให้เห็นว่ามันสามารถขยายได้อย่างไร

นอกจากนี้ยังให้รายละเอียดเพิ่มเติมมากมายเกี่ยวกับการใช้การมอบหมายเพื่อจัดการกับรูปแบบการนำเสนอสำหรับ iPhone กับ iPad และอนุญาตให้ยกเลิกการแสดงป๊อปอัปหากเคยแสดงแบบเต็มหน้าจอ อัปเดตอีกครั้งสำหรับ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)
}

หวังว่านี่จะช่วยได้


0

สำหรับคนที่อยากเรียน!

ฉันสร้างโครงการโอเพ่นซอร์สสำหรับผู้ที่ต้องการศึกษาและใช้มุมมองป็อปโอเวอร์เพื่อวัตถุประสงค์ใด ๆ คุณสามารถค้นหาโครงการได้ที่นี่ https://github.com/tryWabbit/KTListPopup

KTListNewResize

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.