diff --git a/TZImagePickerController/AppDelegate.m b/TZImagePickerController/AppDelegate.m index 7a42f19e..0060ebb1 100644 --- a/TZImagePickerController/AppDelegate.m +++ b/TZImagePickerController/AppDelegate.m @@ -58,7 +58,8 @@ - (void)useNavControllerAsRoot { - (void)pushTZImagePickerController { TZImagePickerController *imagePickerVc = [[TZImagePickerController alloc] initWithMaxImagesCount:9 columnNumber:4 delegate:nil pushPhotoPickerVc:YES]; imagePickerVc.modalPresentationStyle = UIModalPresentationFullScreen; - UINavigationController *nav = (UINavigationController *)[UIApplication sharedApplication].keyWindow.rootViewController; + UIWindow *keyWindow = [TZCommonTools currentKeyWindow]; + UINavigationController *nav =(UINavigationController *)keyWindow.rootViewController; [nav.topViewController presentViewController:imagePickerVc animated:YES completion:nil]; } diff --git a/TZImagePickerController/FLAnimatedImage/FLAnimatedImage.h b/TZImagePickerController/FLAnimatedImage/FLAnimatedImage.h index f056c3b9..0dd731c4 100644 --- a/TZImagePickerController/FLAnimatedImage/FLAnimatedImage.h +++ b/TZImagePickerController/FLAnimatedImage/FLAnimatedImage.h @@ -3,7 +3,7 @@ // Flipboard // // Created by Raphael Schaad on 7/8/13. -// Copyright (c) 2013-2015 Flipboard. All rights reserved. +// Copyright (c) Flipboard. All rights reserved. // @@ -12,7 +12,6 @@ // Allow user classes conveniently just importing one header. #import "FLAnimatedImageView.h" - #ifndef NS_DESIGNATED_INITIALIZER #if __has_attribute(objc_designated_initializer) #define NS_DESIGNATED_INITIALIZER __attribute((objc_designated_initializer)) @@ -34,7 +33,7 @@ extern const NSTimeInterval kFLAnimatedImageDelayTimeIntervalMinimum; @property (nonatomic, strong, readonly) UIImage *posterImage; // Guaranteed to be loaded; usually equivalent to `-imageLazilyCachedAtIndex:0` @property (nonatomic, assign, readonly) CGSize size; // The `.posterImage`'s `.size` -@property (nonatomic, assign, readonly) NSUInteger loopCount; // 0 means repeating the animation indefinitely +@property (nonatomic, assign, readonly) NSUInteger loopCount; // "The number of times to repeat an animated sequence." according to ImageIO (note the slightly different definition to Netscape 2.0 Loop Extension); 0 means repeating the animation forever @property (nonatomic, strong, readonly) NSDictionary *delayTimesForIndexes; // Of type `NSTimeInterval` boxed in `NSNumber`s @property (nonatomic, assign, readonly) NSUInteger frameCount; // Number of valid frames; equal to `[.delayTimes count]` diff --git a/TZImagePickerController/FLAnimatedImage/FLAnimatedImage.m b/TZImagePickerController/FLAnimatedImage/FLAnimatedImage.m index cf49ff20..ddb2ec29 100755 --- a/TZImagePickerController/FLAnimatedImage/FLAnimatedImage.m +++ b/TZImagePickerController/FLAnimatedImage/FLAnimatedImage.m @@ -3,13 +3,18 @@ // Flipboard // // Created by Raphael Schaad on 7/8/13. -// Copyright (c) 2013-2015 Flipboard. All rights reserved. +// Copyright (c) Flipboard. All rights reserved. // #import "FLAnimatedImage.h" #import +#import +#if __has_include() #import +#else +#import +#endif // From vm_param.h, define for iOS 8.0 or higher to build on device. @@ -107,7 +112,7 @@ - (void)setFrameCacheSizeMax:(NSUInteger)frameCacheSizeMax if (_frameCacheSizeMax != frameCacheSizeMax) { // Remember whether the new cap will cause the current cache size to shrink; then we'll make sure to purge from the cache if needed. - BOOL willFrameCacheSizeShrink = (frameCacheSizeMax < self.frameCacheSizeCurrent); + const BOOL willFrameCacheSizeShrink = (frameCacheSizeMax < self.frameCacheSizeCurrent); // Update the value _frameCacheSizeMax = frameCacheSizeMax; @@ -164,7 +169,7 @@ + (void)initialize - (instancetype)init { - FLAnimatedImage *animatedImage = [self initWithAnimatedGIFData:nil]; + FLAnimatedImage *_Nullable const animatedImage = [self initWithAnimatedGIFData:nil]; if (!animatedImage) { FLLog(FLLogLevelError, @"Use `-initWithAnimatedGIFData:` and supply the animated GIF data as an argument to initialize an object of type `FLAnimatedImage`."); } @@ -180,7 +185,7 @@ - (instancetype)initWithAnimatedGIFData:(NSData *)data - (instancetype)initWithAnimatedGIFData:(NSData *)data optimalFrameCacheSize:(NSUInteger)optimalFrameCacheSize predrawingEnabled:(BOOL)isPredrawingEnabled { // Early return if no data supplied! - BOOL hasData = ([data length] > 0); + const BOOL hasData = (data.length > 0); if (!hasData) { FLLog(FLLogLevelError, @"No animated GIF data supplied."); return nil; @@ -210,8 +215,26 @@ - (instancetype)initWithAnimatedGIFData:(NSData *)data optimalFrameCacheSize:(NS } // Early return if not GIF! - CFStringRef imageSourceContainerType = CGImageSourceGetType(_imageSource); - BOOL isGIFData = UTTypeConformsTo(imageSourceContainerType, kUTTypeGIF); + const CFStringRef _Nullable imageSourceContainerType = CGImageSourceGetType(_imageSource); +// const BOOL isGIFData = imageSourceContainerType ? UTTypeConformsTo(imageSourceContainerType, kUTTypeGIF) : NO; + //为了做iOS 15判断 + NSLog(@"imageSourceContainerType========%@",imageSourceContainerType); + if (@available(iOS 15.0, *)) { + NSLog(@"UTTypeGIF=======================%@",UTTypeGIF); + NSLog(@"UTTypeGIF.preferredMIMEType=====%@",UTTypeGIF.preferredMIMEType); + } else { + NSLog(@"kUTTypeGIF======================%@",kUTTypeGIF); + } + BOOL isGIFData = NO; + if (imageSourceContainerType) { + if (@available(iOS 15.0, *)) { + if ([[NSString stringWithFormat:@"%@", imageSourceContainerType] isEqualToString:[NSString stringWithFormat:@"%@",UTTypeGIF]]) { + isGIFData = YES; + } + } else { + isGIFData = UTTypeConformsTo(imageSourceContainerType, kUTTypeGIF); + } + } if (!isGIFData) { FLLog(FLLogLevelError, @"Supplied data is of type %@ and doesn't seem to be GIF data %@", imageSourceContainerType, data); return nil; @@ -227,16 +250,16 @@ - (instancetype)initWithAnimatedGIFData:(NSData *)data optimalFrameCacheSize:(NS // LoopCount = 0; // }; // } - NSDictionary *imageProperties = (__bridge_transfer NSDictionary *)CGImageSourceCopyProperties(_imageSource, NULL); + NSDictionary *_Nullable const imageProperties = (__bridge_transfer NSDictionary *)CGImageSourceCopyProperties(_imageSource, NULL); _loopCount = [[[imageProperties objectForKey:(id)kCGImagePropertyGIFDictionary] objectForKey:(id)kCGImagePropertyGIFLoopCount] unsignedIntegerValue]; // Iterate through frame images - size_t imageCount = CGImageSourceGetCount(_imageSource); + const size_t imageCount = CGImageSourceGetCount(_imageSource); NSUInteger skippedFrameCount = 0; - NSMutableDictionary *delayTimesForIndexesMutable = [NSMutableDictionary dictionaryWithCapacity:imageCount]; + NSMutableDictionary *const delayTimesForIndexesMutable = [NSMutableDictionary dictionaryWithCapacity:imageCount]; for (size_t i = 0; i < imageCount; i++) { @autoreleasepool { - CGImageRef frameImageRef = CGImageSourceCreateImageAtIndex(_imageSource, i, NULL); + const CGImageRef _Nullable frameImageRef = CGImageSourceCreateImageAtIndex(_imageSource, i, NULL); if (frameImageRef) { UIImage *frameImage = [UIImage imageWithCGImage:frameImageRef]; // Check for valid `frameImage` before parsing its properties as frames can be corrupted (and `frameImage` even `nil` when `frameImageRef` was valid). @@ -266,17 +289,17 @@ - (instancetype)initWithAnimatedGIFData:(NSData *)data optimalFrameCacheSize:(NS // }; // } - NSDictionary *frameProperties = (__bridge_transfer NSDictionary *)CGImageSourceCopyPropertiesAtIndex(_imageSource, i, NULL); - NSDictionary *framePropertiesGIF = [frameProperties objectForKey:(id)kCGImagePropertyGIFDictionary]; + NSDictionary *_Nullable const frameProperties = (__bridge_transfer NSDictionary *)CGImageSourceCopyPropertiesAtIndex(_imageSource, i, NULL); + NSDictionary *_Nullable const framePropertiesGIF = [frameProperties objectForKey:(id)kCGImagePropertyGIFDictionary]; // Try to use the unclamped delay time; fall back to the normal delay time. - NSNumber *delayTime = [framePropertiesGIF objectForKey:(id)kCGImagePropertyGIFUnclampedDelayTime]; - if (!delayTime) { + NSNumber *_Nullable delayTime = [framePropertiesGIF objectForKey:(id)kCGImagePropertyGIFUnclampedDelayTime]; + if (delayTime == nil) { delayTime = [framePropertiesGIF objectForKey:(id)kCGImagePropertyGIFDelayTime]; } // If we don't get a delay time from the properties, fall back to `kDelayTimeIntervalDefault` or carry over the preceding frame's value. const NSTimeInterval kDelayTimeIntervalDefault = 0.1; - if (!delayTime) { + if (delayTime == nil) { if (i == 0) { FLLog(FLLogLevelInfo, @"Falling back to default delay time for first frame %@ because none found in GIF properties %@", frameImage, frameProperties); delayTime = @(kDelayTimeIntervalDefault); @@ -320,7 +343,7 @@ - (instancetype)initWithAnimatedGIFData:(NSData *)data optimalFrameCacheSize:(NS if (optimalFrameCacheSize == 0) { // Calculate the optimal frame cache size: try choosing a larger buffer window depending on the predicted image size. // It's only dependent on the image size & number of frames and never changes. - CGFloat animatedImageDataSize = CGImageGetBytesPerRow(self.posterImage.CGImage) * self.size.height * (self.frameCount - skippedFrameCount) / MEGABYTE; + const CGFloat animatedImageDataSize = (CGFloat)CGImageGetBytesPerRow(self.posterImage.CGImage) * self.size.height * (CGFloat)(self.frameCount - skippedFrameCount) / (CGFloat)MEGABYTE; if (animatedImageDataSize <= FLAnimatedImageDataSizeCategoryAll) { _frameCacheSizeOptimal = self.frameCount; } else if (animatedImageDataSize <= FLAnimatedImageDataSizeCategoryDefault) { @@ -355,7 +378,7 @@ - (instancetype)initWithAnimatedGIFData:(NSData *)data optimalFrameCacheSize:(NS + (instancetype)animatedImageWithGIFData:(NSData *)data { - FLAnimatedImage *animatedImage = [[FLAnimatedImage alloc] initWithAnimatedGIFData:data]; + FLAnimatedImage *const animatedImage = [[FLAnimatedImage alloc] initWithAnimatedGIFData:data]; return animatedImage; } @@ -410,7 +433,7 @@ - (UIImage *)imageLazilyCachedAtIndex:(NSUInteger)index } // Get the specified image. - UIImage *image = self.cachedFramesForIndexes[@(index)]; + UIImage *const image = self.cachedFramesForIndexes[@(index)]; // Purge if needed based on the current playhead position. [self purgeFrameCacheIfNeeded]; @@ -424,8 +447,8 @@ - (void)addFrameIndexesToCache:(NSIndexSet *)frameIndexesToAddToCache { // Order matters. First, iterate over the indexes starting from the requested frame index. // Then, if there are any indexes before the requested frame index, do those. - NSRange firstRange = NSMakeRange(self.requestedFrameIndex, self.frameCount - self.requestedFrameIndex); - NSRange secondRange = NSMakeRange(0, self.requestedFrameIndex); + const NSRange firstRange = NSMakeRange(self.requestedFrameIndex, self.frameCount - self.requestedFrameIndex); + const NSRange secondRange = NSMakeRange(0, self.requestedFrameIndex); if (firstRange.length + secondRange.length != self.frameCount) { FLLog(FLLogLevelWarn, @"Two-part frame cache range doesn't equal full range."); } @@ -440,18 +463,18 @@ - (void)addFrameIndexesToCache:(NSIndexSet *)frameIndexesToAddToCache // Start streaming requested frames in the background into the cache. // Avoid capturing self in the block as there's no reason to keep doing work if the animated image went away. - FLAnimatedImage * __weak weakSelf = self; + __weak __typeof(self) weakSelf = self; dispatch_async(self.serialQueue, ^{ // Produce and cache next needed frame. void (^frameRangeBlock)(NSRange, BOOL *) = ^(NSRange range, BOOL *stop) { // Iterate through contiguous indexes; can be faster than `enumerateIndexesInRange:options:usingBlock:`. for (NSUInteger i = range.location; i < NSMaxRange(range); i++) { #if defined(DEBUG) && DEBUG - CFTimeInterval predrawBeginTime = CACurrentMediaTime(); + const CFTimeInterval predrawBeginTime = CACurrentMediaTime(); #endif - UIImage *image = [weakSelf imageAtIndex:i]; + UIImage *const image = [weakSelf imageAtIndex:i]; #if defined(DEBUG) && DEBUG - CFTimeInterval predrawDuration = CACurrentMediaTime() - predrawBeginTime; + const CFTimeInterval predrawDuration = CACurrentMediaTime() - predrawBeginTime; CFTimeInterval slowdownDuration = 0.0; if ([self.debug_delegate respondsToSelector:@selector(debug_animatedImagePredrawingSlowdownFactor:)]) { CGFloat predrawingSlowdownFactor = [self.debug_delegate debug_animatedImagePredrawingSlowdownFactor:self]; @@ -493,10 +516,10 @@ + (CGSize)sizeForImage:(id)image } if ([image isKindOfClass:[UIImage class]]) { - UIImage *uiImage = (UIImage *)image; + UIImage *const uiImage = (UIImage *)image; imageSize = uiImage.size; } else if ([image isKindOfClass:[FLAnimatedImage class]]) { - FLAnimatedImage *animatedImage = (FLAnimatedImage *)image; + FLAnimatedImage *const animatedImage = (FLAnimatedImage *)image; imageSize = animatedImage.size; } else { // Bear trap to capture bad images; we have seen crashers cropping up on iOS 7. @@ -513,7 +536,7 @@ + (CGSize)sizeForImage:(id)image - (UIImage *)imageAtIndex:(NSUInteger)index { // It's very important to use the cached `_imageSource` since the random access to a frame with `CGImageSourceCreateImageAtIndex` turns from an O(1) into an O(n) operation when re-initializing the image source every time. - CGImageRef imageRef = CGImageSourceCreateImageAtIndex(_imageSource, index, NULL); + const CGImageRef _Nullable imageRef = CGImageSourceCreateImageAtIndex(_imageSource, index, NULL); // Early return for nil if (!imageRef) { @@ -545,10 +568,10 @@ - (NSMutableIndexSet *)frameIndexesToCache // Add indexes to the set in two separate blocks- the first starting from the requested frame index, up to the limit or the end. // The second, if needed, the remaining number of frames beginning at index zero. - NSUInteger firstLength = MIN(self.frameCacheSizeCurrent, self.frameCount - self.requestedFrameIndex); - NSRange firstRange = NSMakeRange(self.requestedFrameIndex, firstLength); + const NSUInteger firstLength = MIN(self.frameCacheSizeCurrent, self.frameCount - self.requestedFrameIndex); + const NSRange firstRange = NSMakeRange(self.requestedFrameIndex, firstLength); [indexesToCache addIndexesInRange:firstRange]; - NSUInteger secondLength = self.frameCacheSizeCurrent - firstLength; + const NSUInteger secondLength = self.frameCacheSizeCurrent - firstLength; if (secondLength > 0) { NSRange secondRange = NSMakeRange(0, secondLength); [indexesToCache addIndexesInRange:secondRange]; @@ -655,7 +678,7 @@ - (void)didReceiveMemoryWarning:(NSNotification *)notification + (UIImage *)predrawnImageFromImage:(UIImage *)imageToPredraw { // Always use a device RGB color space for simplicity and predictability what will be going on. - CGColorSpaceRef colorSpaceDeviceRGBRef = CGColorSpaceCreateDeviceRGB(); + const CGColorSpaceRef _Nullable colorSpaceDeviceRGBRef = CGColorSpaceCreateDeviceRGB(); // Early return on failure! if (!colorSpaceDeviceRGBRef) { FLLog(FLLogLevelError, @"Failed to `CGColorSpaceCreateDeviceRGB` for image %@", imageToPredraw); @@ -665,17 +688,17 @@ + (UIImage *)predrawnImageFromImage:(UIImage *)imageToPredraw // Even when the image doesn't have transparency, we have to add the extra channel because Quartz doesn't support other pixel formats than 32 bpp/8 bpc for RGB: // kCGImageAlphaNoneSkipFirst, kCGImageAlphaNoneSkipLast, kCGImageAlphaPremultipliedFirst, kCGImageAlphaPremultipliedLast // (source: docs "Quartz 2D Programming Guide > Graphics Contexts > Table 2-1 Pixel formats supported for bitmap graphics contexts") - size_t numberOfComponents = CGColorSpaceGetNumberOfComponents(colorSpaceDeviceRGBRef) + 1; // 4: RGB + A + const size_t numberOfComponents = CGColorSpaceGetNumberOfComponents(colorSpaceDeviceRGBRef) + 1; // 4: RGB + A // "In iOS 4.0 and later, and OS X v10.6 and later, you can pass NULL if you want Quartz to allocate memory for the bitmap." (source: docs) - void *data = NULL; - size_t width = imageToPredraw.size.width; - size_t height = imageToPredraw.size.height; - size_t bitsPerComponent = CHAR_BIT; + void *_Nullable data = NULL; + const size_t width = imageToPredraw.size.width; + const size_t height = imageToPredraw.size.height; + const size_t bitsPerComponent = CHAR_BIT; - size_t bitsPerPixel = (bitsPerComponent * numberOfComponents); - size_t bytesPerPixel = (bitsPerPixel / BYTE_SIZE); - size_t bytesPerRow = (bytesPerPixel * width); + const size_t bitsPerPixel = (bitsPerComponent * numberOfComponents); + const size_t bytesPerPixel = (bitsPerPixel / BYTE_SIZE); + const size_t bytesPerRow = (bytesPerPixel * width); CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault; @@ -694,7 +717,7 @@ + (UIImage *)predrawnImageFromImage:(UIImage *)imageToPredraw // Create our own graphics context to draw to; `UIGraphicsGetCurrentContext`/`UIGraphicsBeginImageContextWithOptions` doesn't create a new context but returns the current one which isn't thread-safe (e.g. main thread could use it at the same time). // Note: It's not worth caching the bitmap context for multiple frames ("unique key" would be `width`, `height` and `hasAlpha`), it's ~50% slower. Time spent in libRIP's `CGSBlendBGRA8888toARGB8888` suddenly shoots up -- not sure why. - CGContextRef bitmapContextRef = CGBitmapContextCreate(data, width, height, bitsPerComponent, bytesPerRow, colorSpaceDeviceRGBRef, bitmapInfo); + const CGContextRef _Nullable bitmapContextRef = CGBitmapContextCreate(data, width, height, bitsPerComponent, bytesPerRow, colorSpaceDeviceRGBRef, bitmapInfo); CGColorSpaceRelease(colorSpaceDeviceRGBRef); // Early return on failure! if (!bitmapContextRef) { @@ -704,8 +727,8 @@ + (UIImage *)predrawnImageFromImage:(UIImage *)imageToPredraw // Draw image in bitmap context and create image by preserving receiver's properties. CGContextDrawImage(bitmapContextRef, CGRectMake(0.0, 0.0, imageToPredraw.size.width, imageToPredraw.size.height), imageToPredraw.CGImage); - CGImageRef predrawnImageRef = CGBitmapContextCreateImage(bitmapContextRef); - UIImage *predrawnImage = [UIImage imageWithCGImage:predrawnImageRef scale:imageToPredraw.scale orientation:imageToPredraw.imageOrientation]; + const CGImageRef _Nullable predrawnImageRef = CGBitmapContextCreateImage(bitmapContextRef); + UIImage *_Nullable predrawnImage = predrawnImageRef ? [UIImage imageWithCGImage:predrawnImageRef scale:imageToPredraw.scale orientation:imageToPredraw.imageOrientation] : nil; CGImageRelease(predrawnImageRef); CGContextRelease(bitmapContextRef); @@ -741,13 +764,13 @@ @implementation FLAnimatedImage (Logging) static void (^_logBlock)(NSString *logString, FLLogLevel logLevel) = nil; static FLLogLevel _logLevel; -+ (void)setLogBlock:(void (^)(NSString *logString, FLLogLevel logLevel))logBlock logLevel:(FLLogLevel)logLevel ++ (void)setLogBlock:(void (^_Nullable)(NSString *logString, FLLogLevel logLevel))logBlock logLevel:(FLLogLevel)logLevel { - _logBlock = logBlock; + _logBlock = [logBlock copy]; _logLevel = logLevel; } -+ (void)logStringFromBlock:(NSString *(^)(void))stringBlock withLevel:(FLLogLevel)level ++ (void)logStringFromBlock:(NSString *(^_Nullable)(void))stringBlock withLevel:(FLLogLevel)level { if (level <= _logLevel && _logBlock && stringBlock) { _logBlock(stringBlock(), level); @@ -797,7 +820,7 @@ - (void)forwardInvocation:(NSInvocation *)invocation // Fallback for when target is nil. Don't do anything, just return 0/NULL/nil. // The method signature we've received to get here is just a dummy to keep `doesNotRecognizeSelector:` from firing. // We can't really handle struct return types here because we don't know the length. - void *nullPointer = NULL; + void *_Nullable nullPointer = NULL; [invocation setReturnValue:&nullPointer]; } diff --git a/TZImagePickerController/FLAnimatedImage/FLAnimatedImageView.h b/TZImagePickerController/FLAnimatedImage/FLAnimatedImageView.h index c0d527aa..8884e534 100644 --- a/TZImagePickerController/FLAnimatedImage/FLAnimatedImageView.h +++ b/TZImagePickerController/FLAnimatedImage/FLAnimatedImageView.h @@ -3,7 +3,7 @@ // Flipboard // // Created by Raphael Schaad on 7/8/13. -// Copyright (c) 2013-2015 Flipboard. All rights reserved. +// Copyright (c) Flipboard. All rights reserved. // @@ -31,6 +31,6 @@ // The animation runloop mode. Enables playback during scrolling by allowing timer events (i.e. animation) with NSRunLoopCommonModes. // To keep scrolling smooth on single-core devices such as iPhone 3GS/4 and iPod Touch 4th gen, the default run loop mode is NSDefaultRunLoopMode. Otherwise, the default is NSDefaultRunLoopMode. -@property (nonatomic, copy) NSString *runLoopMode; +@property (nonatomic, copy) NSRunLoopMode runLoopMode; @end diff --git a/TZImagePickerController/FLAnimatedImage/FLAnimatedImageView.m b/TZImagePickerController/FLAnimatedImage/FLAnimatedImageView.m index 26fea1d2..8c9f583c 100755 --- a/TZImagePickerController/FLAnimatedImage/FLAnimatedImageView.m +++ b/TZImagePickerController/FLAnimatedImage/FLAnimatedImageView.m @@ -3,7 +3,7 @@ // Flipboard // // Created by Raphael Schaad on 7/8/13. -// Copyright (c) 2013-2015 Flipboard. All rights reserved. +// Copyright (c) Flipboard. All rights reserved. // @@ -101,8 +101,16 @@ - (void)setAnimatedImage:(FLAnimatedImage *)animatedImage { if (![_animatedImage isEqual:animatedImage]) { if (animatedImage) { - // Clear out the image. - super.image = nil; + if (super.image) { + // UIImageView's `setImage:` will internally call its layer's `setContentsTransform:` based on the `image.imageOrientation`. + // The `contentsTransform` will affect layer rendering rotation because the CGImage's bitmap buffer does not actually take rotation. + // However, when calling `setImage:nil`, this `contentsTransform` will not be reset to identity. + // Further animation frame will be rendered as rotated. So we must set it to the poster image to clear the previous state. + // See more here: https://github.com/Flipboard/FLAnimatedImage/issues/100 + super.image = animatedImage.posterImage; + // Clear out the image. + super.image = nil; + } // Ensure disabled highlighting; it's not supported (see `-setHighlighted:`). super.highlighted = NO; // UIImageView seems to bypass some accessors when calculating its intrinsic content size, so this ensures its intrinsic content size comes from the animated image. @@ -213,7 +221,6 @@ - (CGSize)intrinsicContentSize return intrinsicContentSize; } -#pragma mark Smart Invert Colors #pragma mark - UIImageView Method Overrides #pragma mark Image Data @@ -249,7 +256,7 @@ - (NSTimeInterval)frameDelayGreatestCommonDivisor // Presision is set to half of the `kFLAnimatedImageDelayTimeIntervalMinimum` in order to minimize frame dropping. const NSTimeInterval kGreatestCommonDivisorPrecision = 2.0 / kFLAnimatedImageDelayTimeIntervalMinimum; - NSArray *delays = self.animatedImage.delayTimesForIndexes.allValues; + NSArray *const delays = self.animatedImage.delayTimesForIndexes.allValues; // Scales the frame delays by `kGreatestCommonDivisorPrecision` // then converts it to an UInteger for in order to calculate the GCD. @@ -259,7 +266,7 @@ - (NSTimeInterval)frameDelayGreatestCommonDivisor } // Reverse to scale to get the value back into seconds. - return scaledGCD / kGreatestCommonDivisorPrecision; + return (double)scaledGCD / kGreatestCommonDivisorPrecision; } @@ -273,7 +280,7 @@ static NSUInteger gcd(NSUInteger a, NSUInteger b) } while (true) { - NSUInteger remainder = a % b; + const NSUInteger remainder = a % b; if (remainder == 0) { return b; } @@ -298,18 +305,21 @@ - (void)startAnimating [self.displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:self.runLoopMode]; } - // Note: The display link's `.frameInterval` value of 1 (default) means getting callbacks at the refresh rate of the display (~60Hz). - // Setting it to 2 divides the frame rate by 2 and hence calls back at every other display refresh. - const NSTimeInterval kDisplayRefreshRate = 60.0; // 60Hz - self.displayLink.frameInterval = MAX([self frameDelayGreatestCommonDivisor] * kDisplayRefreshRate, 1); - + if (@available(iOS 10.0, *)) { + // Adjusting preferredFramesPerSecond allows us to skip unnecessary calls to displayDidRefresh: when showing GIFs + // that don't animate quickly. Use ceil to err on the side of too many FPS so we don't miss a frame transition moment. + self.displayLink.preferredFramesPerSecond = ceil(1.0 / [self frameDelayGreatestCommonDivisor]); + } else { + const NSTimeInterval kDisplayRefreshRate = 60.0; // 60Hz + self.displayLink.frameInterval = MAX([self frameDelayGreatestCommonDivisor] * kDisplayRefreshRate, 1); + } self.displayLink.paused = NO; } else { [super startAnimating]; } } -- (void)setRunLoopMode:(NSString *)runLoopMode +- (void)setRunLoopMode:(NSRunLoopMode)runLoopMode { if (![@[NSDefaultRunLoopMode, NSRunLoopCommonModes] containsObject:runLoopMode]) { NSAssert(NO, @"Invalid run loop mode: %@", runLoopMode); @@ -359,7 +369,7 @@ - (void)setHighlighted:(BOOL)highlighted // Just update our cached value whenever the animated image or visibility (window, superview, hidden, alpha) is changed. - (void)updateShouldAnimate { - BOOL isVisible = self.window && self.superview && ![self isHidden] && self.alpha > 0.0; + const BOOL isVisible = self.window && self.superview && ![self isHidden] && self.alpha > 0.0; self.shouldAnimate = self.animatedImage && isVisible; } @@ -373,12 +383,12 @@ - (void)displayDidRefresh:(CADisplayLink *)displayLink return; } - NSNumber *delayTimeNumber = [self.animatedImage.delayTimesForIndexes objectForKey:@(self.currentFrameIndex)]; + NSNumber *_Nullable const delayTimeNumber = [self.animatedImage.delayTimesForIndexes objectForKey:@(self.currentFrameIndex)]; // If we don't have a frame delay (e.g. corrupt frame), don't update the view but skip the playhead to the next frame (in else-block). - if (delayTimeNumber) { - NSTimeInterval delayTime = [delayTimeNumber floatValue]; + if (delayTimeNumber != nil) { + const NSTimeInterval delayTime = [delayTimeNumber floatValue]; // If we have a nil image (e.g. waiting for frame), don't update the view nor playhead. - UIImage *image = [self.animatedImage imageLazilyCachedAtIndex:self.currentFrameIndex]; + UIImage *_Nullable const image = [self.animatedImage imageLazilyCachedAtIndex:self.currentFrameIndex]; if (image) { FLLog(FLLogLevelVerbose, @"Showing frame %lu for animated image: %@", (unsigned long)self.currentFrameIndex, self.animatedImage); self.currentFrame = image; @@ -387,7 +397,11 @@ - (void)displayDidRefresh:(CADisplayLink *)displayLink self.needsDisplayWhenImageBecomesAvailable = NO; } - self.accumulator += displayLink.duration * displayLink.frameInterval; + if (@available(iOS 10.0, *)) { + self.accumulator += displayLink.targetTimestamp - CACurrentMediaTime(); + } else { + self.accumulator += displayLink.duration * (NSTimeInterval)displayLink.frameInterval; + } // While-loop first inspired by & good Karma to: https://github.com/ondalabs/OLImageView/blob/master/OLImageView.m while (self.accumulator >= delayTime) { @@ -414,7 +428,11 @@ - (void)displayDidRefresh:(CADisplayLink *)displayLink FLLog(FLLogLevelDebug, @"Waiting for frame %lu for animated image: %@", (unsigned long)self.currentFrameIndex, self.animatedImage); #if defined(DEBUG) && DEBUG if ([self.debug_delegate respondsToSelector:@selector(debug_animatedImageView:waitingForFrame:duration:)]) { - [self.debug_delegate debug_animatedImageView:self waitingForFrame:self.currentFrameIndex duration:(NSTimeInterval)displayLink.duration * displayLink.frameInterval]; + if (@available(iOS 10.0, *)) { + [self.debug_delegate debug_animatedImageView:self waitingForFrame:self.currentFrameIndex duration:displayLink.targetTimestamp - CACurrentMediaTime()]; + } else { + [self.debug_delegate debug_animatedImageView:self waitingForFrame:self.currentFrameIndex duration:displayLink.duration * (NSTimeInterval)displayLink.frameInterval]; + } } #endif } @@ -423,7 +441,7 @@ - (void)displayDidRefresh:(CADisplayLink *)displayLink } } -+ (NSString *)defaultRunLoopMode ++ (NSRunLoopMode)defaultRunLoopMode { // Key off `activeProcessorCount` (as opposed to `processorCount`) since the system could shut down cores in certain situations. return [NSProcessInfo processInfo].activeProcessorCount > 1 ? NSRunLoopCommonModes : NSDefaultRunLoopMode; diff --git a/TZImagePickerController/Info.plist b/TZImagePickerController/Info.plist index 8d9097fe..82a79238 100644 --- a/TZImagePickerController/Info.plist +++ b/TZImagePickerController/Info.plist @@ -2,6 +2,13 @@ + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + CFBundleDevelopmentRegion en_US CFBundleExecutable diff --git a/TZImagePickerController/LxGridViewFlowLayout.m b/TZImagePickerController/LxGridViewFlowLayout.m index 3050afec..490ba91d 100755 --- a/TZImagePickerController/LxGridViewFlowLayout.m +++ b/TZImagePickerController/LxGridViewFlowLayout.m @@ -174,7 +174,11 @@ - (void)longPressGestureRecognizerTriggerd:(UILongPressGestureRecognizer *)longP { if (_displayLink == nil) { _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkTriggered:)]; - _displayLink.frameInterval = 6; + if (@available(iOS 10.0, *)) { + _displayLink.preferredFramesPerSecond = 6; + } else { + _displayLink.frameInterval = 6; + } [_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; _remainSecondsToBeginEditing = MIN_PRESS_TO_BEGIN_EDITING_DURATION; diff --git a/TZImagePickerController/TZImagePickerController/TZGifPhotoPreviewController.m b/TZImagePickerController/TZImagePickerController/TZGifPhotoPreviewController.m index 26c1a79a..a7f20de6 100644 --- a/TZImagePickerController/TZImagePickerController/TZGifPhotoPreviewController.m +++ b/TZImagePickerController/TZImagePickerController/TZGifPhotoPreviewController.m @@ -32,7 +32,7 @@ @implementation TZGifPhotoPreviewController - (void)viewDidLoad { [super viewDidLoad]; - self.needShowStatusBar = ![UIApplication sharedApplication].statusBarHidden; + self.needShowStatusBar = ![TZCommonTools currentStatusBarHidden]; self.view.backgroundColor = [UIColor blackColor]; TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; if (tzImagePickerVc) { @@ -44,16 +44,11 @@ - (void)viewDidLoad { - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; - _originStatusBarStyle = [UIApplication sharedApplication].statusBarStyle; - [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent; + _originStatusBarStyle = [TZCommonTools currentStatusBarStyle]; } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; - if (self.needShowStatusBar) { - [UIApplication sharedApplication].statusBarHidden = NO; - } - [UIApplication sharedApplication].statusBarStyle = _originStatusBarStyle; } - (void)configPreviewView { @@ -101,6 +96,10 @@ - (void)configBottomToolBar { } } +- (BOOL)prefersStatusBarHidden { + return !self.needShowStatusBar; +} + - (UIStatusBarStyle)preferredStatusBarStyle { TZImagePickerController *tzImagePicker = (TZImagePickerController *)self.navigationController; if (tzImagePicker && [tzImagePicker isKindOfClass:[TZImagePickerController class]]) { @@ -132,12 +131,6 @@ - (void)viewDidLayoutSubviews { - (void)signleTapAction { _toolBar.hidden = !_toolBar.isHidden; [self.navigationController setNavigationBarHidden:_toolBar.isHidden]; - TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; - if (_toolBar.isHidden) { - [UIApplication sharedApplication].statusBarHidden = YES; - } else if (tzImagePickerVc.needShowStatusBar) { - [UIApplication sharedApplication].statusBarHidden = NO; - } } - (void)doneButtonClick { diff --git a/TZImagePickerController/TZImagePickerController/TZImageManager.h b/TZImagePickerController/TZImagePickerController/TZImageManager.h index f7f5ff15..90d50668 100755 --- a/TZImagePickerController/TZImagePickerController/TZImageManager.h +++ b/TZImagePickerController/TZImagePickerController/TZImageManager.h @@ -71,6 +71,8 @@ - (PHImageRequestID)getPhotoWithAsset:(PHAsset *)asset completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler networkAccessAllowed:(BOOL)networkAccessAllowed; - (PHImageRequestID)getPhotoWithAsset:(PHAsset *)asset photoWidth:(CGFloat)photoWidth completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler networkAccessAllowed:(BOOL)networkAccessAllowed; - (PHImageRequestID)requestImageDataForAsset:(PHAsset *)asset completion:(void (^)(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info))completion progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler; +//适配iOS13 +- (PHImageRequestID)requestImageDataFitSystemForAsset:(PHAsset *)asset options:(nullable PHImageRequestOptions *)options completion:(void (^_Nonnull)(NSData *_Nullable imageData, NSString *_Nullable dataUTI, UIImageOrientation orientation, NSDictionary *_Nullable info))completion; /// Get full Image 获取原图 /// 如下两个方法completion一般会调多次,一般会先返回缩略图,再返回原图(详见方法内部使用的系统API的说明),如果info[PHImageResultIsDegradedKey] 为 YES,则表明当前返回的是缩略图,否则是原图。 diff --git a/TZImagePickerController/TZImagePickerController/TZImageManager.m b/TZImagePickerController/TZImagePickerController/TZImageManager.m index 90e989ce..193404cf 100755 --- a/TZImagePickerController/TZImagePickerController/TZImageManager.m +++ b/TZImagePickerController/TZImagePickerController/TZImageManager.m @@ -65,7 +65,7 @@ - (void)configTZScreenWidth { } - (BOOL)isPHAuthorizationStatusLimited { - if (@available(iOS 14,*)) { + if (@available(iOS 14.0, *)) { NSInteger status = [PHPhotoLibrary authorizationStatusForAccessLevel:PHAccessLevelReadWrite]; if (status == PHAuthorizationStatusLimited) { return YES; @@ -79,15 +79,20 @@ - (BOOL)authorizationStatusAuthorized { if (self.isPreviewNetworkImage) { return YES; } - NSInteger status = [PHPhotoLibrary authorizationStatus]; - if (status == 0) { + PHAuthorizationStatus orizationStatus = 0; + if (@available(iOS 14.0, *)) { + orizationStatus = [PHPhotoLibrary authorizationStatusForAccessLevel:PHAccessLevelReadWrite]; + } else { + orizationStatus = [PHPhotoLibrary authorizationStatus]; + } + if (orizationStatus == 0) { /** * 当某些情况下AuthorizationStatus == AuthorizationStatusNotDetermined时,无法弹出系统首次使用的授权alertView,系统应用设置里亦没有相册的设置,此时将无法使用,故作以下操作,弹出系统首次使用的授权alertView */ [self requestAuthorizationWithCompletion:nil]; } - return status == 3; + return orizationStatus == 3; } - (void)requestAuthorizationWithCompletion:(void (^)(void))completion { @@ -100,9 +105,15 @@ - (void)requestAuthorizationWithCompletion:(void (^)(void))completion { }; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { - callCompletionBlock(); - }]; + if (@available(iOS 14.0, *)) { + [PHPhotoLibrary requestAuthorizationForAccessLevel:PHAccessLevelReadWrite handler:^(PHAuthorizationStatus status) { + callCompletionBlock(); + }]; + } else { + [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { + callCompletionBlock(); + }]; + } }); } @@ -322,7 +333,7 @@ - (void)getPhotosBytesWithArray:(NSArray *)photos completion:(void (^)(NSString if (model.type == TZAssetModelMediaTypePhotoGif) { options.version = PHImageRequestOptionsVersionOriginal; } - [[PHImageManager defaultManager] requestImageDataForAsset:model.asset options:options resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) { + [[TZImageManager manager] requestImageDataFitSystemForAsset:model.asset options:options completion:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) { if (model.type != TZAssetModelMediaTypeVideo) dataLength += imageData.length; assetCount ++; if (assetCount >= photos.count) { @@ -375,12 +386,27 @@ - (PHImageRequestID)requestImageDataForAsset:(PHAsset *)asset completion:(void ( }; options.networkAccessAllowed = YES; options.resizeMode = PHImageRequestOptionsResizeModeFast; - int32_t imageRequestID = [[PHImageManager defaultManager] requestImageDataForAsset:asset options:options resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) { + int32_t imageRequestID = [[TZImageManager manager] requestImageDataFitSystemForAsset:asset options:options completion:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) { if (completion) completion(imageData,dataUTI,orientation,info); }]; return imageRequestID; } +//适配iOS13 +- (PHImageRequestID)requestImageDataFitSystemForAsset:(PHAsset *)asset options:(nullable PHImageRequestOptions *)options completion:(void (^_Nonnull)(NSData *_Nullable imageData, NSString *_Nullable dataUTI, UIImageOrientation orientation, NSDictionary *_Nullable info))completion { + int32_t imageRequestID = 0; + if (@available(iOS 13.0, *)) { + imageRequestID = [[PHImageManager defaultManager] requestImageDataAndOrientationForAsset:asset options:options resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, CGImagePropertyOrientation orientation, NSDictionary * _Nullable info) { + if (completion) completion(imageData,dataUTI,[self imageOrientationWithCGImageOrientation:orientation],info); + }]; + } else { + imageRequestID = [[PHImageManager defaultManager] requestImageDataForAsset:asset options:options resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) { + if (completion) completion(imageData,dataUTI,orientation,info); + }]; + } + return imageRequestID; +} + - (PHImageRequestID)getPhotoWithAsset:(PHAsset *)asset photoWidth:(CGFloat)photoWidth completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler networkAccessAllowed:(BOOL)networkAccessAllowed { CGSize imageSize; if (photoWidth < TZScreenWidth && photoWidth < _photoPreviewMaxWidth) { @@ -423,7 +449,7 @@ - (PHImageRequestID)getPhotoWithAsset:(PHAsset *)asset photoWidth:(CGFloat)photo }; options.networkAccessAllowed = YES; options.resizeMode = PHImageRequestOptionsResizeModeFast; - [[PHImageManager defaultManager] requestImageDataForAsset:asset options:options resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) { + [[TZImageManager manager] requestImageDataFitSystemForAsset:asset options:options completion:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) { UIImage *resultImage = [UIImage imageWithData:imageData]; if (![TZImagePickerConfig sharedInstance].notScaleImage) { resultImage = [self scaleImage:resultImage toSize:imageSize]; @@ -473,7 +499,7 @@ - (PHImageRequestID)getOriginalPhotoWithAsset:(PHAsset *)asset progressHandler:( [option setProgressHandler:progressHandler]; } option.resizeMode = PHImageRequestOptionsResizeModeFast; - return [[PHImageManager defaultManager] requestImageDataForAsset:asset options:option resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) { + return [[TZImageManager manager] requestImageDataFitSystemForAsset:asset options:option completion:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) { BOOL cancelled = [[info objectForKey:PHImageCancelledKey] boolValue]; if (!cancelled && imageData) { UIImage *result = [self fixOrientation:[UIImage imageWithData:imageData]]; @@ -496,7 +522,7 @@ - (PHImageRequestID)getOriginalPhotoDataWithAsset:(PHAsset *)asset progressHandl } [option setProgressHandler:progressHandler]; option.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat; - return [[PHImageManager defaultManager] requestImageDataForAsset:asset options:option resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) { + return [[TZImageManager manager] requestImageDataFitSystemForAsset:asset options:option completion:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) { BOOL cancelled = [[info objectForKey:PHImageCancelledKey] boolValue]; if (!cancelled && imageData) { if (completion) completion(imageData,info,NO); @@ -1063,6 +1089,30 @@ - (UIImage *)fixOrientation:(UIImage *)aImage { return img; } +- (UIImageOrientation)imageOrientationWithCGImageOrientation:(CGImagePropertyOrientation)orientation { + UIImageOrientation sureOrientation; + if (orientation == kCGImagePropertyOrientationUp) { + sureOrientation = UIImageOrientationUp; + } else if (orientation == kCGImagePropertyOrientationUpMirrored) { + sureOrientation = UIImageOrientationUpMirrored; + } else if (orientation == kCGImagePropertyOrientationDown) { + sureOrientation = UIImageOrientationDown; + } else if (orientation == kCGImagePropertyOrientationDownMirrored) { + sureOrientation = UIImageOrientationDownMirrored; + } else if (orientation == kCGImagePropertyOrientationLeftMirrored) { + sureOrientation = UIImageOrientationLeftMirrored; + } else if (orientation == kCGImagePropertyOrientationRight) { + sureOrientation = UIImageOrientationRight; + } else if (orientation == kCGImagePropertyOrientationRightMirrored) { + sureOrientation = UIImageOrientationRightMirrored; + } else if (orientation == kCGImagePropertyOrientationLeft) { + sureOrientation = UIImageOrientationLeft; + } else { + sureOrientation = UIImageOrientationUp; + } + return sureOrientation; +} + #pragma clang diagnostic pop @end diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController.h b/TZImagePickerController/TZImagePickerController/TZImagePickerController.h index 2a4069ef..47435a6f 100644 --- a/TZImagePickerController/TZImagePickerController/TZImagePickerController.h +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController.h @@ -24,6 +24,7 @@ #import "TZGifPhotoPreviewController.h" #import "TZPhotoPreviewController.h" #import "TZPhotoPreviewCell.h" +#import "TZAssetCell.h" #if __has_include("TZLocationManager.h") #define TZ_HAVE_LOCATION_CODE 1 @@ -35,7 +36,7 @@ #define CURRENT_SYSTEM_VERSION [[UIDevice currentDevice] systemVersion] #define SYSTEM_VERSION_GREATER_THAN_15 ([CURRENT_SYSTEM_VERSION floatValue] >= 15.0) -@class TZAlbumCell, TZAssetCell; +@class TZAlbumCell; @protocol TZImagePickerControllerDelegate; @interface TZImagePickerController : UINavigationController @@ -375,6 +376,11 @@ + (void)configBarButtonItem:(UIBarButtonItem *)item tzImagePickerVc:(TZImagePickerController *)tzImagePickerVc; + (BOOL)isICloudSyncError:(NSError *)error; + (BOOL)isAssetNotSelectable:(TZAssetModel *)model tzImagePickerVc:(TZImagePickerController *)tzImagePickerVc; ++ (UIWindowScene *)currentWindowScene API_AVAILABLE(ios(13.0)); ++ (UIWindow *)currentKeyWindow; ++ (BOOL)currentStatusBarHidden; ++ (BOOL)currentStatusBarStyle; + @end diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController.m b/TZImagePickerController/TZImagePickerController/TZImagePickerController.m index 8487c27f..02760f65 100644 --- a/TZImagePickerController/TZImagePickerController/TZImagePickerController.m +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController.m @@ -11,7 +11,6 @@ #import "TZPhotoPickerController.h" #import "TZPhotoPreviewController.h" #import "TZAssetModel.h" -#import "TZAssetCell.h" #import "UIView+TZLayout.h" #import "TZImageManager.h" #import "TZVideoCropController.h" @@ -51,7 +50,7 @@ - (instancetype)init { #pragma clang diagnostic ignored "-Wdeprecated-declarations" - (void)viewDidLoad { [super viewDidLoad]; - self.needShowStatusBar = ![UIApplication sharedApplication].statusBarHidden; + self.needShowStatusBar = ![TZCommonTools currentStatusBarHidden]; if (@available(iOS 13.0, *)) { self.view.backgroundColor = UIColor.tertiarySystemBackgroundColor; } else { @@ -68,8 +67,11 @@ - (void)viewDidLoad { self.navigationBar.barTintColor = [UIColor colorWithRed:(34/255.0) green:(34/255.0) blue:(34/255.0) alpha:1.0]; self.navigationBar.tintColor = [UIColor whiteColor]; - self.automaticallyAdjustsScrollViewInsets = NO; - if (self.needShowStatusBar) [UIApplication sharedApplication].statusBarHidden = NO; + if (@available(iOS 11.0, *)) { + + } else { + self.automaticallyAdjustsScrollViewInsets = NO; + } } - (void)setNaviBgColor:(UIColor *)naviBgColor { @@ -137,7 +139,7 @@ - (void)setIsStatusBarDefault:(BOOL)isStatusBarDefault { - (void)configBarButtonItemAppearance { UIBarButtonItem *barItem; - if (@available(iOS 9, *)) { + if (@available(iOS 9.0, *)) { barItem = [UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[TZImagePickerController class]]]; } else { barItem = [UIBarButtonItem appearanceWhenContainedIn:[TZImagePickerController class], nil]; @@ -150,17 +152,19 @@ - (void)configBarButtonItemAppearance { - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; - _originStatusBarStyle = [UIApplication sharedApplication].statusBarStyle; - [UIApplication sharedApplication].statusBarStyle = self.statusBarStyle; + _originStatusBarStyle = [TZCommonTools currentStatusBarStyle]; [self configNavigationBarAppearance]; } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; - [UIApplication sharedApplication].statusBarStyle = _originStatusBarStyle; [self hideProgressHUD]; } +- (BOOL)prefersStatusBarHidden { + return !self.needShowStatusBar; +} + - (UIStatusBarStyle)preferredStatusBarStyle { return self.statusBarStyle; } @@ -220,7 +224,13 @@ - (instancetype)initWithMaxImagesCount:(NSInteger)maxImagesCount columnNumber:(N [self.view addSubview:_settingBtn]; - if ([PHPhotoLibrary authorizationStatus] == 0) { + PHAuthorizationStatus orizationStatus = 0; + if (@available(iOS 14.0, *)) { + orizationStatus = [PHPhotoLibrary authorizationStatusForAccessLevel:PHAccessLevelReadWrite]; + } else { + orizationStatus = [PHPhotoLibrary authorizationStatus]; + } + if (orizationStatus == 0) { _timer = [NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:@selector(observeAuthrizationStatusChange) userInfo:nil repeats:NO]; } } else { @@ -408,7 +418,13 @@ - (void)setNeedFixComposition:(BOOL)needFixComposition { - (void)observeAuthrizationStatusChange { [_timer invalidate]; _timer = nil; - if ([PHPhotoLibrary authorizationStatus] == 0) { + PHAuthorizationStatus orizationStatus = 0; + if (@available(iOS 14.0, *)) { + orizationStatus = [PHPhotoLibrary authorizationStatusForAccessLevel:PHAccessLevelReadWrite]; + } else { + orizationStatus = [PHPhotoLibrary authorizationStatus]; + } + if (orizationStatus == 0) { _timer = [NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:@selector(observeAuthrizationStatusChange) userInfo:nil repeats:NO]; } @@ -656,11 +672,22 @@ - (void)setSortAscendingByModificationDate:(BOOL)sortAscendingByModificationDate } - (void)settingBtnClick { - [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]; + NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString]; + if ([[UIApplication sharedApplication]canOpenURL:url]) { + if (@available(iOS 10.0, *)) { + [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil]; + } else { + [[UIApplication sharedApplication] openURL:url]; + } + } } - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated { - viewController.automaticallyAdjustsScrollViewInsets = NO; + if (@available(iOS 11.0, *)) { + + } else { + viewController.automaticallyAdjustsScrollViewInsets = NO; + } [super pushViewController:viewController animated:animated]; } @@ -695,13 +722,7 @@ - (UIImage *)createImageWithColor:(UIColor *)color size:(CGSize)size radius:(CGF } #pragma mark - UIContentContainer - - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator { - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.02 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - if (![UIApplication sharedApplication].statusBarHidden) { - if (self.needShowStatusBar) [UIApplication sharedApplication].statusBarHidden = NO; - } - }); if (size.width > size.height) { _cropRect = _cropRectLandscape; } else { @@ -821,6 +842,9 @@ - (void)configTableView { if (!self->_tableView) { self->_tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain]; + if (@available(iOS 11.0, *)) { + self->_tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; + } self->_tableView.rowHeight = 70; if (@available(iOS 13.0, *)) { self->_tableView.backgroundColor = [UIColor tertiarySystemBackgroundColor]; @@ -872,7 +896,7 @@ - (void)viewDidLayoutSubviews { CGFloat top = 0; CGFloat tableViewHeight = 0; CGFloat naviBarHeight = self.navigationController.navigationBar.tz_height; - BOOL isStatusBarHidden = [UIApplication sharedApplication].isStatusBarHidden; + BOOL isStatusBarHidden = [TZCommonTools currentStatusBarHidden]; BOOL isFullScreen = self.view.tz_height == [UIScreen mainScreen].bounds.size.height; if (self.navigationController.navigationBar.isTranslucent) { top = naviBarHeight; @@ -943,13 +967,7 @@ + (UIImage *)tz_imageNamedFromMyBundle:(NSString *)name { @implementation TZCommonTools + (UIEdgeInsets)tz_safeAreaInsets { - UIWindow *window = [UIApplication sharedApplication].windows.firstObject; - if (![window isKeyWindow]) { - UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow; - if (CGRectEqualToRect(keyWindow.bounds, [UIScreen mainScreen].bounds)) { - window = keyWindow; - } - } + UIWindow *window = [TZCommonTools currentKeyWindow]; if (@available(iOS 11.0, *)) { UIEdgeInsets insets = [window safeAreaInsets]; return insets; @@ -972,9 +990,17 @@ + (BOOL)tz_isIPhoneX { } + (BOOL)tz_isLandscape { - if ([UIApplication sharedApplication].statusBarOrientation == UIDeviceOrientationLandscapeRight || - [UIApplication sharedApplication].statusBarOrientation == UIDeviceOrientationLandscapeLeft) { - return true; + if (@available(iOS 13.0, *)) { + UIWindowScene *windowScene = [TZCommonTools currentWindowScene]; + if (windowScene.interfaceOrientation == UIDeviceOrientationLandscapeRight || + windowScene.interfaceOrientation == UIDeviceOrientationLandscapeLeft) { + return true; + } + } else { + if ([UIApplication sharedApplication].statusBarOrientation == UIDeviceOrientationLandscapeRight || + [UIApplication sharedApplication].statusBarOrientation == UIDeviceOrientationLandscapeLeft) { + return true; + } } return false; } @@ -1057,6 +1083,54 @@ + (BOOL)isAssetNotSelectable:(TZAssetModel *)model tzImagePickerVc:(TZImagePicke return notSelectable; } ++ (UIWindowScene *)currentWindowScene API_AVAILABLE(ios(13.0)) { + __block UIScene * _Nonnull tempScene; + [[[UIApplication sharedApplication] connectedScenes] enumerateObjectsUsingBlock:^(UIScene * _Nonnull obj, BOOL * _Nonnull stop) { + if (obj.activationState == UISceneActivationStateForegroundActive || obj.activationState == UISceneActivationStateForegroundInactive) { + tempScene = obj; + *stop = YES; + } + }]; + UIWindowScene *windowScene = (UIWindowScene *)tempScene; + return windowScene; +} + ++ (UIWindow *)currentKeyWindow { + if (@available(iOS 13.0, *)) { + UIWindowScene *windowScene = [TZCommonTools currentWindowScene]; + if (@available(iOS 15.0, *)) { + return windowScene.keyWindow; + } else { + for (UIWindow *window in windowScene.windows) { + if (window.isKeyWindow) { + return window; + } + } + } + } else { + return UIApplication.sharedApplication.keyWindow; + } + return nil; +} + ++ (BOOL)currentStatusBarHidden { + if (@available(iOS 13.0, *)) { + UIWindowScene *windowScene = [TZCommonTools currentWindowScene]; + return windowScene.statusBarManager.statusBarHidden; + } else { + return [UIApplication sharedApplication].statusBarHidden; + } +} + ++ (BOOL)currentStatusBarStyle { + if (@available(iOS 13.0, *)) { + UIWindowScene *windowScene = [TZCommonTools currentWindowScene]; + return windowScene.statusBarManager.statusBarStyle; + } else { + return [UIApplication sharedApplication].statusBarStyle; + } +} + @end diff --git a/TZImagePickerController/TZImagePickerController/TZPhotoPickerController.m b/TZImagePickerController/TZImagePickerController/TZPhotoPickerController.m index bfdc65a3..53489df4 100755 --- a/TZImagePickerController/TZImagePickerController/TZPhotoPickerController.m +++ b/TZImagePickerController/TZImagePickerController/TZPhotoPickerController.m @@ -66,7 +66,7 @@ - (UIImagePickerController *)imagePickerVc { _imagePickerVc.navigationBar.barTintColor = self.navigationController.navigationBar.barTintColor; _imagePickerVc.navigationBar.tintColor = self.navigationController.navigationBar.tintColor; UIBarButtonItem *tzBarItem, *BarItem; - if (@available(iOS 9, *)) { + if (@available(iOS 9.0, *)) { tzBarItem = [UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[TZImagePickerController class]]]; BarItem = [UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[UIImagePickerController class]]]; } else { @@ -111,12 +111,15 @@ - (void)viewDidLoad { _showTakePhotoBtn = _model.isCameraRoll && ((tzImagePickerVc.allowTakePicture && tzImagePickerVc.allowPickingImage) || (tzImagePickerVc.allowTakeVideo && tzImagePickerVc.allowPickingVideo)); _authorizationLimited = _model.isCameraRoll && [[TZImageManager manager] isPHAuthorizationStatusLimited]; // [self resetCachedAssets]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didChangeStatusBarOrientationNotification:) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil]; - self.operationQueue = [[NSOperationQueue alloc] init]; self.operationQueue.maxConcurrentOperationCount = 3; } +#pragma mark - UIContentContainer +- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator { + _offsetItemCount = _collectionView.contentOffset.y / (_layout.itemSize.height + _layout.minimumLineSpacing); +} + - (void)fetchAssetModels { TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; if (_isFirstAppear && !_model.models.count) { @@ -178,6 +181,9 @@ - (void)configCollectionView { if (!_collectionView) { _layout = [[UICollectionViewFlowLayout alloc] init]; _collectionView = [[TZCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:_layout]; + if (@available(iOS 11.0, *)) { + _collectionView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; + } if (@available(iOS 13.0, *)) { _collectionView.backgroundColor = UIColor.tertiarySystemBackgroundColor; } else { @@ -365,7 +371,7 @@ - (void)viewDidLayoutSubviews { CGFloat collectionViewHeight = 0; CGFloat naviBarHeight = self.navigationController.navigationBar.tz_height; CGFloat footerTipViewH = _authorizationLimited ? 80 : 0; - BOOL isStatusBarHidden = [UIApplication sharedApplication].isStatusBarHidden; + BOOL isStatusBarHidden = [TZCommonTools currentStatusBarHidden]; BOOL isFullScreen = self.view.tz_height == [UIScreen mainScreen].bounds.size.height; CGFloat toolBarHeight = 50 + [TZCommonTools tz_safeAreaInsets].bottom; if (self.navigationController.navigationBar.isTranslucent) { @@ -427,12 +433,6 @@ - (void)viewDidLayoutSubviews { } } -#pragma mark - Notification - -- (void)didChangeStatusBarOrientationNotification:(NSNotification *)noti { - _offsetItemCount = _collectionView.contentOffset.y / (_layout.itemSize.height + _layout.minimumLineSpacing); -} - #pragma mark - Click Event - (void)navLeftBarButtonClick{ [self.navigationController popViewControllerAnimated:YES]; @@ -793,7 +793,14 @@ - (void)takePhoto { UIAlertAction *cancelAct = [UIAlertAction actionWithTitle:[NSBundle tz_localizedStringForKey:@"Cancel"] style:UIAlertActionStyleCancel handler:nil]; [alertController addAction:cancelAct]; UIAlertAction *settingAct = [UIAlertAction actionWithTitle:[NSBundle tz_localizedStringForKey:@"Setting"] style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { - [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]; + NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString]; + if ([[UIApplication sharedApplication]canOpenURL:url]) { + if (@available(iOS 10.0, *)) { + [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil]; + } else { + [[UIApplication sharedApplication] openURL:url]; + } + } }]; [alertController addAction:settingAct]; [self.navigationController presentViewController:alertController animated:YES completion:nil]; @@ -812,11 +819,18 @@ - (void)takePhoto { } - (void)openSettingsApplication { - [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]; + NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString]; + if ([[UIApplication sharedApplication]canOpenURL:url]) { + if (@available(iOS 10.0, *)) { + [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil]; + } else { + [[UIApplication sharedApplication] openURL:url]; + } + } } - (void)addMorePhoto { - if (@available(iOS 14, *)) { + if (@available(iOS 14.0, *)) { [[PHPhotoLibrary sharedPhotoLibrary] presentLimitedLibraryPickerFromViewController:self]; } } diff --git a/TZImagePickerController/TZImagePickerController/TZPhotoPreviewCell.m b/TZImagePickerController/TZImagePickerController/TZPhotoPreviewCell.m index 4e077b38..b0f44639 100644 --- a/TZImagePickerController/TZImagePickerController/TZPhotoPreviewCell.m +++ b/TZImagePickerController/TZImagePickerController/TZPhotoPreviewCell.m @@ -118,7 +118,7 @@ - (instancetype)initWithFrame:(CGRect)frame { _scrollView.delaysContentTouches = NO; _scrollView.canCancelContentTouches = YES; _scrollView.alwaysBounceVertical = NO; - if (@available(iOS 11, *)) { + if (@available(iOS 11.0, *)) { _scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; } [self addSubview:_scrollView]; @@ -516,10 +516,11 @@ - (void)playButtonClick { CMTime durationTime = _player.currentItem.duration; if (_player.rate == 0.0f) { [[NSNotificationCenter defaultCenter] postNotificationName:@"TZ_VIDEO_PLAY_NOTIFICATION" object:_player]; - if (currentTime.value == durationTime.value) [_player.currentItem seekToTime:CMTimeMake(0, 1)]; + if (currentTime.value == durationTime.value) { + [_player.currentItem seekToTime:CMTimeMake(0, 1) completionHandler:nil]; + } [_player play]; [_playButton setImage:nil forState:UIControlStateNormal]; - [UIApplication sharedApplication].statusBarHidden = YES; if (self.singleTapGestureBlock) { self.singleTapGestureBlock(); } diff --git a/TZImagePickerController/TZImagePickerController/TZPhotoPreviewController.m b/TZImagePickerController/TZImagePickerController/TZPhotoPreviewController.m index 6b55cf7f..67a1ed50 100644 --- a/TZImagePickerController/TZImagePickerController/TZPhotoPreviewController.m +++ b/TZImagePickerController/TZImagePickerController/TZPhotoPreviewController.m @@ -62,7 +62,11 @@ - (void)viewDidLoad { [self configCustomNaviBar]; [self configBottomToolBar]; self.view.clipsToBounds = YES; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didChangeStatusBarOrientationNotification:) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil]; +} + +#pragma mark - UIContentContainer +- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator { + _offsetItemCount = _collectionView.contentOffset.x / _layout.itemSize.width; } - (void)setIsSelectOriginalPhoto:(BOOL)isSelectOriginalPhoto { @@ -78,7 +82,6 @@ - (void)setPhotos:(NSMutableArray *)photos { - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [self.navigationController setNavigationBarHidden:YES animated:YES]; - [UIApplication sharedApplication].statusBarHidden = YES; if (_currentIndex) { [_collectionView setContentOffset:CGPointMake((self.view.tz_width + 20) * self.currentIndex, 0) animated:NO]; } @@ -87,10 +90,6 @@ - (void)viewWillAppear:(BOOL)animated { - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; - TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; - if (tzImagePickerVc.needShowStatusBar) { - [UIApplication sharedApplication].statusBarHidden = NO; - } [self.navigationController setNavigationBarHidden:NO animated:YES]; [TZImageManager manager].shouldFixOrientation = NO; } @@ -207,7 +206,7 @@ - (void)configCollectionView { _collectionView.showsHorizontalScrollIndicator = NO; _collectionView.contentOffset = CGPointMake(0, 0); _collectionView.contentSize = CGSizeMake(self.models.count * (self.view.tz_width + 20), 0); - if (@available(iOS 11, *)) { + if (@available(iOS 11.0, *)) { _collectionView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; } [self.view addSubview:_collectionView]; @@ -263,11 +262,10 @@ - (void)viewDidLayoutSubviews { BOOL isFullScreen = self.view.tz_height == [UIScreen mainScreen].bounds.size.height; CGFloat statusBarHeight = isFullScreen ? [TZCommonTools tz_statusBarHeight] : 0; - CGFloat statusBarHeightInterval = isFullScreen ? (statusBarHeight - 20) : 0; CGFloat naviBarHeight = statusBarHeight + _tzImagePickerVc.navigationBar.tz_height; _naviBar.frame = CGRectMake(0, 0, self.view.tz_width, naviBarHeight); - _backButton.frame = CGRectMake(10, 10 + statusBarHeightInterval, 44, 44); - _selectButton.frame = CGRectMake(self.view.tz_width - 56, 10 + statusBarHeightInterval, 44, 44); + _backButton.frame = CGRectMake(10, statusBarHeight, 44, 44); + _selectButton.frame = CGRectMake(self.view.tz_width - 54, statusBarHeight, 44, 44); _indexLabel.frame = _selectButton.frame; _layout.itemSize = CGSizeMake(self.view.tz_width + 20, self.view.tz_height); @@ -303,12 +301,6 @@ - (void)viewDidLayoutSubviews { } } -#pragma mark - Notification - -- (void)didChangeStatusBarOrientationNotification:(NSNotification *)noti { - _offsetItemCount = _collectionView.contentOffset.x / _layout.itemSize.width; -} - #pragma mark - Click Event - (void)select:(UIButton *)selectButton { diff --git a/TZImagePickerController/TZImagePickerController/TZVideoCropController.m b/TZImagePickerController/TZImagePickerController/TZVideoCropController.m index a631a609..4d806a8e 100644 --- a/TZImagePickerController/TZImagePickerController/TZVideoCropController.m +++ b/TZImagePickerController/TZImagePickerController/TZVideoCropController.m @@ -66,7 +66,11 @@ - (void)viewDidLoad { - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; - [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent; + if (@available(iOS 9.0, *)) { + + } else { + [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent; + } } - (void)viewWillDisappear:(BOOL)animated { @@ -142,6 +146,9 @@ - (void)configVideoImageCollectionView { layout.minimumLineSpacing = 0; layout.minimumInteritemSpacing = 0; _collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; + if (@available(iOS 11.0, *)) { + _collectionView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; + } _collectionView.dataSource = self; _collectionView.delegate = self; _collectionView.contentInset = UIEdgeInsetsMake(0, VideoEditLeftMargin + PanImageWidth, 0, VideoEditLeftMargin + PanImageWidth); @@ -315,7 +322,9 @@ - (void)playButtonClick { CMTime durationTime = _player.currentItem.duration; if (_player.rate == 0.0f) { [[NSNotificationCenter defaultCenter] postNotificationName:@"TZ_VIDEO_PLAY_NOTIFICATION" object:_player]; - if (currentTime.value == durationTime.value) [_player.currentItem seekToTime:CMTimeMake(0, 1)]; + if (currentTime.value == durationTime.value) { + [_player.currentItem seekToTime:CMTimeMake(0, 1) completionHandler:nil]; + } _isPlayed = YES; [self starTimer]; [_playButton setImage:nil forState:UIControlStateNormal]; diff --git a/TZImagePickerController/TZImagePickerController/TZVideoEditedPreviewController.m b/TZImagePickerController/TZImagePickerController/TZVideoEditedPreviewController.m index b9755c1e..3d1b0986 100644 --- a/TZImagePickerController/TZImagePickerController/TZVideoEditedPreviewController.m +++ b/TZImagePickerController/TZImagePickerController/TZVideoEditedPreviewController.m @@ -99,7 +99,9 @@ - (void)playButtonClick { CMTime currentTime = _player.currentItem.currentTime; CMTime durationTime = _player.currentItem.duration; if (_player.rate == 0.0f) { - if (currentTime.value == durationTime.value) [_player.currentItem seekToTime:CMTimeMake(0, 1)]; + if (currentTime.value == durationTime.value) { + [_player.currentItem seekToTime:CMTimeMake(0, 1) completionHandler:nil]; + } [_player play]; _toolBar.hidden = YES; [_playButton setImage:nil forState:UIControlStateNormal]; diff --git a/TZImagePickerController/TZImagePickerController/TZVideoPlayerController.m b/TZImagePickerController/TZImagePickerController/TZVideoPlayerController.m index 7175b4df..e7089f56 100644 --- a/TZImagePickerController/TZImagePickerController/TZVideoPlayerController.m +++ b/TZImagePickerController/TZImagePickerController/TZVideoPlayerController.m @@ -45,7 +45,7 @@ @implementation TZVideoPlayerController - (void)viewDidLoad { [super viewDidLoad]; - self.needShowStatusBar = ![UIApplication sharedApplication].statusBarHidden; + self.needShowStatusBar = ![TZCommonTools currentStatusBarHidden]; self.view.backgroundColor = [UIColor blackColor]; TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; if (tzImagePickerVc) { @@ -57,16 +57,11 @@ - (void)viewDidLoad { - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; - _originStatusBarStyle = [UIApplication sharedApplication].statusBarStyle; - [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent; + _originStatusBarStyle = [TZCommonTools currentStatusBarStyle]; } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; - if (self.needShowStatusBar) { - [UIApplication sharedApplication].statusBarHidden = NO; - } - [UIApplication sharedApplication].statusBarStyle = _originStatusBarStyle; } - (void)configMoviePlayer { @@ -155,6 +150,10 @@ - (void)configBottomToolBar { } } +- (BOOL)prefersStatusBarHidden { + return !self.needShowStatusBar; +} + - (UIStatusBarStyle)preferredStatusBarStyle { TZImagePickerController *tzImagePicker = (TZImagePickerController *)self.navigationController; if (tzImagePicker && [tzImagePicker isKindOfClass:[TZImagePickerController class]]) { @@ -195,13 +194,14 @@ - (void)playButtonClick { CMTime durationTime = _player.currentItem.duration; if (_player.rate == 0.0f) { [[NSNotificationCenter defaultCenter] postNotificationName:@"TZ_VIDEO_PLAY_NOTIFICATION" object:_player]; - if (currentTime.value == durationTime.value) [_player.currentItem seekToTime:CMTimeMake(0, 1)]; + if (currentTime.value == durationTime.value) { + [_player.currentItem seekToTime:CMTimeMake(0, 1) completionHandler:nil]; + } [_player play]; [self.navigationController setNavigationBarHidden:YES]; _toolBar.hidden = YES; _playButtonNormalImage = [_playButton imageForState:UIControlStateNormal]; [_playButton setImage:nil forState:UIControlStateNormal]; - [UIApplication sharedApplication].statusBarHidden = YES; } else { [self pausePlayerAndShowNaviBar]; } @@ -290,10 +290,6 @@ - (void)pausePlayerAndShowNaviBar { [self.navigationController setNavigationBarHidden:NO]; UIImage *normalImage = _playButtonNormalImage ?: [UIImage tz_imageNamedFromMyBundle:@"MMVideoPreviewPlay"]; [_playButton setImage:normalImage forState:UIControlStateNormal]; - - if (self.needShowStatusBar) { - [UIApplication sharedApplication].statusBarHidden = NO; - } } #pragma mark - lazy diff --git a/TZImagePickerController/ViewController.m b/TZImagePickerController/ViewController.m index 3408a3eb..1bc175dd 100644 --- a/TZImagePickerController/ViewController.m +++ b/TZImagePickerController/ViewController.m @@ -68,7 +68,7 @@ - (UIImagePickerController *)imagePickerVc { _imagePickerVc.navigationBar.barTintColor = self.navigationController.navigationBar.barTintColor; _imagePickerVc.navigationBar.tintColor = self.navigationController.navigationBar.tintColor; UIBarButtonItem *tzBarItem, *BarItem; - if (@available(iOS 9, *)) { + if (@available(iOS 9.0, *)) { tzBarItem = [UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[TZImagePickerController class]]]; BarItem = [UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[UIImagePickerController class]]]; } else { @@ -98,6 +98,9 @@ - (void)configCollectionView { // 如不需要长按排序效果,将LxGridViewFlowLayout类改成UICollectionViewFlowLayout即可 _layout = [[LxGridViewFlowLayout alloc] init]; _collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:_layout]; + if (@available(iOS 11.0, *)) { + _collectionView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; + } CGFloat rgb = 244 / 255.0; _collectionView.alwaysBounceVertical = YES; _collectionView.backgroundColor = [UIColor colorWithRed:rgb green:rgb blue:rgb alpha:1.0]; @@ -449,7 +452,14 @@ - (void)takePhoto { UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"无法使用相机" message:@"请在iPhone的""设置-隐私-相机""中允许访问相机" preferredStyle:UIAlertControllerStyleAlert]; [alertController addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil]]; [alertController addAction:[UIAlertAction actionWithTitle:@"设置" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { - [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]; + NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString]; + if ([[UIApplication sharedApplication]canOpenURL:url]) { + if (@available(iOS 10.0, *)) { + [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil]; + } else { + [[UIApplication sharedApplication] openURL:url]; + } + } }]]; [self presentViewController:alertController animated:YES completion:nil]; } else if (authStatus == AVAuthorizationStatusNotDetermined) { @@ -462,19 +472,34 @@ - (void)takePhoto { } }]; // 拍照之前还需要检查相册权限 - } else if ([PHPhotoLibrary authorizationStatus] == 2) { // 已被拒绝,没有相册权限,将无法保存拍的照片 - UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"无法访问相册" message:@"请在iPhone的""设置-隐私-相册""中允许访问相册" preferredStyle:UIAlertControllerStyleAlert]; - [alertController addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil]]; - [alertController addAction:[UIAlertAction actionWithTitle:@"设置" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { - [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]; - }]]; - [self presentViewController:alertController animated:YES completion:nil]; - } else if ([PHPhotoLibrary authorizationStatus] == 0) { // 未请求过相册权限 - [[TZImageManager manager] requestAuthorizationWithCompletion:^{ - [self takePhoto]; - }]; } else { - [self pushImagePickerController]; + PHAuthorizationStatus orizationStatus = 0; + if (@available(iOS 14.0, *)) { + orizationStatus = [PHPhotoLibrary authorizationStatusForAccessLevel:PHAccessLevelReadWrite]; + } else { + orizationStatus = [PHPhotoLibrary authorizationStatus]; + } + if (orizationStatus == 2) { // 已被拒绝,没有相册权限,将无法保存拍的照片 + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"无法访问相册" message:@"请在iPhone的""设置-隐私-相册""中允许访问相册" preferredStyle:UIAlertControllerStyleAlert]; + [alertController addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil]]; + [alertController addAction:[UIAlertAction actionWithTitle:@"设置" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { + NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString]; + if ([[UIApplication sharedApplication]canOpenURL:url]) { + if (@available(iOS 10.0, *)) { + [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil]; + } else { + [[UIApplication sharedApplication] openURL:url]; + } + } + }]]; + [self presentViewController:alertController animated:YES completion:nil]; + } else if (orizationStatus == 0) { // 未请求过相册权限 + [[TZImageManager manager] requestAuthorizationWithCompletion:^{ + [self takePhoto]; + }]; + } else { + [self pushImagePickerController]; + } } }