diff --git a/QMUIKit.podspec b/QMUIKit.podspec
index 9ece3eb1..698ac863 100644
--- a/QMUIKit.podspec
+++ b/QMUIKit.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "QMUIKit"
- s.version = "3.1.0"
+ s.version = "3.1.1"
s.summary = "致力于提高项目 UI 开发效率的解决方案"
s.description = <<-DESC
QMUI iOS 是一个致力于提高项目 UI 开发效率的解决方案,其设计目的是用于辅助快速搭建一个具备基本设计还原效果的 iOS 项目,同时利用自身提供的丰富控件及兼容处理, 让开发者能专注于业务需求而无需耗费精力在基础代码的设计上。不管是新项目的创建,或是已有项目的维护,均可使开发效率和项目质量得到大幅度提升。
diff --git a/QMUIKit/Info.plist b/QMUIKit/Info.plist
index 4c70e903..ce892bfe 100644
--- a/QMUIKit/Info.plist
+++ b/QMUIKit/Info.plist
@@ -15,7 +15,7 @@
CFBundlePackageType
FMWK
CFBundleShortVersionString
- 3.1.0
+ 3.1.1
CFBundleVersion
$(CURRENT_PROJECT_VERSION)
NSPrincipalClass
diff --git a/QMUIKit/QMUIComponents/QMUIAlertController.m b/QMUIKit/QMUIComponents/QMUIAlertController.m
index 4a8602a3..83cdafa5 100644
--- a/QMUIKit/QMUIComponents/QMUIAlertController.m
+++ b/QMUIKit/QMUIComponents/QMUIAlertController.m
@@ -973,9 +973,7 @@ - (void)hideWithAnimated:(BOOL)animated completion:(void (^)(void))completion {
if ([weakSelf.delegate respondsToSelector:@selector(didHideAlertController:)]) {
[weakSelf.delegate didHideAlertController:weakSelf];
}
- if (completion) {
- completion();
- }
+ if (completion) completion();
}];
// 减少alertController计数
diff --git a/QMUIKit/QMUIComponents/QMUIConsole/QMUIConsoleViewController.m b/QMUIKit/QMUIComponents/QMUIConsole/QMUIConsoleViewController.m
index 26c661b5..13552e60 100644
--- a/QMUIKit/QMUIComponents/QMUIConsole/QMUIConsoleViewController.m
+++ b/QMUIKit/QMUIComponents/QMUIConsole/QMUIConsoleViewController.m
@@ -283,6 +283,9 @@ - (void)clear {
#pragma mark - Popover Button
- (void)handlePopoverTouchEvent:(QMUIButton *)button {
+ [self.view setNeedsLayout];
+ [self.view layoutIfNeeded];
+
self.popoverAnimating = YES;
CGAffineTransform scale = CGAffineTransformMakeScale(CGRectGetWidth(self.popoverButton.frame) / CGRectGetWidth(self.containerView.frame), CGRectGetHeight(self.popoverButton.frame) / CGRectGetHeight(self.containerView.frame));
CGAffineTransform translation = CGAffineTransformMakeTranslation(self.popoverButton.center.x - self.containerView.center.x, self.popoverButton.center.y - self.containerView.center.y);
@@ -322,6 +325,7 @@ - (void)handlePopoverTouchEvent:(QMUIButton *)button {
self.containerView.alpha = 0;
self.containerView.transform = transform;
self.containerView.layer.cornerRadius = cornerRadius / 2;
+ [self.view endEditing:YES];
} completion:^(BOOL finished) {
self.containerView.hidden = YES;
self.containerView.transform = CGAffineTransformIdentity;
@@ -381,6 +385,9 @@ - (void)handlePopverLongPressGestureRecognizer:(UILongPressGestureRecognizer *)g
scale.qmui_animationDidStopBlock = ^(__kindof CAAnimation *aAnimation, BOOL finished) {
[QMUIConsole hide];
[weakSelf.popoverButton.layer removeAnimationForKey:@"scale"];
+ if (@available(iOS 10.0, *)) {
+ [[[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleLight] impactOccurred];
+ }
};
[self.popoverButton.layer addAnimation:scale forKey:@"scale"];
}
diff --git a/QMUIKit/QMUIComponents/QMUIConsole/QMUILog+QMUIConsole.m b/QMUIKit/QMUIComponents/QMUIConsole/QMUILog+QMUIConsole.m
index edc7d969..b8312aa4 100644
--- a/QMUIKit/QMUIComponents/QMUIConsole/QMUILog+QMUIConsole.m
+++ b/QMUIKit/QMUIComponents/QMUIConsole/QMUILog+QMUIConsole.m
@@ -28,6 +28,8 @@ + (void)load {
}
- (void)qmuiconsole_printLogWithFile:(const char *)file line:(int)line func:(const char *)func logItem:(QMUILogItem *)logItem {
+ [self qmuiconsole_printLogWithFile:file line:line func:func logItem:logItem];
+
if (!QMUICMIActivated || !ShouldPrintQMUIWarnLogToConsole) return;
if (!logItem.enabled) return;
if (logItem.level != QMUILogLevelWarn) return;
@@ -35,8 +37,6 @@ - (void)qmuiconsole_printLogWithFile:(const char *)file line:(int)line func:(con
NSString *funcString = [NSString stringWithFormat:@"%s", func];
NSString *defaultString = [NSString stringWithFormat:@"%@:%@ | %@", funcString, @(line), logItem];
[QMUIConsole logWithLevel:logItem.levelDisplayString name:logItem.name logString:defaultString];
-
- [self qmuiconsole_printLogWithFile:file line:line func:func logItem:logItem];
}
@end
diff --git a/QMUIKit/QMUIComponents/QMUIDialogViewController.m b/QMUIKit/QMUIComponents/QMUIDialogViewController.m
index 1b8b7dae..caa6c9c4 100644
--- a/QMUIKit/QMUIComponents/QMUIDialogViewController.m
+++ b/QMUIKit/QMUIComponents/QMUIDialogViewController.m
@@ -893,7 +893,7 @@ - (void)setTextFieldSeparatorInsets:(UIEdgeInsets)textFieldSeparatorInsets {
}
- (NSArray *)textFieldTitleLabels {
- return self.mutableTextFields.copy;
+ return self.mutableTitleLabels.copy;
}
- (NSArray *)textFields {
diff --git a/QMUIKit/QMUIComponents/QMUIPopupContainerView.m b/QMUIKit/QMUIComponents/QMUIPopupContainerView.m
index c5082ff7..284eb8d1 100644
--- a/QMUIKit/QMUIComponents/QMUIPopupContainerView.m
+++ b/QMUIKit/QMUIComponents/QMUIPopupContainerView.m
@@ -66,6 +66,10 @@ - (instancetype)initWithCoder:(NSCoder *)aDecoder {
return self;
}
+- (void)dealloc {
+ _sourceView.qmui_frameDidChangeBlock = nil;
+}
+
- (UIImageView *)imageView {
if (!_imageView) {
_imageView = [[UIImageView alloc] init];
@@ -228,14 +232,12 @@ - (void)setSourceBarItem:(__kindof UIBarItem *)sourceBarItem {
- (void)setSourceView:(__kindof UIView *)sourceView {
_sourceView = sourceView;
__weak __typeof(self)weakSelf = self;
- if (!sourceView.qmui_frameDidChangeBlock) {
- sourceView.qmui_frameDidChangeBlock = ^(__kindof UIView * _Nonnull view, CGRect precedingFrame) {
- if (!view.window || !weakSelf.superview) return;
- UIView *convertToView = weakSelf.popupWindow ? UIApplication.sharedApplication.delegate.window : weakSelf.superview;// 对于以 window 方式显示的情况,由于横竖屏旋转时,不同 window 的旋转顺序不同,所以可能导致 sourceBarItem 所在的 window 已经旋转了但 popupWindow 还没旋转(iOS 11 及以后),那么计算出来的坐标就错了,所以这里改为用 UIApplication window
- CGRect rect = [view qmui_convertRect:view.bounds toView:convertToView];
- weakSelf.sourceRect = rect;
- };
- }
+ sourceView.qmui_frameDidChangeBlock = ^(__kindof UIView * _Nonnull view, CGRect precedingFrame) {
+ if (!view.window || !weakSelf.superview) return;
+ UIView *convertToView = weakSelf.popupWindow ? UIApplication.sharedApplication.delegate.window : weakSelf.superview;// 对于以 window 方式显示的情况,由于横竖屏旋转时,不同 window 的旋转顺序不同,所以可能导致 sourceBarItem 所在的 window 已经旋转了但 popupWindow 还没旋转(iOS 11 及以后),那么计算出来的坐标就错了,所以这里改为用 UIApplication window
+ CGRect rect = [view qmui_convertRect:view.bounds toView:convertToView];
+ weakSelf.sourceRect = rect;
+ };
sourceView.qmui_frameDidChangeBlock(sourceView, sourceView.frame);// update layout immediately
}
diff --git a/QMUIKit/QMUIComponents/QMUITableView.m b/QMUIKit/QMUIComponents/QMUITableView.m
index 62052f93..014d7fb9 100644
--- a/QMUIKit/QMUIComponents/QMUITableView.m
+++ b/QMUIKit/QMUIComponents/QMUITableView.m
@@ -15,6 +15,8 @@
#import "QMUITableView.h"
#import "UITableView+QMUI.h"
+#import "UIView+QMUI.h"
+#import "QMUIConsole.h"
@implementation QMUITableView
diff --git a/QMUIKit/QMUICore/QMUIHelper.m b/QMUIKit/QMUICore/QMUIHelper.m
index b4e9167e..a5ca2a88 100644
--- a/QMUIKit/QMUICore/QMUIHelper.m
+++ b/QMUIKit/QMUICore/QMUIHelper.m
@@ -19,6 +19,7 @@
#import "UIViewController+QMUI.h"
#import "NSString+QMUI.h"
#import "UIInterface+QMUI.h"
+#import "NSObject+QMUI.h"
#import
#import
#import
@@ -327,11 +328,31 @@ + (BOOL)isSimulator {
+ (BOOL)isNotchedScreen {
if (@available(iOS 11, *)) {
if (isNotchedScreen < 0) {
- // iOS 12,只要 init 完 window,window 的尺寸就已经被设定为当前 App 的大小了,所以可以通过是否有 safeAreaInsets 来动态判断。
- // 但 iOS 11 及以前无法通过这个方式动态判断,所以只能依靠物理设备的判断方式
- if (@available(iOS 12, *)) {
- UIWindow *window = [[UIWindow alloc] init];
- isNotchedScreen = window.safeAreaInsets.bottom > 0 ? 1 : 0;
+ if (@available(iOS 12.0, *)) {
+ /*
+ 检测方式解释/测试要点:
+ 1. iOS 11 与 iOS 12 可能行为不同,所以要分别测试。
+ 2. 与触发 [QMUIHelper isNotchedScreen] 方法时的进程有关,例如 https://github.com/Tencent/QMUI_iOS/issues/482#issuecomment-456051738 里提到的 [NSObject performSelectorOnMainThread:withObject:waitUntilDone:NO] 就会导致较多的异常。
+ 3. iOS 12 下,在非第2点里提到的情况下,iPhone、iPad 均可通过 UIScreen -_peripheryInsets 方法的返回值区分,但如果满足了第2点,则 iPad 无法使用这个方法,这种情况下要依赖第4点。
+ 4. iOS 12 下,不管是否满足第2点,不管是什么设备类型,均可以通过一个满屏的 UIWindow 的 rootViewController.view.frame.origin.y 的值来区分,如果是非全面屏,这个值必定为20,如果是全面屏,则可能是24或44等不同的值。但由于创建 UIWindow、UIViewController 等均属于较大消耗,所以只在前面的步骤无法区分的情况下才会使用第4点。
+ 5. 对于第4点,经测试与当前设备的方向、是否有勾选 project 里的 General - Hide status bar、当前是否处于来电模式的状态栏这些都没关系。
+ */
+ SEL peripheryInsetsSelector = NSSelectorFromString([NSString stringWithFormat:@"_%@%@", @"periphery", @"Insets"]);
+ UIEdgeInsets peripheryInsets = UIEdgeInsetsZero;
+ [[UIScreen mainScreen] qmui_performSelector:peripheryInsetsSelector withReturnValue:&peripheryInsets];
+ if (peripheryInsets.bottom <= 0) {
+ UIWindow *window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
+ peripheryInsets = window.safeAreaInsets;
+ if (peripheryInsets.bottom <= 0) {
+ UIViewController *viewController = [UIViewController new];
+ [viewController loadViewIfNeeded];
+ window.rootViewController = viewController;
+ if (CGRectGetMinY(viewController.view.frame) > 20) {
+ peripheryInsets.bottom = 1;
+ }
+ }
+ }
+ isNotchedScreen = peripheryInsets.bottom > 0 ? 1 : 0;
} else {
isNotchedScreen = [QMUIHelper is58InchScreen] ? 1 : 0;
}
@@ -339,7 +360,7 @@ + (BOOL)isNotchedScreen {
} else {
isNotchedScreen = 0;
}
-
+
return isNotchedScreen > 0;
}
@@ -468,7 +489,7 @@ + (UIEdgeInsets)safeAreaInsetsForDeviceWithNotch {
switch (orientation) {
case UIInterfaceOrientationPortrait:
return UIEdgeInsetsMake(44, 0, 34, 0);
-
+
case UIInterfaceOrientationPortraitUpsideDown:
return UIEdgeInsetsMake(34, 0, 44, 0);
diff --git a/QMUIKit/QMUIKit.h b/QMUIKit/QMUIKit.h
index b90d4d88..e513a0ef 100644
--- a/QMUIKit/QMUIKit.h
+++ b/QMUIKit/QMUIKit.h
@@ -13,7 +13,7 @@
#ifndef QMUIKit_h
#define QMUIKit_h
-static NSString * const QMUI_VERSION = @"3.1.0";
+static NSString * const QMUI_VERSION = @"3.1.1";
#if __has_include("CAAnimation+QMUI.h")
#import "CAAnimation+QMUI.h"
diff --git a/QMUIKit/UIKitExtensions/NSObject+QMUI.h b/QMUIKit/UIKitExtensions/NSObject+QMUI.h
index 864fe5f8..b77ce94b 100644
--- a/QMUIKit/UIKitExtensions/NSObject+QMUI.h
+++ b/QMUIKit/UIKitExtensions/NSObject+QMUI.h
@@ -160,12 +160,12 @@
@code
- (UITableViewCell *)cellForIndexPath:(NSIndexPath *)indexPath {
// 1)在这里给 button 绑定上 indexPath 对象
- [cell strongBind:indexPath forKey:@"indexPath"];
+ [cell qmui_bindObject:indexPath forKey:@"indexPath"];
}
- (void)didTapButton:(UIButton *)button {
// 2)在这里取出被点击的 button 的 indexPath 对象
- NSIndexPath *indexPathTapped = [button getBindForKey:@"indexPath"];
+ NSIndexPath *indexPathTapped = [button qmui_getBoundObjectForKey:@"indexPath"];
}
@endcode
*/
diff --git a/qmui.xcodeproj/project.xcworkspace/xcuserdata/molice.xcuserdatad/UserInterfaceState.xcuserstate b/qmui.xcodeproj/project.xcworkspace/xcuserdata/molice.xcuserdatad/UserInterfaceState.xcuserstate
new file mode 100644
index 00000000..b98ecfc4
Binary files /dev/null and b/qmui.xcodeproj/project.xcworkspace/xcuserdata/molice.xcuserdatad/UserInterfaceState.xcuserstate differ
diff --git a/qmui.xcodeproj/xcuserdata/molice.xcuserdatad/xcschemes/xcschememanagement.plist b/qmui.xcodeproj/xcuserdata/molice.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644
index 00000000..ccc13613
--- /dev/null
+++ b/qmui.xcodeproj/xcuserdata/molice.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -0,0 +1,27 @@
+
+
+
+
+ SchemeUserState
+
+ QMUIKit.xcscheme_^#shared#^_
+
+ orderHint
+ 0
+
+
+ SuppressBuildableAutocreation
+
+ 16E46D491B00D8C1002B7DB8
+
+ primary
+
+
+ FE0AFAD01D82B9D8000D21D9
+
+ primary
+
+
+
+
+