Skip to content

Commit 7882ad3

Browse files
committed
Improve floating popup bar positioning and layout
1 parent 3443417 commit 7882ad3

File tree

11 files changed

+326
-248
lines changed

11 files changed

+326
-248
lines changed

LNPopupController/LNPopupController.xcodeproj/project.pbxproj

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
39B550182D92D29000B474EC /* _LNPopupTransitionGenericCloseAnimator.h in Headers */ = {isa = PBXBuildFile; fileRef = 39B550032D92D29000B474EC /* _LNPopupTransitionGenericCloseAnimator.h */; };
8181
39B550192D92D29000B474EC /* _LNPopupTransitionPreferredCloseAnimator.h in Headers */ = {isa = PBXBuildFile; fileRef = 39B550092D92D29000B474EC /* _LNPopupTransitionPreferredCloseAnimator.h */; };
8282
39B5501A2D92D29000B474EC /* _LNPopupTransitionGenericOpenAnimator.h in Headers */ = {isa = PBXBuildFile; fileRef = 39B550052D92D29000B474EC /* _LNPopupTransitionGenericOpenAnimator.h */; };
83+
39C39F422DA3DB96007630FD /* LNPopupBarExtras.mm in Sources */ = {isa = PBXBuildFile; fileRef = 39C39F412DA3DB90007630FD /* LNPopupBarExtras.mm */; };
8384
39C553DF2D8F2B3200F8D8B2 /* _LNPopupTransitionView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 39C553DE2D8F2B3200F8D8B2 /* _LNPopupTransitionView.mm */; };
8485
39C553E02D8F2B3200F8D8B2 /* _LNPopupTransitionView.h in Headers */ = {isa = PBXBuildFile; fileRef = 39C553DD2D8F2B3200F8D8B2 /* _LNPopupTransitionView.h */; };
8586
39C553E32D91925300F8D8B2 /* LNPopupImageView+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 39C553E22D91924900F8D8B2 /* LNPopupImageView+Private.h */; };
@@ -169,6 +170,7 @@
169170
39B5500A2D92D29000B474EC /* _LNPopupTransitionPreferredCloseAnimator.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = _LNPopupTransitionPreferredCloseAnimator.mm; sourceTree = "<group>"; };
170171
39B5500B2D92D29000B474EC /* _LNPopupTransitionPreferredOpenAnimator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _LNPopupTransitionPreferredOpenAnimator.h; sourceTree = "<group>"; };
171172
39B5500C2D92D29000B474EC /* _LNPopupTransitionPreferredOpenAnimator.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = _LNPopupTransitionPreferredOpenAnimator.mm; sourceTree = "<group>"; };
173+
39C39F412DA3DB90007630FD /* LNPopupBarExtras.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = LNPopupBarExtras.mm; sourceTree = "<group>"; };
172174
39C553DD2D8F2B3200F8D8B2 /* _LNPopupTransitionView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _LNPopupTransitionView.h; sourceTree = "<group>"; };
173175
39C553DE2D8F2B3200F8D8B2 /* _LNPopupTransitionView.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = _LNPopupTransitionView.mm; sourceTree = "<group>"; };
174176
39C553E22D91924900F8D8B2 /* LNPopupImageView+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "LNPopupImageView+Private.h"; sourceTree = "<group>"; };
@@ -202,6 +204,10 @@
202204
39E7A603200B5157007AF3AD /* _LNPopupSwizzlingUtils.m */,
203205
394A85BF1B630992004FFC61 /* _LNWeakRef.h */,
204206
394A85C01B630992004FFC61 /* _LNWeakRef.m */,
207+
39AC478F26C69AC9001D53C2 /* LNMath.h */,
208+
39AC479026C69AC9001D53C2 /* LNMath.m */,
209+
39A0DDB126F7894700E5D751 /* NSAttributedString+LNPopupSupport.h */,
210+
39A0DDB226F7894700E5D751 /* NSAttributedString+LNPopupSupport.m */,
205211
397AFBFE1F1A216400E7D95C /* GestureRecognizers */,
206212
391481B91DCFA514002416D1 /* LNChevronView.h */,
207213
391481B81DCFA514002416D1 /* LNChevronView.m */,
@@ -216,6 +222,7 @@
216222
39C553DD2D8F2B3200F8D8B2 /* _LNPopupTransitionView.h */,
217223
39C553DE2D8F2B3200F8D8B2 /* _LNPopupTransitionView.mm */,
218224
3947E1B81B6300370001178B /* LNPopupBar+Private.h */,
225+
39C39F412DA3DB90007630FD /* LNPopupBarExtras.mm */,
219226
3947E1A41B61CD650001178B /* LNPopupBar.mm */,
220227
393E4EAC26713E5700929E47 /* LNPopupBarAppearance+Private.h */,
221228
393E4EA52670F12500929E47 /* LNPopupBarAppearance.mm */,
@@ -245,10 +252,6 @@
245252
3947E1A01B61CD1F0001178B /* UIViewController+LNPopupSupport.mm */,
246253
394A85C71B63FB96004FFC61 /* UIViewController+LNPopupSupportPrivate.h */,
247254
394A85C81B63FE52004FFC61 /* UIViewController+LNPopupSupportPrivate.mm */,
248-
39AC478F26C69AC9001D53C2 /* LNMath.h */,
249-
39AC479026C69AC9001D53C2 /* LNMath.m */,
250-
39A0DDB126F7894700E5D751 /* NSAttributedString+LNPopupSupport.h */,
251-
39A0DDB226F7894700E5D751 /* NSAttributedString+LNPopupSupport.m */,
252255
);
253256
name = Implementation;
254257
path = Private;
@@ -484,6 +487,7 @@
484487
393E4EA72670F12500929E47 /* LNPopupBarAppearance.mm in Sources */,
485488
39B5500D2D92D29000B474EC /* _LNPopupTransitionAnimator.mm in Sources */,
486489
39B5500E2D92D29000B474EC /* _LNPopupTransitionCloseAnimator.m in Sources */,
490+
39C39F422DA3DB96007630FD /* LNPopupBarExtras.mm in Sources */,
487491
39B5500F2D92D29000B474EC /* _LNPopupTransitionOpenAnimator.m in Sources */,
488492
39B550102D92D29000B474EC /* _LNPopupTransitionPreferredOpenAnimator.mm in Sources */,
489493
39B550112D92D29000B474EC /* _LNPopupTransitionPreferredCloseAnimator.mm in Sources */,

LNPopupController/LNPopupController/Private/LNPopupBar+Private.h

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#import "_LNPopupBarBackgroundView.h"
1313
#import "_LNPopupBackgroundShadowView.h"
1414
#import "_LNPopupBarBackgroundMaskView.h"
15+
#import "MarqueeLabel.h"
1516

1617
CF_EXTERN_C_BEGIN
1718

@@ -143,4 +144,64 @@ inline __attribute__((always_inline)) LNPopupBarStyle _LNPopupResolveBarStyleFro
143144

144145
@end
145146

147+
@protocol _LNPopupToolbarLayoutDelegate <NSObject>
148+
149+
- (void)_toolbarDidLayoutSubviews;
150+
151+
@end
152+
153+
@interface LNPopupBar () <_LNPopupToolbarLayoutDelegate>
154+
155+
- (void)_windowWillRotate:(NSNotification*)note;
156+
- (void)_windowDidRotate:(NSNotification*)note;
157+
- (UIFont*)_titleFont;
158+
- (UIColor*)_titleColor;
159+
- (UIFont*)_subtitleFont;
160+
- (UIColor*)_subtitleColor;
161+
162+
@end
163+
164+
@protocol LNMarqueeLabel <NSObject>
165+
166+
- (void)resetLabel;
167+
- (void)unpauseLabel;
168+
- (void)pauseLabel;
169+
- (void)restartLabel;
170+
- (BOOL)isPaused;
171+
- (void)shutdownLabel;
172+
173+
@property (nonatomic, assign) CGFloat rate;
174+
@property (nonatomic, assign) CGFloat animationDelay;
175+
@property (nonatomic, weak) MarqueeLabel* synchronizedLabel;
176+
@property (nonatomic, readonly) NSTimeInterval animationDuration;
177+
@property (nonatomic, assign) BOOL holdScrolling;
178+
179+
@end
180+
181+
@interface _LNPopupBarContentView : _LNPopupBarBackgroundView @end
182+
183+
@interface _LNPopupBarTitlesView : UIStackView @end
184+
185+
@interface _LNPopupToolbar : UIToolbar
186+
187+
@property (nonatomic, weak) id<_LNPopupToolbarLayoutDelegate> _layoutDelegate;
188+
189+
@end
190+
191+
@interface _LNPopupTitleLabelWrapper: UIView
192+
193+
+ (instancetype)wrapperForLabel:(UILabel*)wrapped;
194+
195+
@property (nonatomic, strong) UILabel* wrapped;
196+
@property (nonatomic, strong) NSLayoutConstraint* wrappedWidthConstraint;
197+
198+
@end
199+
200+
@interface _LNPopupBarShadowView : UIImageView @end
201+
202+
@interface LNNonMarqueeLabel : UILabel <LNMarqueeLabel> @end
203+
204+
@interface MarqueeLabel () <LNMarqueeLabel> @end
205+
206+
146207
CF_EXTERN_C_END

LNPopupController/LNPopupController/Private/LNPopupBar.mm

Lines changed: 18 additions & 208 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@
1515
#import "LNPopupImageView+Private.h"
1616
#import "UIView+LNPopupSupportPrivate.h"
1717

18+
const CGFloat LNPopupBarHeightCompact = 40.0;
19+
const CGFloat LNPopupBarHeightProminent = 64.0;
20+
const CGFloat LNPopupBarHeightFloating = 64.0;
21+
const CGFloat LNPopupBarProminentImageWidth = 48.0;
22+
const CGFloat LNPopupBarFloatingImageWidth = 40.0;
23+
const CGFloat LNPopupBarFloatingPadImageWidth = 44.0;
24+
const CGFloat LNPopupBarFloatingPadWidthLimit = 954.0;
25+
1826
#ifdef DEBUG
1927
#import "LNPopupDebug.h"
2028

@@ -65,214 +73,6 @@ CGFloat _LNPopupBarHeightForPopupBar(LNPopupBar* popupBar)
6573
}
6674
}
6775

68-
#ifndef LNPopupControllerEnforceStrictClean
69-
static SEL _effectWithStyle_tintColor_invertAutomaticStyle_SEL;
70-
static id(*_effectWithStyle_tintColor_invertAutomaticStyle)(id, SEL, NSUInteger, UIColor*, BOOL);
71-
72-
__attribute__((constructor))
73-
static void __setupFunction(void)
74-
{
75-
_effectWithStyle_tintColor_invertAutomaticStyle_SEL = NSSelectorFromString(LNPopupHiddenString("_effectWithStyle:tintColor:invertAutomaticStyle:"));
76-
Method m = class_getClassMethod(UIBlurEffect.class, _effectWithStyle_tintColor_invertAutomaticStyle_SEL);
77-
_effectWithStyle_tintColor_invertAutomaticStyle = reinterpret_cast<decltype(_effectWithStyle_tintColor_invertAutomaticStyle)>(method_getImplementation(m));
78-
}
79-
#endif
80-
81-
@interface _LNPopupBarContentView : _LNPopupBarBackgroundView @end
82-
@implementation _LNPopupBarContentView @end
83-
84-
@interface _LNPopupBarTitlesView : UIStackView @end
85-
@implementation _LNPopupBarTitlesView @end
86-
87-
@interface _LNPopupTitleLabelWrapper: UIView
88-
89-
@property (nonatomic, strong) UILabel* wrapped;
90-
@property (nonatomic, strong) NSLayoutConstraint* wrappedWidthConstraint;
91-
92-
@end
93-
94-
@implementation _LNPopupTitleLabelWrapper
95-
96-
+ (instancetype)wrapperForLabel:(UILabel*)wrapped
97-
{
98-
_LNPopupTitleLabelWrapper* rv = [[_LNPopupTitleLabelWrapper alloc] initWithFrame:wrapped.frame];
99-
rv.wrapped = wrapped;
100-
101-
rv.translatesAutoresizingMaskIntoConstraints = wrapped.translatesAutoresizingMaskIntoConstraints;
102-
[rv addSubview:wrapped];
103-
104-
rv.wrappedWidthConstraint = [wrapped.widthAnchor constraintEqualToConstant:rv.bounds.size.width];
105-
106-
[NSLayoutConstraint activateConstraints:@[
107-
[rv.leadingAnchor constraintEqualToAnchor:wrapped.leadingAnchor],
108-
[rv.heightAnchor constraintEqualToAnchor:wrapped.heightAnchor],
109-
rv->_wrappedWidthConstraint
110-
]];
111-
112-
return rv;
113-
}
114-
115-
- (void)setBounds:(CGRect)bounds
116-
{
117-
[super setBounds:bounds];
118-
119-
if(_wrappedWidthConstraint.constant == bounds.size.width)
120-
{
121-
return;
122-
}
123-
124-
if(UIView.inheritedAnimationDuration == 0.0)
125-
{
126-
_wrappedWidthConstraint.constant = bounds.size.width;
127-
[_wrapped layoutSubviews];
128-
}
129-
else
130-
{
131-
[UIView transitionWithView:_wrapped
132-
duration:UIView.inheritedAnimationDuration / 2.0
133-
options:UIViewAnimationOptionTransitionCrossDissolve | UIViewAnimationOptionCurveEaseOut
134-
animations:^{
135-
_wrappedWidthConstraint.constant = bounds.size.width;
136-
[_wrapped layoutSubviews];
137-
} completion:nil];
138-
}
139-
}
140-
141-
@end
142-
143-
@interface _LNPopupBarShadowView : UIImageView @end
144-
@implementation _LNPopupBarShadowView
145-
146-
#if DEBUG
147-
148-
- (void)setAlpha:(CGFloat)alpha
149-
{
150-
[super setAlpha:alpha];
151-
}
152-
153-
- (void)setHidden:(BOOL)hidden
154-
{
155-
[super setHidden:hidden];
156-
}
157-
158-
#endif
159-
160-
@end
161-
162-
@protocol _LNPopupToolbarLayoutDelegate <NSObject>
163-
164-
- (void)_toolbarDidLayoutSubviews;
165-
166-
@end
167-
168-
@interface _LNPopupToolbar : UIToolbar
169-
170-
@property (nonatomic, weak) id<_LNPopupToolbarLayoutDelegate> _layoutDelegate;
171-
172-
@end
173-
@implementation _LNPopupToolbar
174-
175-
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
176-
{
177-
UIView* rv = [super hitTest:point withEvent:event];
178-
179-
if(rv != nil && [rv isKindOfClass:UIControl.class] == NO && [NSStringFromClass(rv.class) containsString:@"BarItemView"] == NO)
180-
{
181-
rv = nil;
182-
}
183-
184-
return rv;
185-
}
186-
187-
- (void)layoutSubviews
188-
{
189-
[super layoutSubviews];
190-
191-
//On iOS 11 and above reset the semantic content attribute to make sure it propagades to all subviews.
192-
[self setSemanticContentAttribute:self.semanticContentAttribute];
193-
194-
[self._layoutDelegate _toolbarDidLayoutSubviews];
195-
}
196-
197-
- (void)_deepSetSemanticContentAttribute:(UISemanticContentAttribute)semanticContentAttribute toView:(UIView*)view startingFromView:(UIView*)staringView;
198-
{
199-
if(view == staringView)
200-
{
201-
[super setSemanticContentAttribute:semanticContentAttribute];
202-
}
203-
else
204-
{
205-
[view setSemanticContentAttribute:semanticContentAttribute];
206-
}
207-
208-
[view.subviews enumerateObjectsUsingBlock:^(__kindof UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
209-
[self _deepSetSemanticContentAttribute:semanticContentAttribute toView:obj startingFromView:staringView];
210-
}];
211-
}
212-
213-
- (void)setSemanticContentAttribute:(UISemanticContentAttribute)semanticContentAttribute
214-
{
215-
//On iOS 11, due to a bug in UIKit, the semantic content attribute must be propagaded recursively to all subviews, so that the system behaves correctly.
216-
[self _deepSetSemanticContentAttribute:semanticContentAttribute toView:self startingFromView:self];
217-
}
218-
219-
@end
220-
221-
@protocol LNMarqueeLabel <NSObject>
222-
223-
- (void)resetLabel;
224-
- (void)unpauseLabel;
225-
- (void)pauseLabel;
226-
- (void)restartLabel;
227-
- (BOOL)isPaused;
228-
- (void)shutdownLabel;
229-
230-
@property (nonatomic, assign) CGFloat rate;
231-
@property (nonatomic, assign) CGFloat animationDelay;
232-
@property (nonatomic, weak) MarqueeLabel* synchronizedLabel;
233-
@property (nonatomic, readonly) NSTimeInterval animationDuration;
234-
@property (nonatomic, assign) BOOL holdScrolling;
235-
236-
@end
237-
238-
@interface LNNonMarqueeLabel : UILabel <LNMarqueeLabel> @end
239-
@implementation LNNonMarqueeLabel
240-
241-
- (void)resetLabel {}
242-
- (void)unpauseLabel {}
243-
- (void)pauseLabel {}
244-
- (void)restartLabel {}
245-
- (void)shutdownLabel {}
246-
- (BOOL)isPaused { return YES; }
247-
- (NSTimeInterval)animationDuration { return 0.0; }
248-
249-
@synthesize rate=_rate, animationDelay=_animationDelay, synchronizedLabel=_synchronizedLabel, holdScrolling=_holdScrolling;
250-
251-
@end
252-
253-
@interface MarqueeLabel () <LNMarqueeLabel> @end
254-
255-
const CGFloat LNPopupBarHeightCompact = 40.0;
256-
const CGFloat LNPopupBarHeightProminent = 64.0;
257-
const CGFloat LNPopupBarHeightFloating = 64.0;
258-
const CGFloat LNPopupBarProminentImageWidth = 48.0;
259-
const CGFloat LNPopupBarFloatingImageWidth = 40.0;
260-
const CGFloat LNPopupBarFloatingPadImageWidth = 44.0;
261-
const CGFloat LNPopupBarFloatingPadWidthLimit = 954.0;
262-
263-
static BOOL __animatesItemSetter = NO;
264-
265-
@interface LNPopupBar () <_LNPopupToolbarLayoutDelegate>
266-
267-
- (void)_windowWillRotate:(NSNotification*)note;
268-
- (void)_windowDidRotate:(NSNotification*)note;
269-
- (UIFont*)_titleFont;
270-
- (UIColor*)_titleColor;
271-
- (UIFont*)_subtitleFont;
272-
- (UIColor*)_subtitleColor;
273-
274-
@end
275-
27676
__attribute__((objc_direct_members))
27777
@implementation LNPopupBar
27878
{
@@ -300,6 +100,7 @@ @implementation LNPopupBar
300100
UIWindow* _swiftHacksWindow2;
301101
}
302102

103+
static BOOL __animatesItemSetter = NO;
303104
+ (void)setAnimatesItemSetter:(BOOL)animate
304105
{
305106
__animatesItemSetter = animate;
@@ -538,6 +339,15 @@ - (nonnull instancetype)initWithFrame:(CGRect)frame
538339
return self;
539340
}
540341

342+
#if DEBUG
343+
344+
- (void)setFrame:(CGRect)frame
345+
{
346+
[super setFrame:frame];
347+
}
348+
349+
#endif
350+
541351
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
542352
{
543353
[super traitCollectionDidChange:previousTraitCollection];

0 commit comments

Comments
 (0)