UIPopoverPresentationController的詳解

簡介

UIPopoverPresentationController是用 iOS 8.0 后UIKit用來管理彈窗的對象旨巷,這個對象不用直接創(chuàng)建把沼,UIKit 會自動創(chuàng)建此類的實例,可以通過配置UIViewController的popoverPresentationController 屬性,來實現(xiàn)各種自定義的彈窗行為彈出窗口行為。

使用到的類和屬性介紹

open class UIPopoverPresentationController : UIPresentationController {
    //**************************************************************
   /*
        通過UIPopoverPresentationControllerDelegate 協(xié)議的方法可以自定義彈窗的行為。
    */
    weak open var delegate: UIPopoverPresentationControllerDelegate?
        //**************************************************************
    
    open var permittedArrowDirections: UIPopoverArrowDirection
    
    //************************通過下面三個屬性確定錨點的位置*************************
    /*
    將此屬性與 sourceRect 屬性結(jié)合使用來指定彈窗的錨點位置病线。 或者,也可以使用 barButtonItem 屬性指定彈出框的錨點位置。
    */
    open var sourceView: UIView?

    
    /*彈出框應該指向的sourceView坐標空間中的矩形送挑。 如果設(shè)置了 barButtonItem绑莺,則忽略此屬性。
     從 iOS 13.2 開始惕耕,CGRectNull 的值會導致 popover 指向 sourceView 的當前幀纺裁,并在 sourceView 的大小發(fā)生變化時自動更新。 在 iOS 13.2 之前司澎,不支    持空矩形欺缘。 iOS 13.2 中的默認值為 CGRectNull。 在 iOS 13.2 之前挤安,默認值為 CGRectZero谚殊。這就意味在iOS13.2之前想正確的顯示錨點的位置,必須設(shè)置sourceRect,在iOS13.2之后蛤铜,不用設(shè)置sourceRect嫩絮,只需設(shè)置sourceView也能顯示在正確的位置
     */
    open var sourceRect: CGRect
    /*
      設(shè)置點擊UIBarButtonItem 彈出窗口,彈出框的箭頭指向設(shè)置點擊UIBarButtonItem围肥。 或者絮记,您可以使用 sourceView 和 sourceRect 屬性指定彈出框的錨點位置。此屬性的默認值為 nil虐先。
     */
    open var barButtonItem: UIBarButtonItem?
    //*************************************************
  
    //*****************************修改彈窗樣式*********************************
    
    /*
     將此屬性設(shè)置為 true 允許彈出框在空間受限時與 sourceRect 屬性中的矩形重疊。 此屬性的默認值為 false派敷,可防止彈出框與源矩形重疊蛹批。
     這個屬性在彈窗中有鍵盤的時候非常有用,彈窗在鍵盤彈出的時候篮愉,如果被鍵盤遮住腐芍,如果這個屬性為false,則會縮小彈出的高度,彈窗中UI會變形试躏,如果設(shè)置為true猪勇,
     則彈窗會上移,而不會改變彈窗的高度
    */
    @available(iOS 9.0, *)
    open var canOverlapSourceViewRect: Bool
    
   /* 用戶可以在彈出窗口可見時與之交互的一組視圖颠蕴。
     當彈出框處于活動狀態(tài)時泣刹,與其他視圖的交互通常會被禁用,直到彈出框被解除犀被。
     將一組 UIView 對象分配給此屬性會導致 UIKit 繼續(xù)將觸摸事件分派到您指定的視圖椅您。
     passthroughViews的默認值是nil, 如果想和彈窗之外的某個view進行交會,可以將它添加進passthroughViews寡键,這樣交互的過程中彈窗也不會消失
    */
    open var passthroughViews: [UIView]?

    /* 
    設(shè)置彈出框背景顏色掀泳。 設(shè)置為 nil 以使用默認背景顏色。 
    這個值是修改 _UIVisualEffectContentView的顏色,而不是修改當UIPopoverPresentationController所在的viewController.view的背景色员舵,
    當UIPopoverPresentationController所在的viewController.view沒有設(shè)置backgroundColor的時候能顯示出來脑沿,
    若viewController.view設(shè)置了backgroundColor就會被遮住,顯示設(shè)置的背景色
    */
    @NSCopying open var backgroundColor: UIColor?

    
    /*
     控制彈窗相對于屏幕的邊距 默認邊插入是沿每條邊 10 個點马僻。 在確定顯示彈出框的位置時庄拇,彈窗會自動從區(qū)域中減去狀態(tài)欄,因此無需將狀態(tài)欄高度計入插圖巫玻。
    */
    open var popoverLayoutMargins: UIEdgeInsets
  
     /*
      修改彈窗的樣式丛忆,如陰影,箭頭高度等 默認是nil
     */
     open var popoverBackgroundViewClass: UIPopoverBackgroundViewMethods.Type?
   //**************************************************************
   /*
     在顯示彈出窗口之前仍秤,將此屬性設(shè)置為允許彈出窗口的箭頭方向熄诡。 彈出窗口使用的實際箭頭方向存儲在 arrowDirection 屬性中。
     此屬性的默認值為 any诗力。
    */
    open var arrowDirection: UIPopoverArrowDirection { get }
}

public protocol UIPopoverPresentationControllerDelegate : UIAdaptivePresentationControllerDelegate {

    /* 即將呈現(xiàn)彈出窗口凰浮。
       使用此方法可以對彈出窗口的外觀和行為進行最后次自定義。
       在調(diào)用此方法時苇本,彈出窗口尚未出現(xiàn)在屏幕上袜茧。 您可以使用此方法修改 popover 呈現(xiàn)控制器的配置或執(zhí)行您的應用程序所需的任何其他操作。
     */
    @available(iOS 8.0, *)
    optional func prepareForPopoverPresentation(_ popoverPresentationController: UIPopoverPresentationController)

    
    /*
      是否應該解除彈出框瓣窄。(iOS 8.0 - iOS 13.0)
     */
    @available(iOS, introduced: 8.0, deprecated: 13.0)
    optional func popoverPresentationControllerShouldDismissPopover(_ popoverPresentationController: UIPopoverPresentationController) -> Bool

    
    //彈窗已經(jīng)Dismiss
    @available(iOS, introduced: 8.0, deprecated: 13.0)
    optional func popoverPresentationControllerDidDismissPopover(_ popoverPresentationController: UIPopoverPresentationController)


    /*需要重新定位彈出框的位置笛厦。
     彈出框表示控制器調(diào)用此方法以響應需要新的彈出框大小的界面更改。 
     例如俺夕,當必須調(diào)整彈出框的大小以為鍵盤騰出空間時裳凸,UIKit 會調(diào)用此方法。 您可以使用此方法獲取彈出框的新大小劝贸,并可選擇更改建議的視圖和矩形姨谷。
     如果你沒有在你的委托中實現(xiàn)這個方法,UIKit 會將彈出框的大小調(diào)整為指定的矩形并將它(根據(jù)需要)移動到指定的視圖映九。
     popoverPresentationController:管理彈出框界面的彈出框展示控制器梦湘。
     rect:在輸入時,彈出框的新矩形件甥。 這個 popover 在 view 參數(shù)中的視圖坐標空間中捌议。 如果要為彈出框建議不同的矩形,請將新值放入此參數(shù)中嚼蚀。
     view: 在輸入時禁灼,包含彈出框的新視圖。 如果你想為 popover 建議一個不同的視圖轿曙,把那個視圖放在這個參數(shù)中
    */
    @available(iOS 8.0, *)
    optional func popoverPresentationController(_ popoverPresentationController: UIPopoverPresentationController, willRepositionPopoverTo rect: UnsafeMutablePointer<CGRect>, in view: AutoreleasingUnsafeMutablePointer<UIView>)
}

//這里插入一個知識點:從A控制器通過present的方式跳轉(zhuǎn)到了B控制器弄捕,那么 A.presentedViewController 就是B控制器僻孝;B.presentingViewController 就是A控制器

public protocol UIAdaptivePresentationControllerDelegate : NSObjectProtocol {

    /*
    只支持 UIModalPresentationFullScreen 和 UIModalPresentationOverFullScreen
    在iOS 8.3 及更高版本中,使用adaptivePresentationStyle(for:traitCollection:) 方法而不是此方法來處理所有特征更改守谓。 如果您不實現(xiàn)該方法穿铆,則可以使用該方法在轉(zhuǎn)換到水平緊湊環(huán)境時更改演示樣式。
如果你沒有實現(xiàn)這個方法或者如果你返回一個無效的樣式斋荞,當前的呈現(xiàn)控制器返回它的首選默認樣式荞雏。
    */
    @available(iOS 8.0, *)
    optional func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle

   /*  返回 UIModalPresentationNone 將表明適配不應該發(fā)生。
   當當前環(huán)境的特征即將改變時平酿,表示控制器調(diào)用此方法凤优。 此方法的實現(xiàn)可以返回用于指定特征的首選呈現(xiàn)樣式。
   如果您不返回允許的樣式之一蜈彼,則表示控制器將使用其首選的默認樣式筑辨。如果你沒有在你的委托中實現(xiàn)這個方法,UIKit 會調(diào)用adaptivePresentationStyle(for:) 方法幸逆。   如果想present為彈窗樣式必須設(shè)置為 UIModalPresentationNone
    */
    @available(iOS 8.3, *)
    optional func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle

   /*
    當size class更改導致底層呈現(xiàn)樣式發(fā)生更改時棍辕,呈現(xiàn)控制器調(diào)用此方法以請求視圖控制器以該新樣式顯示。 這種方法是您將當前視圖控制器替換為更適合新呈現(xiàn)樣式的視圖控制器的機會还绘。 例如楚昭,您可以使用此方法將導航控制器插入到您的視圖層次結(jié)構(gòu)中,以便在緊湊的環(huán)境中更輕松地推送新的視圖控制器拍顷。 在這種情況下抚太,您將返回一個導航控制器,其根視圖控制器是當前呈現(xiàn)的視圖控制器昔案。 如果您愿意凭舶,您也可以返回一個完全不同的視圖控制器。
如果你沒有實現(xiàn)這個方法或者你的實現(xiàn)返回 nil爱沟,則呈現(xiàn)控制器使用它現(xiàn)有的presentedViewController。
    */
    @available(iOS 8.0, *)
    optional func presentationController(_ controller: UIPresentationController, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController?

    /*
      如果適配沒有發(fā)生并使用了original style匆背,則 UIModalPresentationNone 將作為參數(shù)傳遞呼伸。
      當 size class 發(fā)生變化時,UIKit 會調(diào)用此方法來讓您知道presentation controller將如何適應钝尸。 使用此方法進行任何其他更改括享。 
    例如,您可以使用過渡協(xié)調(diào)器對象為過渡創(chuàng)建附加動畫珍促。
    */
    @available(iOS 8.3, *)
    optional func presentationController(_ presentationController: UIPresentationController, willPresentWithAdaptiveStyle style: UIModalPresentationStyle, transitionCoordinator: UIViewControllerTransitionCoordinator?)

    
  /*
    是否可以Dismiss
    如果是使用 presentedViewController isModalInPresentation 為true的時候(isModalInPresentation = true 則不允許直接下拉dismiss,這是iOS 13后铃辖,present VC后的默認樣式) 和調(diào)用 dismissf方法,這個方法是不會調(diào)用的
    返回NO防止dismiss VC
  
  系統(tǒng)可以隨時調(diào)用該方法猪叙。 不保證此方法后會調(diào)用presentationControllerWillDismiss(_:) 或presentationControllerDidDismiss(_:)娇斩。 確保您對該方法的實現(xiàn)快速返回仁卷。
  */
    @available(iOS 13.0, *)
    optional func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool

  /*
   您可以使用此方法通過presentationController 的transitionCoordinator 設(shè)置動畫或交互通知。
   調(diào)用 dismiss方法犬第,這個方法是不會調(diào)用的
   */
    @available(iOS 13.0, *)
    optional func presentationControllerWillDismiss(_ presentationController: UIPresentationController)

    
   /*
    vc dismiss 了
    調(diào)用 dismissf方法锦积,這個方法是不會調(diào)用的
    */
    @available(iOS 13.0, *)
    optional func presentationControllerDidDismiss(_ presentationController: UIPresentationController)

   
  /*
  UIKit 支持在presentationController.isModalInPresentation 返回true 或presentationControllerShouldDismiss(_:) 返回false 時拒絕關(guān)閉演示。
  可以使用此方法通知用戶為什么不能關(guān)閉VC
  */
    @available(iOS 13.0, *)
    optional func presentationControllerDidAttemptToDismiss(_ presentationController: UIPresentationController)
}



// 下面定義的方法都是抽象的歉嗓; 為了繼承`UIPopoverBackgroundView`丰介,你必須提供下面每個方法的實現(xiàn)。 對于 `readwrite` 屬性鉴分,您必須提供兩個訪問器的實現(xiàn)哮幢。
public protocol UIPopoverBackgroundViewMethods {

    //箭頭三角形底邊的長度。
    static func arrowBase() -> CGFloat

    
    //描述背景視圖的每個邊緣與其內(nèi)容視圖的對應邊緣之間的距離
    static func contentViewInsets() -> UIEdgeInsets

    //箭頭三角形的高度
    static func arrowHeight() -> CGFloat
}

@available(iOS 5.0, *)
open class UIPopoverBackgroundView : UIView, UIPopoverBackgroundViewMethods {

    
  /*
  箭頭偏移表示箭頭中心應該出現(xiàn)在離視圖中心多遠的地方志珍。 對于 `UIPopoverArrowDirectionUp` 和 `UIPopoverArrowDirectionDown`橙垢,這是一個從左到右的偏移量; 箭頭在中心的左邊碴裙,arrowOffset為負數(shù)钢悲,箭頭在中心的右邊為正。 對于 `UIPopoverArrowDirectionLeft` 和 `UIPopoverArrowDirectionRight`舔株,這是一個從上到下的偏移量莺琳; 箭頭在中心的上邊,arrowOffset為負數(shù)载慈,箭頭在中心的下邊為正惭等。。
  */
    open var arrowOffset: CGFloat

    
    /* `arrowDirection` 管理彈出框箭頭指向的方向办铡。 當彈出窗口在屏幕上仍然可見時辞做,您可能需要更改箭頭的方向。
      */
    open var arrowDirection: UIPopoverArrowDirection

    
  /* 此方法可能會被覆蓋以防止在彈出框內(nèi)繪制 contentinset 和陰影寡具。 此方法的默認實現(xiàn)返回 YES秤茅。
      */
    @available(iOS, introduced: 6.0, deprecated: 13.0, message: "No longer supported")
    open class var wantsDefaultContentAppearance: Bool { get }
}

例子

  1. 通過設(shè)置sourceView彈出

    class SourceViewVC: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
        }
        
    
        @IBAction func clickPopBtn(_ sender: UIButton) {
            let popVC = PopVC.init()
            //設(shè)置為彈窗樣式
            popVC.modalPresentationStyle = .popover
            //設(shè)置彈出大小
            popVC.preferredContentSize = CGSize.init(width: 200, height: 200)
            popVC.popoverPresentationController?.sourceView = sender
            //在iOS13.2之前必須設(shè)置sourceRect,否則無法顯示正確位置
            popVC.popoverPresentationController?.sourceRect = sender.bounds
            popVC.popoverPresentationController?.permittedArrowDirections = .up
            popVC.popoverPresentationController?.delegate = self
            present(popVC, animated: true, completion: nil)
        }
    }
    
    extension SourceViewVC : UIPopoverPresentationControllerDelegate{
        //是否允許點擊背景消失
        public func popoverPresentationControllerShouldDismissPopover(_ popoverPresentationController: UIPopoverPresentationController) -> Bool {
            return true
        }
        //是否允許點擊背景消失
        @available(iOS 13.0, *)
        public func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool {
            return true
        }
        //必須設(shè)置為none,否則沒有彈窗效果
        public func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
            return .none
        }
        //Dismiss
        public func popoverPresentationControllerDidDismissPopover(_ popoverPresentationController: UIPopoverPresentationController) {
           
        }
        //Dismiss
        @available(iOS 13.0, *)
        func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
            
        }
    }
    
sourceView.png
  1. 通過UIBarButtonItem彈出

    class BarItemViewController: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
        }
        
       
        @IBAction func clickBarItem(_ sender: UIBarButtonItem) {
            let popVC = PopVC.init()
            //設(shè)置為彈窗樣式
            popVC.modalPresentationStyle = .popover
            //設(shè)置彈出大小
            popVC.preferredContentSize = CGSize.init(width: 200, height: 200)
            popVC.popoverPresentationController?.barButtonItem = sender
            popVC.popoverPresentationController?.permittedArrowDirections = .up
            popVC.popoverPresentationController?.delegate = self
            present(popVC, animated: true, completion: nil)
        }
    }
    
    extension BarItemViewController : UIPopoverPresentationControllerDelegate{
        //是否允許點擊背景消失
        public func popoverPresentationControllerShouldDismissPopover(_ popoverPresentationController: UIPopoverPresentationController) -> Bool {
            return true
        }
        //是否允許點擊背景消失
        @available(iOS 13.0, *)
        public func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool {
            return true
        }
        //必須設(shè)置為none,否則沒有彈窗效果
        public func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
            return .none
        }
        //Dismiss
        public func popoverPresentationControllerDidDismissPopover(_ popoverPresentationController: UIPopoverPresentationController) {
           
        }
        //Dismiss
        @available(iOS 13.0, *)
        func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
            
        }
    }
    
    
UIBarButtonItem.png
  1. 自定義彈窗童叠,我這里定義的是一個居中無箭頭的彈窗 可以修改彈窗的陰影框喳,邊框,邊框顏色厦坛,圓角等屬性,同時針對鍵盤也做了處理五垮,當彈窗中有輸入框的時候,彈窗會自動上移

    import UIKit
    open class BaseCenterPopVC<T:BasePopoverBgView>: UIViewController,UIPopoverPresentationControllerDelegate{
        ///用于確定彈窗的位置
        private var sourceRect:CGRect = .zero
        ///彈窗的大小
        public var size:CGSize = .zero
        ///是否可以點擊背景消失
        public var enableDismiss = true
        ///點擊背景消失后的回調(diào)
        public var didDismiss:(() -> Void)? = nil
        public var bgView:UIView!
        ///彈窗邊框?qū)挾?    public var popBorderWidth: CGFloat{
            return view.superview?.layer.borderWidth ?? 0
        }
        
        ///彈窗邊框顏色
        public var popBorderColor: CGColor?{
            return view.superview?.layer.borderColor
        }
        ///彈窗的圓角
        public var popCornerRadius: CGFloat{
            return view.superview?.layer.cornerRadius ?? 0
        }
        
        ///彈窗要設(shè)置圓角的角
        @available(iOS 11.0, *)
        public var popMaskedCorners: CACornerMask{
            return view.superview?.layer.maskedCorners ?? []
        }
        
        
        public init(size:CGSize) {
            super.init(nibName: nil, bundle: nil)
            self.size = size
            initPopVC()
        }
        
        required public init?(coder: NSCoder) {
            super.init(coder: coder)
            initPopVC()
        }
        
        func initPopVC(){
            //必須在彈窗彈出前設(shè)置modalPresentationStyle
            modalPresentationStyle = .popover
            popoverPresentationController?.permittedArrowDirections = .up
            popoverPresentationController?.delegate = self
            popoverPresentationController?.canOverlapSourceViewRect = true
            popoverPresentationController?.popoverBackgroundViewClass = T.self
        }
        
        open override func viewDidLoad() {
            super.viewDidLoad()
            //防止使用storyboard后沒有設(shè)置contentSize
            //子類要再super.viewDidLoad()之前設(shè)置size
            if size.equalTo(.zero) {
                fatalError("must set vc's size")
            }
            let screenSize = UIScreen.main.bounds.size
            sourceRect = CGRect.init(x:screenSize.width/2, y: 0, width: 1, height:(screenSize.height - size.height)/2)
            preferredContentSize = size
            popoverPresentationController?.sourceRect = sourceRect
            //從A控制器通過present的方式跳轉(zhuǎn)到了B控制器杜秸,那么 A.presentedViewController 就是B控制器放仗;B.presentingViewController 就是A控制器
            //不能在init中,因為presentingViewController在init中為nil
            weak var presentingView = presentingViewController?.view
            popoverPresentationController?.sourceView = presentingView
            bgView = UIView.init(frame: UIScreen.main.bounds)
            bgView.backgroundColor = UIColor.init(white: 0, alpha: 0.25)
        }
        
        open override func viewWillAppear(_ animated: Bool) {
            super.viewWillAppear(animated)
            presentingViewController?.view.addSubview(bgView)
        }
        
        open override func viewWillDisappear(_ animated: Bool) {
            super.viewWillDisappear(animated)
            bgView.removeFromSuperview()
        }
        
        
        open override func viewDidLayoutSubviews() {
            super.viewDidLayoutSubviews()
            view.superview?.layer.borderWidth = popBorderWidth
            view.superview?.layer.borderColor = popBorderColor
            view.superview?.layer.cornerRadius = popCornerRadius
            if #available(iOS 11.0, *) {
                view.superview?.layer.maskedCorners = popMaskedCorners
            }
        }
        
        //MARK:UIPopoverPresentationControllerDelegate
        public func popoverPresentationControllerShouldDismissPopover(_ popoverPresentationController: UIPopoverPresentationController) -> Bool {
            return enableDismiss
        }
        
        @available(iOS 13.0, *)
        public func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool {
            return enableDismiss
        }
        
        public func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
            return .none
        }
        
        public func popoverPresentationControllerDidDismissPopover(_ popoverPresentationController: UIPopoverPresentationController) {
            didDismiss?()
            didDismiss = nil
        }
        
        @available(iOS 13.0, *)
        public func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
            didDismiss?()
            didDismiss = nil
        }
    }
    
    
    //移除了箭頭的彈窗背景
    open class BasePopoverBgView : UIPopoverBackgroundView{
        ///彈窗背景的陰影偏移
        public var popShadowOffset: CGSize{
            return layer.shadowOffset
        }
        ///彈窗背景的陰影圓角
        public var popShadowRadius: CGFloat{
            return layer.shadowRadius
        }
        ///彈窗背景的陰影不透明度
        public var popShadowOpacity: Float{
            return layer.shadowOpacity
        }
        ///彈窗背景的陰影顏色
        public var popShadowColor: CGColor?{
            return layer.shadowColor
        }
        
        public override static func contentViewInsets() -> UIEdgeInsets {
            return UIEdgeInsets.zero
        }
        
        public override static func arrowHeight() -> CGFloat {
            return 0
        }
        
        open override var arrowDirection: UIPopoverArrowDirection {
            get { return UIPopoverArrowDirection.up }
            set {setNeedsLayout()}
        }
        
        open override var arrowOffset: CGFloat {
            get { return 0 }
            set {setNeedsLayout()}
        }
        
        open override func layoutSubviews() {
            super.layoutSubviews()
            self.layer.shadowOffset = popShadowOffset
            self.layer.shadowRadius = popShadowRadius
            self.layer.shadowOpacity = popShadowOpacity
            self.layer.shadowColor = popShadowColor
        }
    }
    
    open class PopDefaultConfig {
        static let shared = PopDefaultConfig()
        ///彈窗背景的陰影偏移
        public var shadowOffset:CGSize = CGSize.init(width: 0, height: 4)
        ///彈窗背景的陰影圓角
        public var shadowRadius:CGFloat = 4
        ///彈窗背景的陰影不透明度
        public var shadowOpacity:Float = 0.2
        ///彈窗背景的陰影顏色
        public var shadowColor:UIColor = .gray
        ///彈窗邊框?qū)挾?    public  var borderWidth: CGFloat = 0
        ///彈窗邊框顏色
        public var borderColor: UIColor = .white
        ///彈窗的圓角
        public var cornerRadius: CGFloat = 0
        ///彈窗要設(shè)置圓角的角
        public var maskedCorners:CACornerMask = [.layerMinXMinYCorner,.layerMaxXMinYCorner,.layerMinXMaxYCorner,.layerMaxXMaxYCorner]
        private init(){}
    }
    
    
    open class DefaultPopoverBgView: BasePopoverBgView {
        ///彈窗背景的陰影偏移
        public override var popShadowOffset: CGSize{
            return PopDefaultConfig.shared.shadowOffset
        }
        ///彈窗背景的陰影圓角
        public override var popShadowRadius: CGFloat{
            return PopDefaultConfig.shared.shadowRadius
        }
        ///彈窗背景的陰影不透明度
        public override var popShadowOpacity: Float{
            return PopDefaultConfig.shared.shadowOpacity
        }
        ///彈窗背景的陰影顏色
        public override var popShadowColor: CGColor?{
            return PopDefaultConfig.shared.shadowColor.cgColor
        }
    }
    
    
    open class DefaultPopoVC: BaseCenterPopVC<DefaultPopoverBgView> {
        ///彈窗邊框?qū)挾?    public override var popBorderWidth: CGFloat{
            return PopDefaultConfig.shared.borderWidth
        }
        ///彈窗邊框顏色
        public override var popBorderColor: CGColor?{
            return PopDefaultConfig.shared.borderColor.cgColor
        }
        ///彈窗的圓角
        public override var popCornerRadius: CGFloat{
            return PopDefaultConfig.shared.cornerRadius
        }
        ///彈窗要設(shè)置圓角的角
        @available(iOS 11.0, *)
        public override var popMaskedCorners: CACornerMask{
            return PopDefaultConfig.shared.maskedCorners
        }
    }
    
   class CustomVC: UIViewController {
   
       override func viewDidLoad() {
           super.viewDidLoad()
           //通過 PopDefaultConfig全局配置彈窗的屬性
           PopDefaultConfig.shared.borderWidth = 1
           PopDefaultConfig.shared.borderColor = UIColor.blue
           PopDefaultConfig.shared.cornerRadius = 10
       }
       @IBAction func clickGlobalPopBtn(_ sender: Any) {
           let vc = GlobalPopVC.init(size: CGSize.init(width: 200, height: 200))
           present(vc, animated: true, completion: nil)
       }
       
       @IBAction func clickCustomPopBtn(_ sender: Any) {
           let vc = CustomPopVC.init(size: CGSize.init(width: 200, height: 200))
           present(vc, animated: true, completion: nil)
       }
       //Storyboard中彈出CustomSBPopVC
   }
   
   
   class GlobalPopVC: DefaultPopoVC {
       override func viewDidLoad() {
           super.viewDidLoad()
           view.backgroundColor = UIColor.orange
       }
   }
   
   class CustomPopVC: BaseCenterPopVC<CustomBgView> {
       
       ///彈窗邊框?qū)挾?       override var popBorderWidth: CGFloat{
           return 2
       }
       ///彈窗邊框顏色
       override var popBorderColor: CGColor?{
           return UIColor.green.cgColor
       }
       ///彈窗的圓角
       override var popCornerRadius: CGFloat{
           return 20
       }
       
       ///彈窗要設(shè)置圓角的角
       override var popMaskedCorners: CACornerMask{
           return [.layerMinXMinYCorner,.layerMaxXMaxYCorner]
       }
       
       override func viewDidLoad() {
           super.viewDidLoad()
           view.backgroundColor = UIColor.red
       }
   }
   
   
   class CustomBgView: BasePopoverBgView {
       ///彈窗背景的陰影偏移
       override var popShadowOffset: CGSize{
           return CGSize.init(width: 10, height: 10)
       }
       ///彈窗背景的陰影圓角
       override var popShadowRadius: CGFloat{
           return 10
       }
       ///彈窗背景的陰影不透明度
       override var popShadowOpacity: Float{
           return 0.2
       }
       ///彈窗背景的陰影顏色
       override var popShadowColor: CGColor?{
           return UIColor.red.cgColor
       }
   }
   
   class CustomSBPopVC: DefaultPopoVC {
       override func viewDidLoad() {
           //必須在父類調(diào)用viewDidLoad之前設(shè)置size
           size = CGSize.init(width: UIScreen.main.bounds.size.width, height: 300)
           super.viewDidLoad()
       }
       
   }
   
   extension CustomSBPopVC : UITextFieldDelegate{
       func textFieldShouldReturn(_ textField: UITextField) -> Bool {
           textField.resignFirstResponder()
           return true
       }
   }
   
CustomPop.png
GlobalPop.png
Storyboard.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末撬碟,一起剝皮案震驚了整個濱河市诞挨,隨后出現(xiàn)的幾起案子莉撇,更是在濱河造成了極大的恐慌,老刑警劉巖亭姥,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件稼钩,死亡現(xiàn)場離奇詭異,居然都是意外死亡达罗,警方通過查閱死者的電腦和手機坝撑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來粮揉,“玉大人巡李,你說我怎么就攤上這事》鋈希” “怎么了侨拦?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長辐宾。 經(jīng)常有香客問我狱从,道長,這世上最難降的妖魔是什么叠纹? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任季研,我火速辦了婚禮,結(jié)果婚禮上誉察,老公的妹妹穿的比我還像新娘与涡。我一直安慰自己,他們只是感情好持偏,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布驼卖。 她就那樣靜靜地躺著,像睡著了一般鸿秆。 火紅的嫁衣襯著肌膚如雪酌畜。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天卿叽,我揣著相機與錄音檩奠,去河邊找鬼。 笑死附帽,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的井誉。 我是一名探鬼主播蕉扮,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼颗圣!你這毒婦竟也來了喳钟?” 一聲冷哼從身側(cè)響起屁使,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎奔则,沒想到半個月后蛮寂,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡易茬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年酬蹋,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片抽莱。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡范抓,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出食铐,到底是詐尸還是另有隱情匕垫,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布虐呻,位于F島的核電站象泵,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏斟叼。R本人自食惡果不足惜偶惠,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望犁柜。 院中可真熱鬧洲鸠,春花似錦、人聲如沸馋缅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽萤悴。三九已至瘾腰,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間覆履,已是汗流浹背蹋盆。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留硝全,地道東北人栖雾。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像伟众,于是被迫代替她去往敵國和親析藕。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容