Skip to content

Commit

Permalink
4.2.0,兼容 iOS 14 Beta,废弃 iOS 9
Browse files Browse the repository at this point in the history
  • Loading branch information
MoLice committed Jul 29, 2020
1 parent e4c7374 commit 59eb35e
Show file tree
Hide file tree
Showing 115 changed files with 3,818 additions and 1,552 deletions.
63 changes: 47 additions & 16 deletions QMUIConfigurationTemplate/QMUIConfigurationTemplate.m

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions QMUIKit.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "QMUIKit"
s.version = "4.1.3"
s.version = "4.2.0"
s.summary = "致力于提高项目 UI 开发效率的解决方案"
s.description = <<-DESC
QMUI iOS 是一个致力于提高项目 UI 开发效率的解决方案,其设计目的是用于辅助快速搭建一个具备基本设计还原效果的 iOS 项目,同时利用自身提供的丰富控件及兼容处理, 让开发者能专注于业务需求而无需耗费精力在基础代码的设计上。不管是新项目的创建,或是已有项目的维护,均可使开发效率和项目质量得到大幅度提升。
Expand All @@ -16,7 +16,7 @@ Pod::Spec.new do |s|
s.screenshot = 'https://cloud.githubusercontent.com/assets/1190261/26751376/63f96538-486a-11e7-81cf-5bc83a945207.png'

s.platform = :ios, '9.0'
s.frameworks = 'Foundation', 'UIKit', 'CoreGraphics', 'Photos'
s.frameworks = 'Foundation', 'UIKit', 'CoreGraphics'
s.preserve_paths = 'QMUIConfigurationTemplate/*'
s.source_files = 'QMUIKit/QMUIKit.h'
s.resource_bundles = {'QMUIResources' => ['QMUIKit/QMUIResources/*.*']}
Expand Down Expand Up @@ -346,6 +346,7 @@ Pod::Spec.new do |s|

ss.subspec 'QMUIAssetLibrary' do |sss|
sss.source_files = 'QMUIKit/QMUIComponents/AssetLibrary/*.{h,m}'
sss.weak_framework = 'Photos'
end

ss.subspec 'QMUIImagePickerLibrary' do |sss|
Expand Down
2 changes: 1 addition & 1 deletion QMUIKit/QMUIComponents/AssetLibrary/QMUIAsset.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ typedef NS_ENUM(NSUInteger, QMUIAssetDownloadStatus) {
*
* @return 返回请求图片的请求 id
*/
- (NSInteger)requestLivePhotoWithCompletion:(void (^)(PHLivePhoto *livePhoto, NSDictionary<NSString *, id> *info))completion withProgressHandler:(PHAssetImageProgressHandler)phProgressHandler NS_AVAILABLE_IOS(9_1);
- (NSInteger)requestLivePhotoWithCompletion:(void (^)(PHLivePhoto *livePhoto, NSDictionary<NSString *, id> *info))completion withProgressHandler:(PHAssetImageProgressHandler)phProgressHandler;

/**
* 异步请求 AVPlayerItem,可能会有网络请求
Expand Down
8 changes: 2 additions & 6 deletions QMUIKit/QMUIComponents/AssetLibrary/QMUIAsset.m
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,8 @@ - (instancetype)initWithPHAsset:(PHAsset *)phAsset {
if ([[phAsset qmui_valueForKey:@"uniformTypeIdentifier"] isEqualToString:(__bridge NSString *)kUTTypeGIF]) {
_assetSubType = QMUIAssetSubTypeGIF;
} else {
if (@available(iOS 9.1, *)) {
if (phAsset.mediaSubtypes & PHAssetMediaSubtypePhotoLive) {
_assetSubType = QMUIAssetSubTypeLivePhoto;
} else {
_assetSubType = QMUIAssetSubTypeImage;
}
if (phAsset.mediaSubtypes & PHAssetMediaSubtypePhotoLive) {
_assetSubType = QMUIAssetSubTypeLivePhoto;
} else {
_assetSubType = QMUIAssetSubTypeImage;
}
Expand Down
2 changes: 1 addition & 1 deletion QMUIKit/QMUIComponents/CALayer+QMUIViewAnimation.m
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ + (instancetype)sharedDelegator {
return instance;
}

+ (id)allocWithZone:(struct _NSZone *)zone{
+ (id)allocWithZone:(struct _NSZone *)zone {
return [self sharedDelegator];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
#import "QMUIAlertController.h"
#import "UIImage+QMUI.h"
#import "UIView+QMUI.h"
#import "UIControl+QMUI.h"
#import "QMUILog.h"
#import "QMUIAppearance.h"

Expand Down Expand Up @@ -184,10 +183,8 @@ - (NSUInteger)numberOfImagesInImagePreviewView:(QMUIImagePreviewView *)imagePrev
- (QMUIImagePreviewMediaType)imagePreviewView:(QMUIImagePreviewView *)imagePreviewView assetTypeAtIndex:(NSUInteger)index {
QMUIAsset *imageAsset = [self.imagesAssetArray objectAtIndex:index];
if (imageAsset.assetType == QMUIAssetTypeImage) {
if (@available(iOS 9.1, *)) {
if (imageAsset.assetSubType == QMUIAssetSubTypeLivePhoto) {
return QMUIImagePreviewMediaTypeLivePhoto;
}
if (imageAsset.assetSubType == QMUIAssetSubTypeLivePhoto) {
return QMUIImagePreviewMediaTypeLivePhoto;
}
return QMUIImagePreviewMediaTypeImage;
} else if (imageAsset.assetType == QMUIAssetTypeVideo) {
Expand Down Expand Up @@ -341,40 +338,36 @@ - (void)requestImageForZoomImageView:(QMUIZoomImageView *)zoomImageView withInde

// 这么写是为了消除 Xcode 的 API available warning
BOOL isLivePhoto = NO;
if (@available(iOS 9.1, *)) {
if (imageAsset.assetSubType == QMUIAssetSubTypeLivePhoto) {
isLivePhoto = YES;
imageView.tag = -1;
imageAsset.requestID = [imageAsset requestLivePhotoWithCompletion:^void(PHLivePhoto *livePhoto, NSDictionary *info) {
// 这里可能因为 imageView 复用,导致前面的请求得到的结果显示到别的 imageView 上,
// 因此判断如果是新请求(无复用问题)或者是当前的请求才把获得的图片结果展示出来
dispatch_async(dispatch_get_main_queue(), ^{
BOOL isNewRequest = (imageView.tag == -1 && imageAsset.requestID == 0);
BOOL isCurrentRequest = imageView.tag == imageAsset.requestID;
BOOL loadICloudImageFault = !livePhoto || info[PHImageErrorKey];
if (!loadICloudImageFault && (isNewRequest || isCurrentRequest)) {
// 如果是走 PhotoKit 的逻辑,那么这个 block 会被多次调用,并且第一次调用时返回的图片是一张小图,
// 这时需要把图片放大到跟屏幕一样大,避免后面加载大图后图片的显示会有跳动
if (@available(iOS 9.1, *)) {
imageView.livePhoto = livePhoto;
}
}
BOOL downloadSucceed = (livePhoto && !info) || (![[info objectForKey:PHLivePhotoInfoCancelledKey] boolValue] && ![info objectForKey:PHLivePhotoInfoErrorKey] && ![[info objectForKey:PHLivePhotoInfoIsDegradedKey] boolValue]);
if (downloadSucceed) {
// 资源资源已经在本地或下载成功
[imageAsset updateDownloadStatusWithDownloadResult:YES];
self.downloadStatus = QMUIAssetDownloadStatusSucceed;
imageView.cloudDownloadStatus = QMUIAssetDownloadStatusSucceed;
} else if ([info objectForKey:PHLivePhotoInfoErrorKey] ) {
// 下载错误
[imageAsset updateDownloadStatusWithDownloadResult:NO];
self.downloadStatus = QMUIAssetDownloadStatusFailed;
imageView.cloudDownloadStatus = QMUIAssetDownloadStatusFailed;
}
});
} withProgressHandler:phProgressHandler];
imageView.tag = imageAsset.requestID;
}
if (imageAsset.assetSubType == QMUIAssetSubTypeLivePhoto) {
isLivePhoto = YES;
imageView.tag = -1;
imageAsset.requestID = [imageAsset requestLivePhotoWithCompletion:^void(PHLivePhoto *livePhoto, NSDictionary *info) {
// 这里可能因为 imageView 复用,导致前面的请求得到的结果显示到别的 imageView 上,
// 因此判断如果是新请求(无复用问题)或者是当前的请求才把获得的图片结果展示出来
dispatch_async(dispatch_get_main_queue(), ^{
BOOL isNewRequest = (imageView.tag == -1 && imageAsset.requestID == 0);
BOOL isCurrentRequest = imageView.tag == imageAsset.requestID;
BOOL loadICloudImageFault = !livePhoto || info[PHImageErrorKey];
if (!loadICloudImageFault && (isNewRequest || isCurrentRequest)) {
// 如果是走 PhotoKit 的逻辑,那么这个 block 会被多次调用,并且第一次调用时返回的图片是一张小图,
// 这时需要把图片放大到跟屏幕一样大,避免后面加载大图后图片的显示会有跳动
imageView.livePhoto = livePhoto;
}
BOOL downloadSucceed = (livePhoto && !info) || (![[info objectForKey:PHLivePhotoInfoCancelledKey] boolValue] && ![info objectForKey:PHLivePhotoInfoErrorKey] && ![[info objectForKey:PHLivePhotoInfoIsDegradedKey] boolValue]);
if (downloadSucceed) {
// 资源资源已经在本地或下载成功
[imageAsset updateDownloadStatusWithDownloadResult:YES];
self.downloadStatus = QMUIAssetDownloadStatusSucceed;
imageView.cloudDownloadStatus = QMUIAssetDownloadStatusSucceed;
} else if ([info objectForKey:PHLivePhotoInfoErrorKey] ) {
// 下载错误
[imageAsset updateDownloadStatusWithDownloadResult:NO];
self.downloadStatus = QMUIAssetDownloadStatusFailed;
imageView.cloudDownloadStatus = QMUIAssetDownloadStatusFailed;
}
});
} withProgressHandler:phProgressHandler];
imageView.tag = imageAsset.requestID;
}

if (isLivePhoto) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
#import "UIView+QMUI.h"
#import <MobileCoreServices/MobileCoreServices.h>
#import "QMUIEmptyView.h"
#import "UIControl+QMUI.h"
#import "UIViewController+QMUI.h"
#import "QMUILog.h"
#import "QMUIAppearance.h"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,36 @@

@interface _QMUITransitionNavigationBar : UINavigationBar

@property(nonatomic, weak) UINavigationBar *originalNavigationBar;
@end

@implementation _QMUITransitionNavigationBar

- (void)setOriginalNavigationBar:(UINavigationBar *)originBar {
_originalNavigationBar = originBar;

if (self.barStyle != originBar.barStyle) {
self.barStyle = originBar.barStyle;
}

if (self.translucent != originBar.translucent) {
self.translucent = originBar.translucent;
}

if (![self.barTintColor isEqual:originBar.barTintColor]) {
self.barTintColor = originBar.barTintColor;
}

UIImage *backgroundImage = [originBar backgroundImageForBarMetrics:UIBarMetricsDefault];
if (backgroundImage && backgroundImage.size.width <= 0 && backgroundImage.size.height <= 0) {
// 假设这里的图片时通过`[UIImage new]`这种形式创建的,那么会navBar会奇怪地显示为系统默认navBar的样式。不知道为什么 navController 设置自己的 navBar 为 [UIImage new] 却没事,所以这里做个保护。
backgroundImage = [UIImage qmui_imageWithColor:UIColorClear];
}
[self setBackgroundImage:backgroundImage forBarMetrics:UIBarMetricsDefault];

self.shadowImage = originBar.shadowImage;
}

- (void)layoutSubviews {
[super layoutSubviews];
if (@available(iOS 11, *)) {
Expand Down Expand Up @@ -183,7 +209,7 @@ + (void)load {
OverrideImplementation([UIViewController class], @selector(viewWillLayoutSubviews), ^id(__unsafe_unretained Class originClass, SEL originCMD, IMP (^originalIMPProvider)(void)) {
return ^(UIViewController *selfObject) {

if (![selfObject.navigationController.delegate respondsToSelector:@selector(navigationController:animationControllerForOperation:fromViewController:toViewController:)]) {
if (selfObject.navigationController.delegate && ![selfObject.navigationController.delegate respondsToSelector:@selector(navigationController:animationControllerForOperation:fromViewController:toViewController:)]) {

id<UIViewControllerTransitionCoordinator> transitionCoordinator = selfObject.transitionCoordinator;
UIViewController *fromViewController = [transitionCoordinator viewControllerForKey:UITransitionContextFromViewControllerKey];
Expand Down Expand Up @@ -233,28 +259,7 @@ - (void)addTransitionNavigationBarIfNeeded {

UINavigationBar *originBar = self.navigationController.navigationBar;
_QMUITransitionNavigationBar *customBar = [[_QMUITransitionNavigationBar alloc] init];

if (customBar.barStyle != originBar.barStyle) {
customBar.barStyle = originBar.barStyle;
}

if (customBar.translucent != originBar.translucent) {
customBar.translucent = originBar.translucent;
}

if (![customBar.barTintColor isEqual:originBar.barTintColor]) {
customBar.barTintColor = originBar.barTintColor;
}

UIImage *backgroundImage = [originBar backgroundImageForBarMetrics:UIBarMetricsDefault];
if (backgroundImage && backgroundImage.size.width <= 0 && backgroundImage.size.height <= 0) {
// 假设这里的图片时通过`[UIImage new]`这种形式创建的,那么会navBar会奇怪地显示为系统默认navBar的样式。不知道为什么 navController 设置自己的 navBar 为 [UIImage new] 却没事,所以这里做个保护。
backgroundImage = [UIImage qmui_imageWithColor:UIColorClear];
}
[customBar setBackgroundImage:backgroundImage forBarMetrics:UIBarMetricsDefault];

[customBar setShadowImage:originBar.shadowImage];

customBar.originalNavigationBar = originBar;
self.transitionNavigationBar = customBar;
[self resizeTransitionNavigationBarFrame];

Expand Down Expand Up @@ -651,7 +656,7 @@ + (void)load {

- (void)handlePopViewControllerNavigationBarTransitionWithDisappearViewController:(UIViewController *)disappearViewController appearViewController:(UIViewController *)appearViewController {

if (![self.delegate respondsToSelector:@selector(navigationController:animationControllerForOperation:fromViewController:toViewController:)]) {
if (self.delegate && ![self.delegate respondsToSelector:@selector(navigationController:animationControllerForOperation:fromViewController:toViewController:)]) {

BOOL shouldCustomNavigationBarTransition = [self shouldCustomTransitionAutomaticallyWithFirstViewController:disappearViewController secondViewController:appearViewController];

Expand Down
15 changes: 9 additions & 6 deletions QMUIKit/QMUIComponents/QMUIAlertController.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,13 @@ typedef NS_ENUM(NSInteger, QMUIAlertControllerStyle) {
/// alert 内部 textField 的边框颜色,如果不需要边框,可设置为 nil
@property(nullable, nonatomic, strong) UIColor *alertTextFieldBorderColor UI_APPEARANCE_SELECTOR;

/// alert 内部 textField 的 textInsets,textField 的高度会由文字大小加这个 inset 来决定
@property(nonatomic, assign) UIEdgeInsets alertTextFieldTextInsets UI_APPEARANCE_SELECTOR;

/// alert 内部 textField 的 margin,当存在多个 textField 时可通过参数 @c aTextFieldIndex 来为不同 textField 设置不一样的 margin。
/// @note 注意 margin 是在原有布局基础上叠加的,左右叠加 @c alertHeaderInsets ,顶部 @c alertHeaderInsets.top ,底部为 0。
@property(nonatomic, copy) UIEdgeInsets (^alertTextFieldMarginBlock)(__kindof QMUIAlertController *aAlertController, NSInteger aTextFieldIndex);

/// sheet距离屏幕四边的间距,默认UIEdgeInsetsMake(10, 10, 10, 10)。
@property(nonatomic, assign) UIEdgeInsets sheetContentMargin UI_APPEARANCE_SELECTOR;

Expand Down Expand Up @@ -258,10 +265,10 @@ typedef NS_ENUM(NSInteger, QMUIAlertControllerStyle) {
/// 将`QMUIAlertController`弹出来的`QMUIModalPresentationViewController`对象
@property(nullable, nonatomic, strong, readonly) QMUIModalPresentationViewController *modalPresentationViewController;

/// 主体内容(alert 下指整个弹窗,actionSheet 下指取消按钮上方的那些 header 和 按钮)背后用来做背景样式的 view,默认为空白的 UIView,当你需要做磨砂效果时可以将一个 UIVisualEffectView 赋值给它(但推荐用 QMUIVisualEffectView)。当赋值为 nil 时,内部会自动创建一个空白的 UIView 代替,以保证这个属性不为空。
/// 主体内容(alert 下指整个弹窗,actionSheet 下指取消按钮上方的那些 header 和 按钮)背后用来做背景样式的 view,默认为空白的 UIView,当你需要做磨砂效果时可以将一个 UIVisualEffectView 赋值给它。当赋值为 nil 时,内部会自动创建一个空白的 UIView 代替,以保证这个属性不为空。
@property(null_resettable, nonatomic, strong) UIView *mainVisualEffectView;

/// actionSheet 下的取消按钮背后用来做背景样式的 view,默认为空白的 UIView,当你需要做磨砂效果时可以将一个 UIVisualEffectView 赋值给它(但推荐用 QMUIVisualEffectView)。alert 情况下不会出现。当赋值为 nil 时,内部会自动创建一个空白的 UIView 代替,以保证这个属性不为空。
/// actionSheet 下的取消按钮背后用来做背景样式的 view,默认为空白的 UIView,当你需要做磨砂效果时可以将一个 UIVisualEffectView 赋值给它。alert 情况下不会出现。当赋值为 nil 时,内部会自动创建一个空白的 UIView 代替,以保证这个属性不为空。
@property(null_resettable, nonatomic, strong) UIView *cancelButtonVisualEffectView;

/**
Expand All @@ -278,10 +285,6 @@ typedef NS_ENUM(NSInteger, QMUIAlertControllerStyle) {
/// @warning: 只对 sheet 类型有效
@property(nonatomic, assign) BOOL isExtendBottomLayout UI_APPEARANCE_SELECTOR;

/// 在显示 alert 之前先降下键盘,默认为 YES。系统的 UIAlertController 也会在显示时降下键盘,但它能在消失后把键盘自动升起,并且这个过程不会触发 becomeFirstResponder/resignFirstResponder,QMUIAlertController 暂时做不到这样的效果,只负责降下,不负责恢复。
/// iOS 10 及以上,一个 UIWindow 显示出来时默认就会降下键盘,所以这个属性只在 iOS 9 里有效,iOS 10 及以上即便设置为 NO 也没有效果。
@property(nonatomic, assign) BOOL dismissKeyboardAutomatically;

@end


Expand Down
Loading

0 comments on commit 59eb35e

Please sign in to comment.