diff --git a/LNPopupController/LNPopupController/Private/LNPopupController.h b/LNPopupController/LNPopupController/Private/LNPopupController.h index f183052..5f2ff64 100644 --- a/LNPopupController/LNPopupController/Private/LNPopupController.h +++ b/LNPopupController/LNPopupController/Private/LNPopupController.h @@ -11,12 +11,13 @@ #import "UIViewController+LNPopupSupportPrivate.h" #import #import "LNPopupContentView+Private.h" +#import "LNPopupBar+Private.h" CF_EXTERN_C_BEGIN #define _LNPopupPresentationStateTransitioning ((LNPopupPresentationState)2) -@interface LNPopupController : NSObject +@interface LNPopupController : NSObject <_LNPopupBarDelegate> - (instancetype)initWithContainerViewController:(__kindof UIViewController*)containerController; @@ -24,6 +25,7 @@ CF_EXTERN_C_BEGIN @property (nonatomic, strong) LNPopupBar* popupBar; @property (nonatomic, strong, readonly) LNPopupBar* popupBarStorage; +@property (nonatomic, strong, readonly) LNPopupBar* popupBarNoCreate; @property (nonatomic, strong) LNPopupContentView* popupContentView; @property (nonatomic, strong) UIScrollView* popupContentContainerView; diff --git a/LNPopupController/LNPopupController/Private/LNPopupController.mm b/LNPopupController/LNPopupController/Private/LNPopupController.mm index 7afb31a..4d3fa41 100644 --- a/LNPopupController/LNPopupController/Private/LNPopupController.mm +++ b/LNPopupController/LNPopupController/Private/LNPopupController.mm @@ -72,7 +72,7 @@ static BOOL _LNCallDelegateObjectBool(UIViewController* controller, SEL selector #pragma mark Popup Controller -@interface LNPopupController () <_LNPopupItemDelegate, _LNPopupBarDelegate> +@interface LNPopupController () <_LNPopupItemDelegate> - (void)_applicationDidEnterBackground; - (void)_applicationWillEnterForeground; @@ -184,13 +184,12 @@ - (instancetype)initWithContainerViewController:(__kindof UIViewController*)cont - (CGRect)_frameForOpenPopupBar { -// CGRect defaultFrame = [_containerController defaultFrameForBottomDockingView_internalOrDeveloper]; return CGRectMake(0, - self.popupBar.frame.size.height, _containerController.view.bounds.size.width, self.popupBar.frame.size.height); } - (CGRect)_frameForClosedPopupBar { - CGRect defaultFrame = [_containerController defaultFrameForBottomDockingView_internalOrDeveloper]; + CGRect defaultFrame = [_containerController _defaultFrameForBottomDockingViewForPopupBar:_popupBar]; UIEdgeInsets insets = [_containerController insetsForBottomDockingView]; return CGRectMake(0, defaultFrame.origin.y - self.popupBar.frame.size.height - insets.bottom, _containerController.view.bounds.size.width, self.popupBar.frame.size.height); } @@ -272,7 +271,7 @@ - (void)_setContentToState:(LNPopupPresentationState)state animated:(BOOL)animat targetFrame.size = closedFrame.size; } - _cachedDefaultFrame = [_containerController defaultFrameForBottomDockingView_internalOrDeveloper]; + _cachedDefaultFrame = [_containerController _defaultFrameForBottomDockingViewForPopupBar:_popupBar]; _cachedInsets = [_containerController insetsForBottomDockingView]; self.popupBar.frame = targetFrame; @@ -788,7 +787,7 @@ - (void)_popupBarPresentationByUserPanGestureHandler_changed:(UIPanGestureRecogn [self _transitionToState:_LNPopupPresentationStateTransitioning notifyDelegate:YES animated:YES useSpringAnimation:NO allowPopupBarAlphaModification:YES allowFeedbackGeneration:NO forceFeedbackGenerationAtStart:NO completion:nil]; - _cachedDefaultFrame = [_containerController defaultFrameForBottomDockingView_internalOrDeveloper]; + _cachedDefaultFrame = [_containerController _defaultFrameForBottomDockingViewForPopupBar:_popupBar]; _cachedInsets = [_containerController insetsForBottomDockingView]; _cachedOpenPopupFrame = [self _frameForOpenPopupBar]; @@ -1141,7 +1140,7 @@ - (void)_movePopupBarAndContentToBottomBarSuperview } } -- (LNPopupBar *)popupBarStorage +- (LNPopupBar*)popupBarStorage { if(_popupBar) { @@ -1165,7 +1164,12 @@ - (LNPopupBar *)popupBarStorage return _popupBar; } -- (LNPopupBar *)popupBar +- (LNPopupBar*)popupBarNoCreate +{ + return _popupBar; +} + +- (LNPopupBar*)popupBar { if(_popupControllerInternalState == LNPopupPresentationStateBarHidden) { @@ -1175,7 +1179,7 @@ - (LNPopupBar *)popupBar return self.popupBarStorage; } -- (LNPopupContentView *)popupContentView +- (LNPopupContentView*)popupContentView { if(_popupContentView) { @@ -1385,7 +1389,7 @@ - (void)_presentPopupBarWithContentViewController:(UIViewController*)contentView [self.popupBar.customBarViewController _userFacing_viewIsAppearing:animated]; - _LNPopupSupportSetPopupInsetsForViewController(_containerController, YES, UIEdgeInsetsMake(0, 0, barFrame.size.height, 0)); + _LNPopupSupportSetPopupInsetsForViewController(_containerController, YES, UIEdgeInsetsMake(0, 0, barFrame.size.height - [_containerController _ln_popupOffsetForPopupBarStyle:self.popupBar.resolvedStyle], 0)); if(open) { @@ -1631,7 +1635,7 @@ - (void)_dismissPopupBarAnimated:(BOOL)animated completion:(void(^)(void))comple [self _removeContentControllerFromContentView:_currentContentController]; - CGRect bottomBarFrame = [_containerController defaultFrameForBottomDockingView_internalOrDeveloper]; + CGRect bottomBarFrame = [_containerController _defaultFrameForBottomDockingViewForPopupBar:_popupBar]; bottomBarFrame.origin.y -= _cachedInsets.bottom; _bottomBar.frame = bottomBarFrame; @@ -1732,7 +1736,7 @@ - (void)_popupBarMetricsDidChange:(LNPopupBar*)bar barFrame.origin.y -= (barFrame.size.height - currentHeight); self.popupBar.frame = barFrame; - _LNPopupSupportSetPopupInsetsForViewController(_containerController, YES, UIEdgeInsetsMake(0, 0, self.popupBar.frame.size.height, 0)); + _LNPopupSupportSetPopupInsetsForViewController(_containerController, YES, UIEdgeInsetsMake(0, 0, self.popupBar.frame.size.height - [_containerController _ln_popupOffsetForPopupBarStyle:self.popupBar.resolvedStyle], 0)); } - (void)_popupBarStyleDidChange:(LNPopupBar*)bar diff --git a/LNPopupController/LNPopupController/Private/UIViewController+LNPopupSupport.mm b/LNPopupController/LNPopupController/Private/UIViewController+LNPopupSupport.mm index 90484eb..b942a67 100644 --- a/LNPopupController/LNPopupController/Private/UIViewController+LNPopupSupport.mm +++ b/LNPopupController/LNPopupController/Private/UIViewController+LNPopupSupport.mm @@ -13,6 +13,7 @@ #import "_LNPopupSwizzlingUtils.h" #import "_LNPopupBase64Utils.hh" #import "LNMath.h" +#import "LNPopupBar+Private.h" #import static const void* _LNPopupItemKey = &_LNPopupItemKey; @@ -404,6 +405,24 @@ - (CGRect)defaultFrameForBottomDockingView return CGRectZero; } +- (CGFloat)_ln_popupOffsetForPopupBarStyle:(LNPopupBarStyle)barStyle +{ + if(barStyle != LNPopupBarStyleFloating /*|| UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPhone*/) + { + return 0.0; + } + + id dockingView = self.bottomDockingViewForPopupBar; + + if(dockingView != nil && ([dockingView isKindOfClass:UIToolbar.class] || [dockingView isKindOfClass:UITabBar.class]) == NO) + { + //User docking view, do not offset. + return 0.0; + } + + return self.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassRegular ? 7.0 : 0.0; +} + - (CGRect)defaultFrameForBottomDockingView_internal { CGFloat safeAreaAddition = self.view.safeAreaInsets.bottom - _LNPopupSafeAreas(self).bottom; @@ -416,9 +435,13 @@ - (CGRect)defaultFrameForBottomDockingView_internal return CGRectMake(0, self.view.bounds.size.height - safeAreaAddition, self.view.bounds.size.width, safeAreaAddition); } -- (CGRect)defaultFrameForBottomDockingView_internalOrDeveloper +- (CGRect)_defaultFrameForBottomDockingViewForPopupBar:(LNPopupBar*)popupBar { - return [self bottomDockingViewForPopupBar] != nil ? [self defaultFrameForBottomDockingView] : [self defaultFrameForBottomDockingView_internal]; + LNPopupBarStyle barStyle = popupBar != nil ? popupBar.resolvedStyle : _LNPopupResolveBarStyleFromBarStyle(LNPopupBarStyleDefault); + + CGRect rv = [self bottomDockingViewForPopupBar] != nil ? [self defaultFrameForBottomDockingView] : [self defaultFrameForBottomDockingView_internal]; + rv.origin.y += [self _ln_popupOffsetForPopupBarStyle:barStyle]; + return rv; } - (BOOL)shouldExtendPopupBarUnderSafeArea diff --git a/LNPopupController/LNPopupController/Private/UIViewController+LNPopupSupportPrivate.h b/LNPopupController/LNPopupController/Private/UIViewController+LNPopupSupportPrivate.h index 510ec0d..bf2cc46 100644 --- a/LNPopupController/LNPopupController/Private/UIViewController+LNPopupSupportPrivate.h +++ b/LNPopupController/LNPopupController/Private/UIViewController+LNPopupSupportPrivate.h @@ -63,8 +63,10 @@ void _LNPopupSupportSetPopupInsetsForViewController(UIViewController* controller - (nullable UIView *)bottomDockingViewForPopup_nocreateOrDeveloper; - (nonnull UIView *)bottomDockingViewForPopup_internalOrDeveloper; +- (CGFloat)_ln_popupOffsetForPopupBarStyle:(LNPopupBarStyle)barStyle; + - (CGRect)defaultFrameForBottomDockingView_internal; -- (CGRect)defaultFrameForBottomDockingView_internalOrDeveloper; +- (CGRect)_defaultFrameForBottomDockingViewForPopupBar:(LNPopupBar*)LNPopupBar; - (_LNPopupBarBackgroundView*)_ln_bottomBarExtension_nocreate; - (_LNPopupBarBackgroundView*)_ln_bottomBarExtension; diff --git a/LNPopupController/LNPopupController/Private/UIViewController+LNPopupSupportPrivate.mm b/LNPopupController/LNPopupController/Private/UIViewController+LNPopupSupportPrivate.mm index dedc2e1..d5bfc0a 100644 --- a/LNPopupController/LNPopupController/Private/UIViewController+LNPopupSupportPrivate.mm +++ b/LNPopupController/LNPopupController/Private/UIViewController+LNPopupSupportPrivate.mm @@ -298,7 +298,7 @@ - (BOOL)_ln_isModalInPresentation - (BOOL)_ln_isObjectFromSwiftUI { static NSString* key = LNPopupHiddenString("_isFromSwiftUI"); - return [self.class respondsToSelector:NSSelectorFromString(key)] && [self.class valueForKey:key]; + return [self.class respondsToSelector:NSSelectorFromString(key)] && [[self.class valueForKey:key] boolValue]; } - (void)_ln_popup_setOverrideUserInterfaceStyle:(UIUserInterfaceStyle)overrideUserInterfaceStyle @@ -796,7 +796,7 @@ - (void)_ln_popup_viewDidLayoutSubviews { if(self.bottomDockingViewForPopup_nocreateOrDeveloper == self._ln_bottomBarSupport_nocreate) { - self._ln_bottomBarSupport_nocreate.frame = self.defaultFrameForBottomDockingView_internalOrDeveloper; + self._ln_bottomBarSupport_nocreate.frame = [self _defaultFrameForBottomDockingViewForPopupBar:self._ln_popupController_nocreate.popupBar]; [self.view bringSubviewToFront:self._ln_bottomBarSupport_nocreate]; self._ln_bottomBarExtension.frame = self._ln_bottomBarSupport_nocreate.frame; @@ -820,6 +820,19 @@ - (void)_ln_popup_viewDidLayoutSubviews { [self _layoutPopupBarOrderForUse]; } + + if(self._ln_popupController_nocreate.popupControllerInternalState != LNPopupPresentationStateBarHidden) + { + UIEdgeInsets neededInsets = UIEdgeInsetsMake(0, 0, MAX(0, self.popupBar.frame.size.height - [self _ln_popupOffsetForPopupBarStyle:self.popupBar.resolvedStyle]), 0); + + UIEdgeInsets safe = _LNPopupSafeAreas(self); + UIEdgeInsets childAdditive = _LNPopupChildAdditiveSafeAreas(self); + + if(neededInsets.bottom != MAX(safe.bottom, childAdditive.bottom)) + { + _LNPopupSupportSetPopupInsetsForViewController(self, YES, neededInsets); + } + } } UIView* extensionView = self._ln_bottomBarExtension_nocreate; @@ -1015,6 +1028,11 @@ - (UIEdgeInsets)insetsForBottomDockingView return self.tabBar.hidden == NO && self._isTabBarHiddenDuringTransition == NO ? UIEdgeInsetsZero : self.view.superview.safeAreaInsets; } +- (CGFloat)_ln_popupOffsetForPopupBarStyle:(LNPopupBarStyle)barStyle +{ + return self._isTabBarHiddenDuringTransition ? [super _ln_popupOffsetForPopupBarStyle:barStyle] : 0; +} + - (CGRect)defaultFrameForBottomDockingView { CGRect bottomBarFrame = self.tabBar.frame; @@ -1420,6 +1438,7 @@ - (void)hBWT:(NSInteger)transition iE:(BOOL)isExplicit d:(NSTimeInterval)duratio self._ln_bottomBarExtension_nocreate.frame = CGRectMake(0, self.view.bounds.size.height - bottomSafeArea, self.view.bounds.size.width, bottomSafeArea); [self _setIgnoringLayoutDuringTransition:NO]; + [self._ln_popupController_nocreate _popupBarMetricsDidChange:self._ln_popupController_nocreate.popupBar]; [self._ln_popupController_nocreate _setContentToState:self._ln_popupController_nocreate.popupControllerInternalState]; self._ln_popupController_nocreate.popupBar.bottomShadowView.hidden = YES; @@ -1593,6 +1612,7 @@ - (void)sBWT:(NSInteger)transition iE:(BOOL)isExplicit d:(NSTimeInterval)duratio self._ln_popupController_nocreate.popupBar.bottomShadowView.hidden = YES; self._ln_popupController_nocreate.popupBar.bottomShadowView.alpha = 1.0; + [self._ln_popupController_nocreate _popupBarMetricsDidChange:self._ln_popupController_nocreate.popupBar]; [self._ln_popupController_nocreate _setContentToState:self._ln_popupController_nocreate.popupControllerInternalState]; [self _layoutPopupBarOrderForUse]; @@ -1669,6 +1689,11 @@ - (nullable UIView *)bottomDockingViewForPopupBar return self.toolbar; } +- (CGFloat)_ln_popupOffsetForPopupBarStyle:(LNPopupBarStyle)barStyle +{ + return self.isToolbarHidden ? [super _ln_popupOffsetForPopupBarStyle:barStyle] : 0; +} + - (CGRect)defaultFrameForBottomDockingView { CGRect toolbarBarFrame = self.toolbar.frame; @@ -1691,14 +1716,15 @@ - (UIEdgeInsets)insetsForBottomDockingView return UIEdgeInsetsZero; } - if(UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad && self.view.superview.safeAreaInsets.bottom > 0 && [self _ln_isObjectFromSwiftUI]) + CGFloat offset = 0; + + if(UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad && self.view.superview.safeAreaInsets.bottom > 0 && ([self _ln_isObjectFromSwiftUI] || self.splitViewController != nil)) { -// NSLog(@"superview: %@ window: %@", @(self.view.superview.safeAreaInsets.bottom), @(self.view.window.safeAreaInsets.bottom)); -// //Something in SwiftUI reports safe area insets incorrectly on iPadOS. This is a workaround for this issue. - return UIEdgeInsetsMake(0, 0, MAX(self.view.superview.safeAreaInsets.bottom, self.view.window.safeAreaInsets.bottom) - 5, 0); + offset -= 5; } - return UIEdgeInsetsMake(0, 0, MAX(self.view.superview.safeAreaInsets.bottom, self.view.window.safeAreaInsets.bottom), 0); + + return UIEdgeInsetsMake(0, 0, MAX(self.view.superview.safeAreaInsets.bottom, self.view.window.safeAreaInsets.bottom) + offset, 0); } + (void)load @@ -1961,6 +1987,7 @@ - (void)_sTH:(BOOL)hidden e:(UIRectEdge)edge d:(NSTimeInterval)duration; [self _layoutPopupBarOrderForTransition]; void (^animations)(void) = ^ { + [self._ln_popupController_nocreate _popupBarMetricsDidChange:self._ln_popupController_nocreate.popupBar]; //During the transition, animate the popup bar and content together with the toolbar transition. [self._ln_popupController_nocreate _setContentToState:self._ln_popupController_nocreate.popupControllerInternalState]; diff --git a/LNPopupControllerExample/LNPopupControllerExample/TestingScene/Base.lproj/Main.storyboard b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/Base.lproj/Main.storyboard index 8681d0a..6e555d5 100644 --- a/LNPopupControllerExample/LNPopupControllerExample/TestingScene/Base.lproj/Main.storyboard +++ b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/Base.lproj/Main.storyboard @@ -114,14 +114,14 @@ - + - + - - - - - + - + - + - - - - - + @@ -177,10 +171,7 @@ - - - - + @@ -200,10 +191,7 @@ - - - - + @@ -436,7 +424,7 @@ - + @@ -451,11 +439,10 @@ - + - @@ -479,7 +466,7 @@ - + @@ -506,7 +493,7 @@ @@ -617,8 +604,10 @@ + + @@ -762,18 +751,14 @@ - - + - + - - - - + diff --git a/LNPopupControllerExample/LNPopupControllerExample/TestingScene/DemoViewController.m b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/DemoViewController.m index 5ef0991..f7525f6 100644 --- a/LNPopupControllerExample/LNPopupControllerExample/TestingScene/DemoViewController.m +++ b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/DemoViewController.m @@ -62,6 +62,9 @@ @implementation DemoViewController __weak IBOutlet UIBarButtonItem *_barStyleButton; __weak IBOutlet UIBarButtonItem *_hideTabBarButton; + __weak IBOutlet UIButton* _showPopupBarButton; + __weak IBOutlet UIButton* _hidePopupBarButton; + BOOL _alreadyPresentedAutomatically; } @@ -122,7 +125,10 @@ - (void)viewDidLoad { if(self.splitViewController != nil) { - self.colorSeedString = [NSString stringWithFormat:@"%@", @(arc4random())]; + UIViewController* indexTarget = self.tabBarController ?: self.navigationController ?: self; + NSInteger idx = 1 - [self.splitViewController.viewControllers indexOfObject:indexTarget]; + + self.colorSeedString = [NSString stringWithFormat:@"split_%@_%@%@ccolors", NSStringFromClass(self.splitViewController.class), @(idx), @(idx)]; } else if(self.tabBarController != nil) { @@ -320,8 +326,28 @@ - (void)updateBottomDockingViewEffectForBarPresentation - (UIViewController*)_targetVCForPopup { + void (^block)(NSString*) = ^ (NSString* title) { + self->_hideTabBarButton.enabled = NO; + if (@available(iOS 16.0, *)) + { + self->_hideTabBarButton.hidden = YES; + } + self->_showPopupBarButton.hidden = YES; + self->_hidePopupBarButton.hidden = YES; + [self.navigationController setToolbarHidden:YES animated:NO]; + + if (@available(iOS 17.0, *)) + { + UIContentUnavailableConfiguration* config = [UIContentUnavailableConfiguration emptyConfiguration]; + config.text = title; + [self setContentUnavailableConfiguration:config]; + } + }; + if([self.splitViewController isKindOfClass:LNSplitViewControllerPrimaryPopup.class] && self.navigationController != [self.splitViewController viewControllerForColumn:UISplitViewControllerColumnPrimary]) { + self.view.backgroundColor = UIColor.systemBackgroundColor; + block(NSLocalizedString(@"Primary", @"")); return nil; } @@ -332,11 +358,9 @@ - (UIViewController*)_targetVCForPopup } if([self.splitViewController isKindOfClass:LNSplitViewControllerSecondaryPopup.class] && [vcs containsObject:[self.splitViewController viewControllerForColumn:UISplitViewControllerColumnPrimary]]) { - return nil; - } - - if([self.splitViewController isKindOfClass:LNSplitViewControllerSecondaryPopup.class] && [vcs containsObject:[self.splitViewController viewControllerForColumn:UISplitViewControllerColumnSupplementary]]) - { + self.view.backgroundColor = UIColor.clearColor; + block(NSLocalizedString(@"Sidebar", @"")); + return nil; } diff --git a/LNPopupControllerExample/LNPopupControllerExample/TestingScene/LNSplitViewController.m b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/LNSplitViewController.m index e048691..58f04f5 100644 --- a/LNPopupControllerExample/LNPopupControllerExample/TestingScene/LNSplitViewController.m +++ b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/LNSplitViewController.m @@ -14,13 +14,16 @@ - (void)viewDidLoad { [super viewDidLoad]; - self.minimumPrimaryColumnWidth = 400; - self.maximumPrimaryColumnWidth = 400; - - if(self.style == UISplitViewControllerStyleTripleColumn) + if([self isKindOfClass:LNSplitViewControllerSecondaryPopup.class] == NO) { - self.minimumSupplementaryColumnWidth = 400; - self.maximumSupplementaryColumnWidth = 400; + self.minimumPrimaryColumnWidth = 400; + self.maximumPrimaryColumnWidth = 400; + + if(self.style == UISplitViewControllerStyleTripleColumn) + { + self.minimumSupplementaryColumnWidth = 400; + self.maximumSupplementaryColumnWidth = 400; + } } }