131 lines
4.4 KiB
Objective-C
131 lines
4.4 KiB
Objective-C
//
|
|
// UIViewController+LayoutHelper.m
|
|
// HWPanModal
|
|
//
|
|
// Created by heath wang on 2019/4/26.
|
|
//
|
|
|
|
#import "UIViewController+LayoutHelper.h"
|
|
#import "HWPanModalPresentationController.h"
|
|
#import "UIViewController+PanModalDefault.h"
|
|
|
|
@implementation UIViewController (LayoutHelper)
|
|
|
|
- (CGFloat)topLayoutOffset {
|
|
if (@available(iOS 11, *)) {
|
|
return [UIApplication sharedApplication].keyWindow.safeAreaInsets.top;
|
|
} else {
|
|
return [UIApplication sharedApplication].keyWindow.rootViewController.topLayoutGuide.length;
|
|
}
|
|
|
|
}
|
|
|
|
- (CGFloat)bottomLayoutOffset {
|
|
if (@available(iOS 11, *)) {
|
|
return [UIApplication sharedApplication].keyWindow.safeAreaInsets.bottom;
|
|
} else {
|
|
return [UIApplication sharedApplication].keyWindow.rootViewController.bottomLayoutGuide.length;
|
|
}
|
|
}
|
|
|
|
- (HWPanModalPresentationController *)hw_presentedVC {
|
|
/*
|
|
* Fix iOS13 bug: if we access presentationController before present VC, this will lead `modalPresentationStyle` not working.
|
|
* refer to: https://github.com/HeathWang/HWPanModal/issues/27
|
|
* Apple Doc: If you have not yet presented the current view controller, accessing this property creates a presentation controller based on the current value in the modalPresentationStyle property.
|
|
*/
|
|
|
|
/**
|
|
* fix bug: https://github.com/HeathWang/HWPanModal/issues/37
|
|
*/
|
|
if (self.presentingViewController) {
|
|
return [self hw_getPanModalPresentationController];
|
|
} else {
|
|
return nil;
|
|
}
|
|
}
|
|
|
|
- (HWPanModalPresentationController *)hw_getPanModalPresentationController {
|
|
UIViewController *ancestorsVC;
|
|
|
|
// seeking for the root presentation VC.
|
|
if (self.splitViewController) {
|
|
ancestorsVC = self.splitViewController;
|
|
} else if (self.navigationController) {
|
|
ancestorsVC = self.navigationController;
|
|
} else if (self.tabBarController) {
|
|
ancestorsVC = self.tabBarController;
|
|
} else {
|
|
ancestorsVC = self;
|
|
}
|
|
|
|
if ([ancestorsVC.presentationController isMemberOfClass:HWPanModalPresentationController.class]) {
|
|
return (HWPanModalPresentationController *) ancestorsVC.presentationController;
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
/**
|
|
Returns the short form Y postion
|
|
|
|
- Note: If voiceover is on, the `longFormYPos` is returned.
|
|
We do not support short form when voiceover is on as it would make it difficult for user to navigate.
|
|
*/
|
|
- (CGFloat)shortFormYPos {
|
|
if (UIAccessibilityIsVoiceOverRunning()) {
|
|
return self.longFormYPos;
|
|
} else {
|
|
CGFloat shortFormYPos = [self topMarginFromPanModalHeight:[self shortFormHeight]] + [self topOffset];
|
|
return MAX(shortFormYPos, self.longFormYPos);
|
|
}
|
|
}
|
|
|
|
- (CGFloat)mediumFormYPos {
|
|
if (UIAccessibilityIsVoiceOverRunning()) {
|
|
return self.longFormYPos;
|
|
} else {
|
|
CGFloat mediumFormYPos = [self topMarginFromPanModalHeight:[self mediumFormHeight]] + [self topOffset];
|
|
return MAX(mediumFormYPos, self.longFormYPos);
|
|
}
|
|
}
|
|
|
|
- (CGFloat)longFormYPos {
|
|
return MAX([self topMarginFromPanModalHeight:[self longFormHeight]], [self topMarginFromPanModalHeight:PanModalHeightMake(PanModalHeightTypeMax, 0)]) + [self topOffset];
|
|
}
|
|
|
|
/**
|
|
* Use the container view for relative positioning as this view's frame
|
|
is adjusted in PanModalPresentationController
|
|
*/
|
|
- (CGFloat)bottomYPos {
|
|
if (self.hw_presentedVC.containerView) {
|
|
return self.hw_presentedVC.containerView.bounds.size.height - [self topOffset];
|
|
}
|
|
return self.view.bounds.size.height;
|
|
}
|
|
|
|
- (CGFloat)topMarginFromPanModalHeight:(PanModalHeight)panModalHeight {
|
|
switch (panModalHeight.heightType) {
|
|
case PanModalHeightTypeMax:
|
|
return 0.0f;
|
|
case PanModalHeightTypeMaxTopInset:
|
|
return panModalHeight.height;
|
|
case PanModalHeightTypeContent:
|
|
return self.bottomYPos - (panModalHeight.height + self.bottomLayoutOffset);
|
|
case PanModalHeightTypeContentIgnoringSafeArea:
|
|
return self.bottomYPos - panModalHeight.height;
|
|
case PanModalHeightTypeIntrinsic:
|
|
{
|
|
[self.view layoutIfNeeded];
|
|
|
|
CGSize targetSize = CGSizeMake(self.hw_presentedVC.containerView ? self.hw_presentedVC.containerView.bounds.size.width : [UIScreen mainScreen].bounds.size.width, UILayoutFittingCompressedSize.height);
|
|
CGFloat intrinsicHeight = [self.view systemLayoutSizeFittingSize:targetSize].height;
|
|
return self.bottomYPos - (intrinsicHeight + self.bottomLayoutOffset);
|
|
}
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
@end
|