QMUIModalPresentationViewController

@interface QMUIModalPresentationViewController : UIViewController

一个提供通用的弹出浮层功能的控件,可以将任意UIViewUIViewController以浮层的形式显示出来并自动布局。

支持 3 种方式显示浮层:

  1. 推荐 新起一个 UIWindow 盖在当前界面上,将 QMUIModalPresentationViewControllerrootViewController 的形式显示出来,可通过 supportedOrientationMask 支持横竖屏,不支持在浮层不消失的情况下做界面切换(因为 window 会把背后的 controller 盖住,看不到界面切换)。 可通过 shownInWindowMode 属性来判断是否在用这种方式显示。

    [modalPresentationViewController showWithAnimated:YES completion:nil];
    
  2. 使用系统接口来显示,支持界面切换,注意 使用这种方法必定只能以动画的形式来显示浮层,无法以无动画的形式来显示,并且 animated 参数必须为 NO。可通过 supportedOrientationMask 支持横竖屏。 可通过 shownInPresentedMode 属性来判断是否在用这种方式显示。

    [self presentViewController:modalPresentationViewController animated:NO completion:nil];
    
  3. 将浮层作为一个 subview 添加到 superview 上,从而能够实现在浮层不消失的情况下进行界面切换,但需要 superview 自行管理浮层的大小和横竖屏旋转,而且 QMUIModalPresentationViewController 不能用局部变量来保存,会在显示后被释放,需要自行 retain。横竖屏跟随当前界面的设置。 可通过 shownInSubviewMode 属性来判断是否在用这种方式显示。

    self.modalPresentationViewController.view.frame = CGRectMake(50, 50, 100, 100);
    [self.view addSubview:self.modalPresentationViewController.view];
    

默认的布局会将浮层居中显示,浮层的大小可通过接口控制:

  1. 如果是用 contentViewController,则可通过 preferredContentSizeInModalPresentationViewController:keyboardHeight:limitSize: 来设置
  2. 如果使用 contentView,或者使用 contentViewController 但没实现 preferredContentSizeInModalPresentationViewController:keyboardHeight:limitSize:,则调用contentViewsizeThatFits:方法获取大小。
  3. 浮层大小会受 maximumContentViewWidth 属性的限制,以及 contentViewMargins 属性的影响。

通过layoutBlockshowingAnimationhidingAnimation可设置自定义的布局、打开及隐藏的动画,并允许你适配键盘升起时的场景。

默认提供背景遮罩dimmingView,你也可以使用自己的遮罩 view。

默认提供多种显示动画,可通过 animationStyle 来设置。

Warning

如果使用者retain了modalPresentationViewController,注意应该在hideWithAnimated:completion:里release

See

QMUIAlertController

See

QMUIDialogViewController

See

QMUIMoreOperationController

  • Undocumented

    Declaration

    Objective-C

    @property(nullable, nonatomic, weak) IBOutlet id<QMUIModalPresentationViewControllerDelegate> delegate

    Swift

    @IBOutlet weak var delegate: QMUIModalPresentationViewControllerDelegate? { get set }
  • 要被弹出的浮层

    Warning

    当设置了contentView时,不要再设置contentViewController

    Declaration

    Objective-C

    @property (nonatomic, strong, nullable) UIView *contentView;

    Swift

    @IBOutlet var contentView: UIView? { get set }
  • 要被弹出的浮层,适用于浮层以UIViewController的形式来管理的情况。

    Warning

    当设置了contentViewController时,contentViewController.view会被当成contentView使用,因此不要再自行设置contentView

    Warning

    注意contentViewController是强引用,容易导致循环引用,使用时请注意

    Declaration

    Objective-C

    @property (nonatomic, strong, nullable) UIViewController<QMUIModalPresentationContentViewControllerProtocol> *contentViewController;

    Swift

    @IBOutlet var contentViewController: (UIViewController & QMUIModalPresentationContentViewControllerProtocol)? { get set }
  • 设置contentView布局时与外容器的间距,默认为(20, 20, 20, 20)

    Warning

    当设置了layoutBlock属性时,此属性不生效

    Declaration

    Objective-C

    @property (nonatomic) UIEdgeInsets contentViewMargins;

    Swift

    var contentViewMargins: UIEdgeInsets { get set }
  • 限制contentView布局时的最大宽度,默认为 CGFLOAT_MAX,也即无限制。

    Warning

    当设置了layoutBlock属性时,此属性不生效

    Declaration

    Objective-C

    @property (nonatomic) CGFloat maximumContentViewWidth;

    Swift

    var maximumContentViewWidth: CGFloat { get set }
  • 背景遮罩,默认为一个普通的UIView,背景色为UIColorMask,可设置为自己的view,注意dimmingView的大小将会盖满整个控件。

    QMUIModalPresentationViewController会自动给自定义的dimmingView添加手势以实现点击遮罩隐藏浮层。

    Declaration

    Objective-C

    @property (nonatomic, strong, nullable) UIView *dimmingView;

    Swift

    @IBOutlet var dimmingView: UIView? { get set }
  • 由于点击遮罩导致浮层即将被隐藏的回调

    Declaration

    Objective-C

    @property (nonatomic, copy, nullable) void (^)(void) willHideByDimmingViewTappedBlock;

    Swift

    var willHideByDimmingViewTappedBlock: (() -> Void)? { get set }
  • 由于点击遮罩导致浮层被隐藏后的回调(区分于hideWithAnimated:completion:里的completion,这里是特地用于点击遮罩的情况)

    Declaration

    Objective-C

    @property (nonatomic, copy, nullable) void (^)(void) didHideByDimmingViewTappedBlock;

    Swift

    var didHideByDimmingViewTappedBlock: (() -> Void)? { get set }
  • 控制当前是否以模态的形式存在。如果以模态的形式存在,则点击空白区域不会隐藏浮层。

    默认为NO,也即点击空白区域将会自动隐藏浮层。

    Declaration

    Objective-C

    @property (nonatomic, getter=isModal) BOOL modal;

    Swift

    var isModal: Bool { get set }
  • 标志当前浮层的显示/隐藏状态,默认为NO。

    Declaration

    Objective-C

    @property (nonatomic, readonly, getter=isVisible) BOOL visible;

    Swift

    var isVisible: Bool { get }
  • 修改当前界面要支持的横竖屏方向,默认为 SupportedOrientationMask。

    Declaration

    Objective-C

    @property (nonatomic) UIInterfaceOrientationMask supportedOrientationMask;

    Swift

    var supportedOrientationMask: UIInterfaceOrientationMask { get set }
  • 设置要使用的显示/隐藏动画的类型,默认为QMUIModalPresentationAnimationStyleFade

    Warning

    当使用了showingAnimationhidingAnimation时,该属性无效

    Declaration

    Objective-C

    @property (nonatomic) QMUIModalPresentationAnimationStyle animationStyle;

    Swift

    var animationStyle: QMUIModalPresentationAnimationStyle { get set }
  • 是否以 UIWindow 的方式显示,建议在显示之后才使用,否则可能不准确。

    Declaration

    Objective-C

    @property (nonatomic, assign, unsafe_unretained, readonly,
              getter=isShownInWindowMode) BOOL shownInWindowMode;

    Swift

    var isShownInWindowMode: Bool { get }
  • 是否以系统 present 的方式显示,建议在显示之后才使用,否则可能不准确。

    Declaration

    Objective-C

    @property (nonatomic, assign, unsafe_unretained, readonly,
              getter=isShownInPresentedMode) BOOL shownInPresentedMode;

    Swift

    var isShownInPresentedMode: Bool { get }
  • 是否以 addSubview 的方式显示,建议在显示之后才使用,否则可能不准确。

    Declaration

    Objective-C

    @property (nonatomic, assign, unsafe_unretained, readonly,
              getter=isShownInSubviewMode) BOOL shownInSubviewMode;

    Swift

    var isShownInSubviewMode: Bool { get }
  • 只响应 modal.view 上的 view 所产生的键盘事件,当为 NO 时,只要有键盘事件产生,浮层都会重新计算布局。 默认为 YES,也即只响应浮层上的 view 引起的键盘位置变化。

    Declaration

    Objective-C

    @property (nonatomic) BOOL onlyRespondsToKeyboardEventFromDescendantViews;

    Swift

    var onlyRespondsToKeyboardEventFromDescendantViews: Bool { get set }
  • 管理自定义的浮层布局,将会在浮层显示前、控件的容器大小发生变化时(例如横竖屏、来电状态栏)被调用,请在 block 内主动为 view 设置期望的 frame,设置时建议用 qmui_frameApplyTransform 取代 setFrame:,否则在有键盘的情况下,显隐动画可能有错。 @arg containerBounds 浮层所在的父容器的大小,也即self.view.bounds @arg keyboardHeight 键盘在当前界面里的高度,若无键盘,则为0 @arg contentViewDefaultFrame 不使用自定义布局的情况下的默认布局,会受contentViewMarginsmaximumContentViewWidthcontentView sizeThatFits:的影响

    See

    contentViewMargins

    See

    maximumContentViewWidth

    Declaration

    Objective-C

    @property (nonatomic, copy, nullable) void (^) (CGRect, CGFloat, CGRect) layoutBlock;

    Swift

    var layoutBlock: ((CGRect, CGFloat, CGRect) -> Void)? { get set }
  • 管理自定义的显示动画,需要管理的对象包括contentViewdimmingView,在showingAnimation被调用前,contentView已被添加到界面上。若使用了layoutBlock,则会先调用layoutBlock,再调用showingAnimation。在动画结束后,必须调用参数里的completion block。 @arg dimmingView 背景遮罩的View,请自行设置显示遮罩的动画 @arg containerBounds 浮层所在的父容器的大小,也即self.view.bounds @arg keyboardHeight 键盘在当前界面里的高度,若无键盘,则为0 @arg contentViewFrame 动画执行完后contentView的最终frame,若使用了layoutBlock,则也即layoutBlock计算完后的frame @arg completion 动画结束后给到modalController的回调,modalController会在这个回调里做一些状态设置,务必调用。

    Declaration

    Objective-C

    @property (nonatomic, copy, nullable) void (^) (UIView *_Nullable, CGRect, CGFloat, CGRect, void (^_Nonnull)(BOOL)) showingAnimation;

    Swift

    var showingAnimation: ((UIView?, CGRect, CGFloat, CGRect, @escaping (Bool) -> Void) -> Void)? { get set }
  • 管理自定义的隐藏动画,需要管理的对象包括contentViewdimmingView,在动画结束后,必须调用参数里的completion block。 @arg dimmingView 背景遮罩的View,请自行设置隐藏遮罩的动画 @arg containerBounds 浮层所在的父容器的大小,也即self.view.bounds @arg keyboardHeight 键盘在当前界面里的高度,若无键盘,则为0 @arg completion 动画结束后给到modalController的回调,modalController会在这个回调里做一些清理工作,务必调用

    Declaration

    Objective-C

    @property (nonatomic, copy, nullable) void (^) (UIView *_Nullable, CGRect, CGFloat, void (^_Nonnull)(BOOL)) hidingAnimation;

    Swift

    var hidingAnimation: ((UIView?, CGRect, CGFloat, @escaping (Bool) -> Void) -> Void)? { get set }
  • 请求重新计算浮层的布局

    Declaration

    Objective-C

    - (void)updateLayout;

    Swift

    func updateLayout()
  • 将浮层以 UIWindow 的方式显示出来

    Declaration

    Objective-C

    - (void)showWithAnimated:(BOOL)animated
                  completion:(void (^_Nullable)(BOOL))completion;

    Swift

    func showWith(animated: Bool, completion: ((Bool) -> Void)? = nil)

    Parameters

    animated

    是否以动画的形式显示

    completion

    显示动画结束后的回调

  • 将浮层隐藏掉

    Warning

    这里的completion只会在你显式调用hideWithAnimated:completion:方法来隐藏浮层时会被调用,如果你通过点击dimmingView来触发hideWithAnimated:completion:,则completion是不会被调用的,那种情况下如果你要在浮层隐藏后做一些事情,请使用delegate提供的didHideModalPresentationViewController:方法。

    Declaration

    Objective-C

    - (void)hideWithAnimated:(BOOL)animated
                  completion:(void (^_Nullable)(BOOL))completion;

    Swift

    func hideWith(animated: Bool, completion: ((Bool) -> Void)? = nil)

    Parameters

    animated

    是否以动画的形式隐藏

    completion

    隐藏动画结束后的回调

  • 将浮层以 addSubview 的方式显示出来

    Declaration

    Objective-C

    - (void)showInView:(nonnull UIView *)view
              animated:(BOOL)animated
            completion:(void (^_Nullable)(BOOL))completion;

    Swift

    func show(in view: UIView, animated: Bool, completion: ((Bool) -> Void)? = nil)

    Parameters

    view

    要显示到哪个 view 上

    animated

    是否以动画的形式显示

    completion

    显示动画结束后的回调

  • 将某个 view 上显示的浮层隐藏掉

    Warning

    这里的completion只会在你显式调用hideInView:animated:completion:方法来隐藏浮层时会被调用,如果你通过点击dimmingView来触发hideInView:animated:completion:,则completion是不会被调用的,那种情况下如果你要在浮层隐藏后做一些事情,请使用delegate提供的didHideModalPresentationViewController:方法。

    Declaration

    Objective-C

    - (void)hideInView:(nonnull UIView *)view
              animated:(BOOL)animated
            completion:(void (^_Nullable)(BOOL))completion;

    Swift

    func hide(in view: UIView, animated: Bool, completion: ((Bool) -> Void)? = nil)

    Parameters

    view

    要隐藏哪个 view 上的浮层

    animated

    是否以动画的形式隐藏

    completion

    隐藏动画结束后的回调

Manager

  • 判断当前App里是否有modalViewController正在显示(存在modalViewController但不可见的时候,也视为不存在)

    Declaration

    Objective-C

    + (BOOL)isAnyModalPresentationViewControllerVisible;

    Swift

    class func isAnyModalPresentationViewControllerVisible() -> Bool

    Return Value

    只要存在正在显示的浮层,则返回YES,否则返回NO

  • 把所有正在显示的并且允许被隐藏的modalViewController都隐藏掉

    See

    shouldHideModalPresentationViewController:

    See

    QMUIModalPresentationComponentProtocol

    Warning

    当要隐藏一个 modalPresentationViewController 时,如果这个 modal 有实现 QMUIModalPresentationComponentProtocol 协议,则会调用它的 hideModalPresentationComponent 方法来隐藏,否则直接用 QMUIModalPresentationViewController 的 hideWithAnimated:completion:

    Declaration

    Objective-C

    + (BOOL)hideAllVisibleModalPresentationViewControllerIfCan;

    Swift

    class func hideAllVisibleModalPresentationViewControllerIfCan() -> Bool

    Return Value

    只要遇到一个正在显示的并且不能被隐藏的浮层,就会返回NO,否则都返回YES,表示成功隐藏掉所有可视浮层

UIAppearance

  • Undocumented

    Declaration

    Objective-C

    + (instancetype)appearance;

    Swift

    class func appearance() -> Self