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 + + + + +