Skip to content

Commit b2f7f48

Browse files
author
molicechen
committed
4.7.0
1 parent cc0c1d6 commit b2f7f48

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+632
-163
lines changed

QMUIConfigurationTemplate/QMUIConfigurationTemplate.m

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,6 @@ - (void)applyConfigurationTemplate {
284284
QMUICMI.shouldFixTabBarSafeAreaInsetsBug = NO; // ShouldFixTabBarSafeAreaInsetsBug : 是否要对 iOS 11 及以后的版本修复当存在 UITabBar 时,UIScrollView 的 inset.bottom 可能错误的 bug(issue #218 #934),默认为 YES
285285
QMUICMI.shouldFixSearchBarMaskViewLayoutBug = NO; // ShouldFixSearchBarMaskViewLayoutBug : 是否自动修复 UISearchController.searchBar 被当作 tableHeaderView 使用时可能出现的布局 bug(issue #950)
286286
QMUICMI.shouldPrintQMUIWarnLogToConsole = IS_DEBUG; // ShouldPrintQMUIWarnLogToConsole : 是否在出现 QMUILogWarn 时自动把这些 log 以 QMUIConsole 的方式显示到设备屏幕上
287-
QMUICMI.sendAnalyticsToQMUITeam = YES; // SendAnalyticsToQMUITeam : 是否允许在 DEBUG 模式下上报 Bundle Identifier 和 Display Name 给 QMUI 统计用
288287
QMUICMI.dynamicPreferredValueForIPad = NO; // DynamicPreferredValueForIPad : 当 iPad 处于 Slide Over 或 Split View 分屏模式下,宏 `PreferredValueForXXX` 是否把 iPad 视为某种屏幕宽度近似的 iPhone 来取值。
289288
QMUICMI.ignoreKVCAccessProhibited = NO; // IgnoreKVCAccessProhibited : 是否全局忽略 iOS 13 对 KVC 访问 UIKit 私有属性的限制
290289
QMUICMI.adjustScrollIndicatorInsetsByContentInsetAdjustment = NO; // AdjustScrollIndicatorInsetsByContentInsetAdjustment : 当将 UIScrollView.contentInsetAdjustmentBehavior 设为 UIScrollViewContentInsetAdjustmentNever 时,是否自动将 UIScrollView.automaticallyAdjustsScrollIndicatorInsets 设为 NO,以保证原本在 iOS 12 下的代码不用修改就能在 iOS 13 下正常控制滚动条的位置。

QMUIKit.podspec

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
Pod::Spec.new do |s|
22
s.name = "QMUIKit"
3-
s.version = "4.6.3"
3+
s.version = "4.7.0"
44
s.summary = "致力于提高项目 UI 开发效率的解决方案"
55
s.description = <<-DESC
66
QMUI iOS 是一个致力于提高项目 UI 开发效率的解决方案,其设计目的是用于辅助快速搭建一个具备基本设计还原效果的 iOS 项目,同时利用自身提供的丰富控件及兼容处理, 让开发者能专注于业务需求而无需耗费精力在基础代码的设计上。不管是新项目的创建,或是已有项目的维护,均可使开发效率和项目质量得到大幅度提升。
77
DESC
8-
s.homepage = "https://qmuiteam.com/ios"
8+
s.homepage = "https://github.com/Tencent/QMUI_iOS"
99
s.license = 'MIT'
1010
s.author = {"qmuiteam" => "[email protected]"}
1111
s.source = {:git => "https://github.com/Tencent/QMUI_iOS.git", :tag => s.version.to_s}
1212
#s.source = {:git => "https://github.com/Tencent/QMUI_iOS.git", :branch => 'master'}
1313
s.social_media_url = 'https://github.com/Tencent/QMUI_iOS'
1414
s.requires_arc = true
15-
s.documentation_url = 'https://qmuiteam.com/ios/page/document.html'
15+
s.documentation_url = 'https://github.com/Tencent/QMUI_iOS'
1616
s.screenshot = 'https://cloud.githubusercontent.com/assets/1190261/26751376/63f96538-486a-11e7-81cf-5bc83a945207.png'
1717

1818
s.platform = :ios, '13.0'

QMUIKit/QMUIComponents/ImagePickerLibrary/QMUIImagePickerViewController.m

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,16 @@ - (void)viewWillAppear:(BOOL)animated {
122122
[self.collectionView reloadData];
123123
}
124124

125+
- (void)viewWillDisappear:(BOOL)animated {
126+
[super viewWillDisappear:animated];
127+
128+
// 在 pop 回相簿列表时重置标志位以使下次进来 picker 时 collection 可以滚动到正确的初始位置
129+
// 但不能影响从 picker 进入大图的路径
130+
if (self.navigationController && ![self.navigationController.viewControllers containsObject:self]) {
131+
self.hasScrollToInitialPosition = NO;
132+
}
133+
}
134+
125135
- (void)showEmptyView {
126136
[super showEmptyView];
127137
self.emptyView.backgroundColor = self.view.backgroundColor; // 为了盖住背后的 collectionView,这里加个背景色(不盖住的话会看到 collectionView 先滚到列表顶部然后跳到列表底部)
@@ -244,10 +254,6 @@ - (void)scrollToInitialPositionIfNeeded {
244254
}
245255
}
246256

247-
- (void)willPopInNavigationControllerWithAnimated:(BOOL)animated {
248-
self.hasScrollToInitialPosition = NO;
249-
}
250-
251257
#pragma mark - Getters & Setters
252258

253259
@synthesize collectionViewLayout = _collectionViewLayout;

QMUIKit/QMUIComponents/NavigationBarTransition/UINavigationBar+Transition.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,13 @@
2323

2424
@interface _QMUITransitionNavigationBar : UINavigationBar
2525

26+
@property(nonatomic, weak) UIViewController *parentViewController;
27+
2628
// 建立假 bar 到真 bar 的关系,内部会通过 qmuinb_copyStylesToBar 同时设置真 bar 到假 bar 的关系
2729
@property(nonatomic, weak) UINavigationBar *originalNavigationBar;
30+
2831
@property(nonatomic, assign) BOOL shouldPreventAppearance;
32+
33+
// 根据当前的系统导航栏布局,刷新自身在 vc.view 上的布局
34+
- (void)updateLayout;
2935
@end

QMUIKit/QMUIComponents/NavigationBarTransition/UINavigationBar+Transition.m

Lines changed: 72 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -26,32 +26,63 @@ + (void)load {
2626
static dispatch_once_t onceToken;
2727
dispatch_once(&onceToken, ^{
2828

29-
#ifdef IOS15_SDK_ALLOWED
3029
if (@available(iOS 15.0, *)) {
31-
ExtendImplementationOfVoidMethodWithSingleArgument([UINavigationBar class], @selector(setStandardAppearance:), UINavigationBarAppearance *, ^(UINavigationBar *selfObject, UINavigationBarAppearance *appearance) {
32-
if (selfObject.qmuinb_copyStylesToBar) {
33-
selfObject.qmuinb_copyStylesToBar.standardAppearance = appearance;
34-
}
30+
31+
OverrideImplementation([UINavigationBar class], @selector(setStandardAppearance:), ^id(__unsafe_unretained Class originClass, SEL originCMD, IMP (^originalIMPProvider)(void)) {
32+
return ^(UINavigationBar *selfObject, UINavigationBarAppearance *appearance) {
33+
34+
// call super
35+
void (*originSelectorIMP)(id, SEL, UINavigationBarAppearance *);
36+
originSelectorIMP = (void (*)(id, SEL, UINavigationBarAppearance *))originalIMPProvider();
37+
originSelectorIMP(selfObject, originCMD, appearance);
38+
39+
if (selfObject.qmuinb_copyStylesToBar) {
40+
selfObject.qmuinb_copyStylesToBar.standardAppearance = appearance;
41+
}
42+
};
3543
});
3644

37-
ExtendImplementationOfVoidMethodWithSingleArgument([UINavigationBar class], @selector(setScrollEdgeAppearance:), UINavigationBarAppearance *, ^(UINavigationBar *selfObject, UINavigationBarAppearance *appearance) {
38-
if (selfObject.qmuinb_copyStylesToBar) {
39-
selfObject.qmuinb_copyStylesToBar.scrollEdgeAppearance = appearance;
40-
}
45+
OverrideImplementation([UINavigationBar class], @selector(setScrollEdgeAppearance:), ^id(__unsafe_unretained Class originClass, SEL originCMD, IMP (^originalIMPProvider)(void)) {
46+
return ^(UINavigationBar *selfObject, UINavigationBarAppearance *appearance) {
47+
48+
// call super
49+
void (*originSelectorIMP)(id, SEL, UINavigationBarAppearance *);
50+
originSelectorIMP = (void (*)(id, SEL, UINavigationBarAppearance *))originalIMPProvider();
51+
originSelectorIMP(selfObject, originCMD, appearance);
52+
53+
if (selfObject.qmuinb_copyStylesToBar) {
54+
selfObject.qmuinb_copyStylesToBar.standardAppearance = appearance;
55+
}
56+
};
4157
});
4258
}
43-
#endif
4459

45-
ExtendImplementationOfVoidMethodWithSingleArgument([UINavigationBar class], @selector(setBarStyle:), UIBarStyle, ^(UINavigationBar *selfObject, UIBarStyle barStyle) {
46-
if (selfObject.qmuinb_copyStylesToBar && selfObject.qmuinb_copyStylesToBar.barStyle != barStyle) {
47-
selfObject.qmuinb_copyStylesToBar.barStyle = barStyle;
48-
}
60+
OverrideImplementation([UINavigationBar class], @selector(setBarStyle:), ^id(__unsafe_unretained Class originClass, SEL originCMD, IMP (^originalIMPProvider)(void)) {
61+
return ^(UINavigationBar *selfObject, UIBarStyle barStyle) {
62+
63+
// call super
64+
void (*originSelectorIMP)(id, SEL, UIBarStyle);
65+
originSelectorIMP = (void (*)(id, SEL, UIBarStyle))originalIMPProvider();
66+
originSelectorIMP(selfObject, originCMD, barStyle);
67+
68+
if (selfObject.qmuinb_copyStylesToBar && selfObject.qmuinb_copyStylesToBar.barStyle != barStyle) {
69+
selfObject.qmuinb_copyStylesToBar.barStyle = barStyle;
70+
}
71+
};
4972
});
5073

51-
ExtendImplementationOfVoidMethodWithSingleArgument([UINavigationBar class], @selector(setBarTintColor:), UIColor *, ^(UINavigationBar *selfObject, UIColor *barTintColor) {
52-
if (selfObject.qmuinb_copyStylesToBar && ![selfObject.qmuinb_copyStylesToBar.barTintColor isEqual:barTintColor]) {
53-
selfObject.qmuinb_copyStylesToBar.barTintColor = barTintColor;
54-
}
74+
OverrideImplementation([UINavigationBar class], @selector(setBarTintColor:), ^id(__unsafe_unretained Class originClass, SEL originCMD, IMP (^originalIMPProvider)(void)) {
75+
return ^(UINavigationBar *selfObject, UIColor *barTintColor) {
76+
77+
// call super
78+
void (*originSelectorIMP)(id, SEL, UIColor *);
79+
originSelectorIMP = (void (*)(id, SEL, UIColor *))originalIMPProvider();
80+
originSelectorIMP(selfObject, originCMD, barTintColor);
81+
82+
if (selfObject.qmuinb_copyStylesToBar && ![selfObject.qmuinb_copyStylesToBar.barTintColor isEqual:barTintColor]) {
83+
selfObject.qmuinb_copyStylesToBar.barTintColor = barTintColor;
84+
}
85+
};
5586
});
5687

5788
OverrideImplementation([UINavigationBar class], @selector(setBackgroundImage:forBarMetrics:), ^id(__unsafe_unretained Class originClass, SEL originCMD, IMP (^originalIMPProvider)(void)) {
@@ -68,10 +99,18 @@ + (void)load {
6899
};
69100
});
70101

71-
ExtendImplementationOfVoidMethodWithSingleArgument([UINavigationBar class], @selector(setShadowImage:), UIImage *, ^(UINavigationBar *selfObject, UIImage *firstArgv) {
72-
if (selfObject.qmuinb_copyStylesToBar) {
73-
selfObject.qmuinb_copyStylesToBar.shadowImage = firstArgv;
74-
}
102+
OverrideImplementation([UINavigationBar class], @selector(setShadowImage:), ^id(__unsafe_unretained Class originClass, SEL originCMD, IMP (^originalIMPProvider)(void)) {
103+
return ^(UINavigationBar *selfObject, UIImage *shadowImage) {
104+
105+
// call super
106+
void (*originSelectorIMP)(id, SEL, UIImage *);
107+
originSelectorIMP = (void (*)(id, SEL, UIImage *))originalIMPProvider();
108+
originSelectorIMP(selfObject, originCMD, shadowImage);
109+
110+
if (selfObject.qmuinb_copyStylesToBar) {
111+
selfObject.qmuinb_copyStylesToBar.shadowImage = shadowImage;
112+
}
113+
};
75114
});
76115

77116
OverrideImplementation([UINavigationBar class], @selector(setQmui_effect:), ^id(__unsafe_unretained Class originClass, SEL originCMD, IMP (^originalIMPProvider)(void)) {
@@ -211,6 +250,8 @@ - (void)setOriginalNavigationBar:(UINavigationBar *)originBar {
211250
// 只复制当前 originBar 的样式,所以复制完立马就清空
212251
originBar.qmuinb_copyStylesToBar = self;
213252
originBar.qmuinb_copyStylesToBar = nil;
253+
254+
[self updateLayout];
214255
}
215256

216257
- (void)layoutSubviews {
@@ -228,4 +269,13 @@ - (void)didAddSubview:(UIView *)subview {
228269
}
229270
}
230271

272+
- (void)updateLayout {
273+
if ([self.parentViewController isViewLoaded] && self.originalNavigationBar) {
274+
[self.parentViewController.view bringSubviewToFront:self];
275+
UIView *backgroundView = self.originalNavigationBar.qmui_backgroundView;
276+
CGRect rect = [backgroundView.superview convertRect:backgroundView.frame toView:self.parentViewController.view];
277+
self.frame = CGRectSetX(rect, 0);// push/pop 过程中系统的导航栏转换过来的 x 可能是 112、-112
278+
}
279+
}
280+
231281
@end

QMUIKit/QMUIComponents/NavigationBarTransition/UINavigationController+NavigationBarTransition.m

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ + (void)load {
113113
switch (action) {
114114
case QMUINavigationActionDidPush:
115115
case QMUINavigationActionWillPop:
116-
case QMUINavigationActionWillSet: {
116+
case QMUINavigationActionDidSet: {
117117
BOOL shouldCustomNavigationBarTransition =
118118
[weakNavigationController shouldCustomTransitionAutomaticallyForOperation:UINavigationControllerOperationPush firstViewController:disappearingViewController secondViewController:appearingViewController];
119119
if (shouldCustomNavigationBarTransition) {
@@ -173,9 +173,7 @@ + (void)load {
173173

174174
OverrideImplementation([UIViewController class], @selector(viewWillLayoutSubviews), ^id(__unsafe_unretained Class originClass, SEL originCMD, IMP (^originalIMPProvider)(void)) {
175175
return ^(UIViewController *selfObject) {
176-
if (selfObject.transitionNavigationBar) {
177-
[selfObject layoutTransitionNavigationBar];
178-
}
176+
[selfObject.transitionNavigationBar updateLayout];
179177

180178
// call super
181179
void (*originSelectorIMP)(id, SEL);
@@ -233,24 +231,26 @@ - (void)addTransitionNavigationBarAndBindNavigationBar:(BOOL)shouldBind {
233231
}
234232

235233
_QMUITransitionNavigationBar *customBar = [[_QMUITransitionNavigationBar alloc] init];
234+
customBar.parentViewController = self;
236235
self.transitionNavigationBar = customBar;
237236

238237
// iOS 15 里,假 bar 在 add 到界面上时会被强制同步为 UIAppearance 的值,不管你之前是否设置过自己的样式。而且在那个 runloop 内不管你后续怎么更新 standardAppearance,都会呈现出 UIAppearance 里的统一的值的样式。所以这里一方面屏蔽 didMoveToWindow,从而避免在这时候应用 UIAppearance,另一方面要保证先 add 到界面上再同步当前导航栏的样式。
239-
// 经测试只有 push 时需要这么处理,pop 没问题
238+
// 经测试只有 push 或 push 动画的 set 需要这么处理,pop 及 pop 动画的 set 没问题
240239
// iOS 14 及以下没这种问题。
241-
#ifdef IOS15_SDK_ALLOWED
240+
// https://github.com/Tencent/QMUI_iOS/issues/1501
242241
if (@available(iOS 15.0, *)) {
243-
if (self.navigationController.qmui_navigationAction == QMUINavigationActionDidPush) {
242+
BOOL isPush = self.navigationController.qmui_navigationAction == QMUINavigationActionDidPush;
243+
BOOL isSet = self.navigationController.qmui_navigationAction == QMUINavigationActionDidSet;
244+
BOOL isPopAnimation = isSet && self.navigationController.qmui_lastOperation == UINavigationControllerOperationPop;
245+
if (isPush || (isSet && !isPopAnimation)) {
244246
customBar.shouldPreventAppearance = YES;
245247
}
246248
}
247-
#endif
248249
[self.view addSubview:customBar];
249250
customBar.originalNavigationBar = self.navigationController.navigationBar;// 注意这里内部不会保留真 bar 和假 bar 的 copy 关系
250251
if (shouldBind) {
251252
self.navigationController.navigationBar.qmuinb_copyStylesToBar = customBar;
252253
}
253-
[self layoutTransitionNavigationBar];
254254
}
255255

256256
- (void)removeTransitionNavigationBar {
@@ -264,15 +264,6 @@ - (void)removeTransitionNavigationBar {
264264
}
265265
}
266266

267-
- (void)layoutTransitionNavigationBar {
268-
if (self.isViewLoaded && self.navigationController) {
269-
UIView *backgroundView = self.navigationController.navigationBar.qmui_backgroundView;
270-
CGRect rect = [backgroundView.superview convertRect:backgroundView.frame toView:self.view];
271-
self.transitionNavigationBar.frame = CGRectSetX(rect, 0);// push/pop 过程中系统的导航栏转换过来的 x 可能是 112、-112
272-
[self.view bringSubviewToFront:self.transitionNavigationBar];// 避免在后续被其他 subviews 盖住
273-
}
274-
}
275-
276267
#pragma mark - 工具方法
277268

278269
// 根据当前的viewController,统一处理导航栏的显隐、样式

QMUIKit/QMUIComponents/QMUIAlertController.m

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -759,7 +759,7 @@ - (void)viewDidLayoutSubviews {
759759
}
760760
// 把上下的margin都加上用于跟整个屏幕的高度做比较
761761
CGFloat contentHeight = contentOriginY + UIEdgeInsetsGetVerticalValue(self.sheetContentMargin);
762-
CGFloat screenSpaceHeight = CGRectGetHeight(self.view.bounds);
762+
CGFloat screenSpaceHeight = CGRectGetHeight(self.view.bounds) - SafeAreaInsetsConstantForDeviceWithNotch.top - (self.isExtendBottomLayout ? 0 : SafeAreaInsetsConstantForDeviceWithNotch.bottom);
763763
if (contentHeight > screenSpaceHeight) {
764764
CGFloat cancelButtonAreaHeight = (self.cancelAction ? (CGRectGetHeight(self.cancelAction.button.bounds) + self.sheetCancelButtonMarginTop) : 0);
765765
screenSpaceHeight = screenSpaceHeight - cancelButtonAreaHeight - UIEdgeInsetsGetVerticalValue(self.sheetContentMargin);
@@ -789,7 +789,7 @@ - (void)viewDidLayoutSubviews {
789789
contentHeight -= self.sheetContentMargin.top;
790790
}
791791

792-
self.containerView.qmui_frameApplyTransform = CGRectMake((CGRectGetWidth(self.view.bounds) - CGRectGetWidth(self.containerView.frame)) / 2, screenSpaceHeight - contentHeight - SafeAreaInsetsConstantForDeviceWithNotch.bottom, CGRectGetWidth(self.containerView.frame), contentHeight + (self.isExtendBottomLayout ? SafeAreaInsetsConstantForDeviceWithNotch.bottom : 0));
792+
self.containerView.qmui_frameApplyTransform = CGRectMake((CGRectGetWidth(self.view.bounds) - CGRectGetWidth(self.containerView.frame)) / 2, SafeAreaInsetsConstantForDeviceWithNotch.top + screenSpaceHeight - contentHeight, CGRectGetWidth(self.containerView.frame), contentHeight + (self.isExtendBottomLayout ? SafeAreaInsetsConstantForDeviceWithNotch.bottom : 0));
793793

794794
self.extendLayer.frame = CGRectFlatMake(0, CGRectGetHeight(self.containerView.bounds) - SafeAreaInsetsConstantForDeviceWithNotch.bottom - 1, CGRectGetWidth(self.containerView.bounds), SafeAreaInsetsConstantForDeviceWithNotch.bottom + 1);
795795
}

0 commit comments

Comments
 (0)