| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850 |
- //
- // FDPhotoGroupView.m
- // FDFoundationObjC
- //
- // Created by fandongtongxue on 2020/2/27.
- //
- #import "FDPhotoGroupView.h"
- #import "FDUIDefine.h"
- #import "FDUIColorDefine.h"
- #import "UIView+FD.h"
- #import <YYKit/YYKit.h>
- #import <FDFoundationObjC/FDFoundationObjC.h>
- #define kPadding 20
- #define kHiColor [UIColor colorWithRGBHex:0x2dd6b8]
- @interface FDPhotoGroupItem()<NSCopying>
- @property (nonatomic, readonly) UIImage *thumbImage;
- @property (nonatomic, readonly) BOOL thumbClippedToTop;
- - (BOOL)shouldClipToTop:(CGSize)imageSize forView:(UIView *)view;
- @end
- @implementation FDPhotoGroupItem
- - (UIImage *)thumbImage {
- if ([_thumbView respondsToSelector:@selector(image)]) {
- return ((UIImageView *)_thumbView).image;
- }
- return nil;
- }
- - (BOOL)thumbClippedToTop {
- if (_thumbView) {
- if (_thumbView.layer.contentsRect.size.height < 1) {
- return YES;
- }
- }
- return NO;
- }
- - (BOOL)shouldClipToTop:(CGSize)imageSize forView:(UIView *)view {
- if (imageSize.width < 1 || imageSize.height < 1) return NO;
- if (view.width < 1 || view.fd_height < 1) return NO;
- return imageSize.height / imageSize.width > view.width / view.fd_height;
- }
- - (id)copyWithZone:(NSZone *)zone {
- FDPhotoGroupItem *item = [self.class new];
- return item;
- }
- @end
- @interface FDPhotoGroupCell : UIScrollView <UIScrollViewDelegate>
- @property (nonatomic, strong) UIView *imageContainerView;
- @property (nonatomic, strong) UIImageView *imageView;
- @property (nonatomic, assign) NSInteger page;
- @property (nonatomic, assign) BOOL showProgress;
- @property (nonatomic, assign) CGFloat progress;
- @property (nonatomic, strong) CAShapeLayer *progressLayer;
- @property (nonatomic, strong) FDPhotoGroupItem *item;
- @property (nonatomic, readonly) BOOL itemDidLoad;
- - (void)resizeSubviewSize;
- @end
- @implementation FDPhotoGroupCell
- - (instancetype)init {
- self = super.init;
- if (!self) return nil;
- self.delegate = self;
- self.bouncesZoom = YES;
- self.maximumZoomScale = 3;
- self.multipleTouchEnabled = YES;
- self.alwaysBounceVertical = NO;
- self.showsVerticalScrollIndicator = YES;
- self.showsHorizontalScrollIndicator = NO;
- self.frame = [UIScreen mainScreen].bounds;
-
- _imageContainerView = [UIView new];
- _imageContainerView.clipsToBounds = YES;
- [self addSubview:_imageContainerView];
-
- _imageView = [UIImageView new];
- _imageView.clipsToBounds = YES;
- _imageView.backgroundColor = [UIColor colorWithWhite:1.000 alpha:0.500];
- [_imageContainerView addSubview:_imageView];
-
- _progressLayer = [CAShapeLayer layer];
- _progressLayer.size = CGSizeMake(40, 40);
- _progressLayer.cornerRadius = 20;
- _progressLayer.backgroundColor = [UIColor colorWithWhite:0.000 alpha:0.500].CGColor;
- UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectInset(_progressLayer.bounds, 7, 7) cornerRadius:(40 / 2 - 7)];
- _progressLayer.path = path.CGPath;
- _progressLayer.fillColor = [UIColor clearColor].CGColor;
- _progressLayer.strokeColor = [UIColor whiteColor].CGColor;
- _progressLayer.lineWidth = 4;
- _progressLayer.lineCap = kCALineCapRound;
- _progressLayer.strokeStart = 0;
- _progressLayer.strokeEnd = 0;
- _progressLayer.hidden = YES;
- [self.layer addSublayer:_progressLayer];
- return self;
- }
- - (void)layoutSubviews {
- [super layoutSubviews];
- _progressLayer.center = CGPointMake(self.width / 2, self.height / 2);
- }
- - (void)setItem:(FDPhotoGroupItem *)item {
- if (_item == item) return;
- _item = item;
- _itemDidLoad = NO;
-
-
- [self setZoomScale:1.0 animated:NO];
- self.maximumZoomScale = 1;
-
- [_imageView cancelCurrentImageRequest];
- [_imageView.layer removePreviousFadeAnimation];
-
- _progressLayer.hidden = NO;
- [CATransaction begin];
- [CATransaction setDisableActions:YES];
- _progressLayer.strokeEnd = 0;
- _progressLayer.hidden = YES;
- [CATransaction commit];
-
- if (!_item) {
- _imageView.image = nil;
- return;
- }
-
- @weakify(self);
- if (![item.largeImageURL.absoluteString hasPrefix:@"http"]) {
- _imageView.image = [UIImage imageWithContentsOfFile:item.largeImageURL.absoluteString];
- self.maximumZoomScale = 3;
- self->_itemDidLoad = YES;
-
- [self resizeSubviewSize];
- [self.imageView.layer addFadeAnimationWithDuration:0.1 curve:UIViewAnimationCurveLinear];
- }else{
- [_imageView setImageWithURL:item.largeImageURL placeholder:item.thumbImage options:kNilOptions progress:^(NSInteger receivedSize, NSInteger expectedSize) {
- @strongify(self);
- if (!self) return;
- CGFloat progress = receivedSize / (float)expectedSize;
- progress = progress < 0.01 ? 0.01 : progress > 1 ? 1 : progress;
- if (isnan(progress)) progress = 0;
- self.progressLayer.hidden = NO;
- self.progressLayer.strokeEnd = progress;
- } transform:nil completion:^(UIImage *image, NSURL *url, YYWebImageFromType from, YYWebImageStage stage, NSError *error) {
- @strongify(self);
- if (!self) return;
- self.progressLayer.hidden = YES;
- if (stage == YYWebImageStageFinished) {
- self.maximumZoomScale = 3;
- if (image) {
- self->_itemDidLoad = YES;
-
- [self resizeSubviewSize];
- [self.imageView.layer addFadeAnimationWithDuration:0.1 curve:UIViewAnimationCurveLinear];
- }
- }
-
- }];
- }
- [self resizeSubviewSize];
- }
- - (void)resizeSubviewSize {
- _imageContainerView.origin = CGPointZero;
- _imageContainerView.width = self.width;
-
- UIImage *image = _imageView.image;
- if (image.size.height / image.size.width > self.height / self.width) {
- _imageContainerView.height = floor(image.size.height / (image.size.width / self.width));
- } else {
- CGFloat height = image.size.height / image.size.width * self.width;
- if (height < 1 || isnan(height)) height = self.height;
- height = floor(height);
- _imageContainerView.height = height;
- _imageContainerView.centerY = self.height / 2;
- }
- if (_imageContainerView.height > self.height && _imageContainerView.height - self.height <= 1) {
- _imageContainerView.height = self.height;
- }
- self.contentSize = CGSizeMake(self.width, MAX(_imageContainerView.height, self.height));
- [self scrollRectToVisible:self.bounds animated:NO];
-
- if (_imageContainerView.height <= self.height) {
- self.alwaysBounceVertical = NO;
- } else {
- self.alwaysBounceVertical = YES;
- }
-
- [CATransaction begin];
- [CATransaction setDisableActions:YES];
- _imageView.frame = _imageContainerView.bounds;
- [CATransaction commit];
- }
- - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView{
- return _imageContainerView;
- }
- - (void)scrollViewDidZoom:(UIScrollView *)scrollView {
- UIView *subView = _imageContainerView;
-
- CGFloat offsetX = (scrollView.bounds.size.width > scrollView.contentSize.width)?
- (scrollView.bounds.size.width - scrollView.contentSize.width) * 0.5 : 0.0;
-
- CGFloat offsetY = (scrollView.bounds.size.height > scrollView.contentSize.height)?
- (scrollView.bounds.size.height - scrollView.contentSize.height) * 0.5 : 0.0;
-
- subView.center = CGPointMake(scrollView.contentSize.width * 0.5 + offsetX,
- scrollView.contentSize.height * 0.5 + offsetY);
- }
- @end
- @interface FDPhotoGroupView() <UIScrollViewDelegate, UIGestureRecognizerDelegate>
- @property (nonatomic, weak) UIView *fromView;
- @property (nonatomic, weak) UIView *toContainerView;
- @property (nonatomic, strong) UIImage *snapshotImage;
- @property (nonatomic, strong) UIImage *snapshorImageHideFromView;
- @property (nonatomic, strong) UIImageView *background;
- @property (nonatomic, strong) UIImageView *blurBackground;
- @property (nonatomic, strong) UIView *contentView;
- @property (nonatomic, strong) UIScrollView *scrollView;
- @property (nonatomic, strong) NSMutableArray *cells;
- @property (nonatomic, strong) UIPageControl *pager;
- @property (nonatomic, assign) CGFloat pagerCurrentPage;
- @property (nonatomic, assign) BOOL fromNavigationBarHidden;
- @property (nonatomic, assign) NSInteger fromItemIndex;
- @property (nonatomic, assign) BOOL isPresented;
- @property (nonatomic, strong) UIPanGestureRecognizer *panGesture;
- @property (nonatomic, assign) CGPoint panGestureBeginPoint;
- @end
- @implementation FDPhotoGroupView
- - (instancetype)initWithGroupItems:(NSArray *)groupItems {
- self = [super init];
- if (groupItems.count == 0) return nil;
- _groupItems = groupItems.copy;
- _blurEffectBackground = YES;
-
- NSString *model = [UIDevice currentDevice].machineModel;
- static NSMutableSet *oldDevices;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- oldDevices = [NSMutableSet new];
- [oldDevices addObject:@"iPod1,1"];
- [oldDevices addObject:@"iPod2,1"];
- [oldDevices addObject:@"iPod3,1"];
- [oldDevices addObject:@"iPod4,1"];
- [oldDevices addObject:@"iPod5,1"];
-
- [oldDevices addObject:@"iPhone1,1"];
- [oldDevices addObject:@"iPhone1,1"];
- [oldDevices addObject:@"iPhone1,2"];
- [oldDevices addObject:@"iPhone2,1"];
- [oldDevices addObject:@"iPhone3,1"];
- [oldDevices addObject:@"iPhone3,2"];
- [oldDevices addObject:@"iPhone3,3"];
- [oldDevices addObject:@"iPhone4,1"];
-
- [oldDevices addObject:@"iPad1,1"];
- [oldDevices addObject:@"iPad2,1"];
- [oldDevices addObject:@"iPad2,2"];
- [oldDevices addObject:@"iPad2,3"];
- [oldDevices addObject:@"iPad2,4"];
- [oldDevices addObject:@"iPad2,5"];
- [oldDevices addObject:@"iPad2,6"];
- [oldDevices addObject:@"iPad2,7"];
- [oldDevices addObject:@"iPad3,1"];
- [oldDevices addObject:@"iPad3,2"];
- [oldDevices addObject:@"iPad3,3"];
- });
- if ([oldDevices containsObject:model]) {
- _blurEffectBackground = NO;
- }
-
- self.backgroundColor = [UIColor clearColor];
- self.frame = [UIScreen mainScreen].bounds;
- self.clipsToBounds = YES;
-
- UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismiss)];
- tap.delegate = self;
- [self addGestureRecognizer:tap];
-
- UITapGestureRecognizer *tap2 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleTap:)];
- tap2.delegate = self;
- tap2.numberOfTapsRequired = 2;
- [tap requireGestureRecognizerToFail: tap2];
- [self addGestureRecognizer:tap2];
-
- UILongPressGestureRecognizer *press = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress)];
- press.delegate = self;
- [self addGestureRecognizer:press];
-
- if (kSystemVersion >= 7) {
- UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
- [self addGestureRecognizer:pan];
- _panGesture = pan;
- }
-
-
- _cells = @[].mutableCopy;
-
- _background = UIImageView.new;
- _background.frame = self.bounds;
- _background.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
-
- _blurBackground = UIImageView.new;
- _blurBackground.frame = self.bounds;
- _blurBackground.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
-
- _contentView = UIView.new;
- _contentView.frame = self.bounds;
- _contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
-
- _scrollView = UIScrollView.new;
- _scrollView.frame = CGRectMake(-kPadding / 2, 0, self.width + kPadding, self.height);
- _scrollView.delegate = self;
- _scrollView.scrollsToTop = NO;
- _scrollView.pagingEnabled = YES;
- _scrollView.alwaysBounceHorizontal = groupItems.count > 1;
- _scrollView.showsHorizontalScrollIndicator = NO;
- _scrollView.showsVerticalScrollIndicator = NO;
- _scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
- _scrollView.delaysContentTouches = NO;
- _scrollView.canCancelContentTouches = YES;
-
- _pager = [[UIPageControl alloc] init];
- _pager.hidesForSinglePage = YES;
- _pager.userInteractionEnabled = NO;
- _pager.width = self.width - 36;
- _pager.height = 10;
- _pager.center = CGPointMake(self.fd_width / 2, self.fd_height - 18);
- _pager.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
-
- [self addSubview:_background];
- [self addSubview:_blurBackground];
- [self addSubview:_contentView];
- [_contentView addSubview:_scrollView];
- [_contentView addSubview:_pager];
-
- return self;
- }
- - (void)presentFromImageView:(UIView *)fromView
- toContainer:(UIView *)toContainer
- animated:(BOOL)animated
- completion:(void (^)(void))completion {
- if (!toContainer) return;
-
- _fromView = fromView;
- _toContainerView = toContainer;
-
- NSInteger page = -1;
- for (NSUInteger i = 0; i < self.groupItems.count; i++) {
- if (fromView == ((FDPhotoGroupItem *)self.groupItems[i]).thumbView) {
- page = (int)i;
- break;
- }
- }
- if (page == -1) page = 0;
- _fromItemIndex = page;
-
- _snapshotImage = [_toContainerView snapshotImageAfterScreenUpdates:NO];
- BOOL fromViewHidden = fromView.hidden;
- fromView.hidden = YES;
- _snapshorImageHideFromView = [_toContainerView snapshotImage];
- fromView.hidden = fromViewHidden;
-
- _background.image = _snapshorImageHideFromView;
- if (_blurEffectBackground) {
- _blurBackground.image = [_snapshorImageHideFromView imageByBlurDark]; //Same to UIBlurEffectStyleDark
- } else {
- _blurBackground.image = [UIImage imageWithColor:[UIColor blackColor]];
- }
-
- self.size = _toContainerView.size;
- self.blurBackground.alpha = 0;
- self.pager.alpha = 0;
- self.pager.numberOfPages = self.groupItems.count;
- self.pager.currentPage = page;
- [_toContainerView addSubview:self];
-
- _scrollView.contentSize = CGSizeMake(_scrollView.width * self.groupItems.count, _scrollView.height);
- [_scrollView scrollRectToVisible:CGRectMake(_scrollView.width * _pager.currentPage, 0, _scrollView.width, _scrollView.height) animated:NO];
- [self scrollViewDidScroll:_scrollView];
-
- [UIView setAnimationsEnabled:YES];
- _fromNavigationBarHidden = [UIApplication sharedApplication].statusBarHidden;
- [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:animated ? UIStatusBarAnimationFade : UIStatusBarAnimationNone];
-
-
- FDPhotoGroupCell *cell = [self cellForPage:self.currentPage];
- FDPhotoGroupItem *item = _groupItems[self.currentPage];
-
- if (!item.thumbClippedToTop) {
- NSString *imageKey = [[YYWebImageManager sharedManager] cacheKeyForURL:item.largeImageURL];
- if ([[YYWebImageManager sharedManager].cache getImageForKey:imageKey withType:YYImageCacheTypeMemory]) {
- cell.item = item;
- }
- }
- if (!cell.item) {
- cell.imageView.image = item.thumbImage;
- [cell resizeSubviewSize];
- }
-
- if (item.thumbClippedToTop) {
- CGRect fromFrame = [_fromView convertRect:_fromView.bounds toView:cell];
- CGRect originFrame = cell.imageContainerView.frame;
- CGFloat scale = fromFrame.size.width / cell.imageContainerView.width;
-
- cell.imageContainerView.centerX = CGRectGetMidX(fromFrame);
- cell.imageContainerView.height = fromFrame.size.height / scale;
- cell.imageContainerView.layer.transformScale = scale;
- cell.imageContainerView.centerY = CGRectGetMidY(fromFrame);
-
- float oneTime = animated ? 0.25 : 0;
- [UIView animateWithDuration:oneTime delay:0 options:UIViewAnimationOptionBeginFromCurrentState|UIViewAnimationOptionCurveEaseInOut animations:^{
- _blurBackground.alpha = 1;
- }completion:NULL];
-
- _scrollView.userInteractionEnabled = NO;
- [UIView animateWithDuration:oneTime delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
- cell.imageContainerView.layer.transformScale = 1;
- cell.imageContainerView.frame = originFrame;
- _pager.alpha = 1;
- }completion:^(BOOL finished) {
- _isPresented = YES;
- [self scrollViewDidScroll:_scrollView];
- _scrollView.userInteractionEnabled = YES;
- [self hidePager];
- if (completion) completion();
- }];
-
- } else {
- CGRect fromFrame = [_fromView convertRect:_fromView.bounds toView:cell.imageContainerView];
-
- cell.imageContainerView.clipsToBounds = NO;
- cell.imageView.frame = fromFrame;
- cell.imageView.contentMode = UIViewContentModeScaleAspectFill;
-
- float oneTime = animated ? 0.18 : 0;
- [UIView animateWithDuration:oneTime*2 delay:0 options:UIViewAnimationOptionBeginFromCurrentState|UIViewAnimationOptionCurveEaseInOut animations:^{
- _blurBackground.alpha = 1;
- }completion:NULL];
-
- _scrollView.userInteractionEnabled = NO;
- [UIView animateWithDuration:oneTime delay:0 options:UIViewAnimationOptionBeginFromCurrentState|UIViewAnimationOptionCurveEaseInOut animations:^{
- cell.imageView.frame = cell.imageContainerView.bounds;
- cell.imageView.layer.transformScale = 1.01;
- }completion:^(BOOL finished) {
- [UIView animateWithDuration:oneTime delay:0 options:UIViewAnimationOptionBeginFromCurrentState|UIViewAnimationOptionCurveEaseInOut animations:^{
- cell.imageView.layer.transformScale = 1.0;
- _pager.alpha = 1;
- }completion:^(BOOL finished) {
- cell.imageContainerView.clipsToBounds = YES;
- _isPresented = YES;
- [self scrollViewDidScroll:_scrollView];
- _scrollView.userInteractionEnabled = YES;
- [self hidePager];
- if (completion) completion();
- }];
- }];
- }
- }
- - (void)dismissAnimated:(BOOL)animated completion:(void (^)(void))completion {
- [UIView setAnimationsEnabled:YES];
-
- [[UIApplication sharedApplication] setStatusBarHidden:_fromNavigationBarHidden withAnimation:animated ? UIStatusBarAnimationFade : UIStatusBarAnimationNone];
- NSInteger currentPage = self.currentPage;
- FDPhotoGroupCell *cell = [self cellForPage:currentPage];
- FDPhotoGroupItem *item = _groupItems[currentPage];
-
- UIView *fromView = nil;
- if (_fromItemIndex == currentPage) {
- fromView = _fromView;
- } else {
- fromView = item.thumbView;
- }
-
- [self cancelAllImageLoad];
- _isPresented = NO;
- BOOL isFromImageClipped = fromView.layer.contentsRect.size.height < 1;
-
- [CATransaction begin];
- [CATransaction setDisableActions:YES];
- if (isFromImageClipped) {
- CGRect frame = cell.imageContainerView.frame;
- cell.imageContainerView.layer.anchorPoint = CGPointMake(0.5, 0);
- cell.imageContainerView.frame = frame;
- }
- cell.progressLayer.hidden = YES;
- [CATransaction commit];
-
-
-
-
- if (fromView == nil) {
- self.background.image = _snapshotImage;
- [UIView animateWithDuration:animated ? 0.25 : 0 delay:0 options:UIViewAnimationOptionBeginFromCurrentState|UIViewAnimationOptionCurveEaseOut animations:^{
- self.alpha = 0.0;
- self.scrollView.layer.transformScale = 0.95;
- self.scrollView.alpha = 0;
- self.pager.alpha = 0;
- self.blurBackground.alpha = 0;
- }completion:^(BOOL finished) {
- self.scrollView.layer.transformScale = 1;
- [self removeFromSuperview];
- [self cancelAllImageLoad];
- if (completion) completion();
- }];
- return;
- }
-
- if (_fromItemIndex != currentPage) {
- _background.image = _snapshotImage;
- [_background.layer addFadeAnimationWithDuration:0.25 curve:UIViewAnimationCurveEaseOut];
- } else {
- _background.image = _snapshorImageHideFromView;
- }
-
- if (isFromImageClipped) {
- [cell scrollToTopAnimated:NO];
- }
-
- [UIView animateWithDuration:animated ? 0.2 : 0 delay:0 options:UIViewAnimationOptionBeginFromCurrentState|UIViewAnimationOptionCurveEaseOut animations:^{
- _pager.alpha = 0.0;
- _blurBackground.alpha = 0.0;
- if (isFromImageClipped) {
-
- CGRect fromFrame = [fromView convertRect:fromView.bounds toView:cell];
- CGFloat scale = fromFrame.size.width / cell.imageContainerView.width * cell.zoomScale;
- CGFloat height = fromFrame.size.height / fromFrame.size.width * cell.imageContainerView.width;
- if (isnan(height)) height = cell.imageContainerView.height;
-
- cell.imageContainerView.height = height;
- cell.imageContainerView.center = CGPointMake(CGRectGetMidX(fromFrame), CGRectGetMinY(fromFrame));
- cell.imageContainerView.layer.transformScale = scale;
-
- } else {
- CGRect fromFrame = [fromView convertRect:fromView.bounds toView:cell.imageContainerView];
- cell.imageContainerView.clipsToBounds = NO;
- cell.imageView.contentMode = fromView.contentMode;
- cell.imageView.frame = fromFrame;
- }
- }completion:^(BOOL finished) {
- [UIView animateWithDuration:animated ? 0.15 : 0 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
- self.alpha = 0;
- } completion:^(BOOL finished) {
- cell.imageContainerView.layer.anchorPoint = CGPointMake(0.5, 0.5);
- [self removeFromSuperview];
- if (completion) completion();
- }];
- }];
-
-
- }
- - (void)dismiss {
- [self dismissAnimated:YES completion:nil];
- }
- - (void)cancelAllImageLoad {
- [_cells enumerateObjectsUsingBlock:^(FDPhotoGroupCell *cell, NSUInteger idx, BOOL *stop) {
- [cell.imageView cancelCurrentImageRequest];
- }];
- }
- - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
- [self updateCellsForReuse];
-
- CGFloat floatPage = _scrollView.contentOffset.x / _scrollView.width;
- NSInteger page = _scrollView.contentOffset.x / _scrollView.width + 0.5;
-
- for (NSInteger i = page - 1; i <= page + 1; i++) { // preload left and right cell
- if (i >= 0 && i < self.groupItems.count) {
- FDPhotoGroupCell *cell = [self cellForPage:i];
- if (!cell) {
- FDPhotoGroupCell *cell = [self dequeueReusableCell];
- cell.page = i;
- cell.left = (self.width + kPadding) * i + kPadding / 2;
-
- if (_isPresented) {
- cell.item = self.groupItems[i];
- }
- [self.scrollView addSubview:cell];
- } else {
- if (_isPresented && !cell.item) {
- cell.item = self.groupItems[i];
- }
- }
- }
- }
-
- NSInteger intPage = floatPage + 0.5;
- intPage = intPage < 0 ? 0 : intPage >= _groupItems.count ? (int)_groupItems.count - 1 : intPage;
- _pager.currentPage = intPage;
- [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseInOut animations:^{
- _pager.alpha = 1;
- }completion:^(BOOL finish) {
- }];
- }
- - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
- if (!decelerate) {
- [self hidePager];
- }
- }
- - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
- [self hidePager];
- }
- - (void)hidePager {
- [UIView animateWithDuration:0.3 delay:0.8 options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseOut animations:^{
- _pager.alpha = 0;
- }completion:^(BOOL finish) {
- }];
- }
- /// enqueue invisible cells for reuse
- - (void)updateCellsForReuse {
- for (FDPhotoGroupCell *cell in _cells) {
- if (cell.superview) {
- if (cell.left > _scrollView.contentOffset.x + _scrollView.width * 2||
- cell.right < _scrollView.contentOffset.x - _scrollView.width) {
- [cell removeFromSuperview];
- cell.page = -1;
- cell.item = nil;
- }
- }
- }
- }
- /// dequeue a reusable cell
- - (FDPhotoGroupCell *)dequeueReusableCell {
- FDPhotoGroupCell *cell = nil;
- for (cell in _cells) {
- if (!cell.superview) {
- return cell;
- }
- }
-
- cell = [FDPhotoGroupCell new];
- cell.frame = self.bounds;
- cell.imageContainerView.frame = self.bounds;
- cell.imageView.frame = cell.bounds;
- cell.page = -1;
- cell.item = nil;
- [_cells addObject:cell];
- return cell;
- }
- /// get the cell for specified page, nil if the cell is invisible
- - (FDPhotoGroupCell *)cellForPage:(NSInteger)page {
- for (FDPhotoGroupCell *cell in _cells) {
- if (cell.page == page) {
- return cell;
- }
- }
- return nil;
- }
- - (NSInteger)currentPage {
- NSInteger page = _scrollView.contentOffset.x / _scrollView.width + 0.5;
- if (page >= _groupItems.count) page = (NSInteger)_groupItems.count - 1;
- if (page < 0) page = 0;
- return page;
- }
- - (void)showHUD:(NSString *)msg {
- if (!msg.length) return;
- UIFont *font = [UIFont systemFontOfSize:17];
- CGSize size = [msg sizeForFont:font size:CGSizeMake(200, 200) mode:NSLineBreakByCharWrapping];
- UILabel *label = [UILabel new];
- label.size = CGSizePixelCeil(size);
- label.font = font;
- label.text = msg;
- label.textColor = [UIColor whiteColor];
- label.numberOfLines = 0;
-
- UIView *hud = [UIView new];
- hud.size = CGSizeMake(label.width + 20, label.height + 20);
- hud.backgroundColor = [UIColor colorWithWhite:0.000 alpha:0.650];
- hud.clipsToBounds = YES;
- hud.layer.cornerRadius = 8;
-
- label.center = CGPointMake(hud.width / 2, hud.height / 2);
- [hud addSubview:label];
-
- hud.center = CGPointMake(self.width / 2, self.height / 2);
- hud.alpha = 0;
- [self addSubview:hud];
-
- [UIView animateWithDuration:0.4 animations:^{
- hud.alpha = 1;
- }];
- double delayInSeconds = 1.5;
- dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
- dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
- [UIView animateWithDuration:0.4 animations:^{
- hud.alpha = 0;
- } completion:^(BOOL finished) {
- [hud removeFromSuperview];
- }];
- });
- }
- - (void)doubleTap:(UITapGestureRecognizer *)g {
- if (!_isPresented) return;
- FDPhotoGroupCell *tile = [self cellForPage:self.currentPage];
- if (tile) {
- if (tile.zoomScale > 1) {
- [tile setZoomScale:1 animated:YES];
- } else {
- CGPoint touchPoint = [g locationInView:tile.imageView];
- CGFloat newZoomScale = tile.maximumZoomScale;
- CGFloat xsize = self.width / newZoomScale;
- CGFloat ysize = self.height / newZoomScale;
- [tile zoomToRect:CGRectMake(touchPoint.x - xsize/2, touchPoint.y - ysize/2, xsize, ysize) animated:YES];
- }
- }
- }
- - (void)longPress {
- if (!_isPresented) return;
-
- FDPhotoGroupCell *tile = [self cellForPage:self.currentPage];
- if (!tile.imageView.image) return;
-
- // try to save original image data if the image contains multi-frame (such as GIF/APNG)
- id imageItem = [tile.imageView.image imageDataRepresentation];
- YYImageType type = YYImageDetectType((__bridge CFDataRef)(imageItem));
- if (type != YYImageTypePNG &&
- type != YYImageTypeJPEG &&
- type != YYImageTypeGIF) {
- imageItem = tile.imageView.image;
- }
-
- UIActivityViewController *activityViewController =
- [[UIActivityViewController alloc] initWithActivityItems:@[imageItem] applicationActivities:nil];
- if ([activityViewController respondsToSelector:@selector(popoverPresentationController)]) {
- activityViewController.popoverPresentationController.sourceView = self;
- }
- UIViewController *toVC = self.toContainerView.viewController;
- if (!toVC) toVC = self.viewController;
- [toVC presentViewController:activityViewController animated:YES completion:nil];
- }
- - (void)pan:(UIPanGestureRecognizer *)g {
- switch (g.state) {
- case UIGestureRecognizerStateBegan: {
- if (_isPresented) {
- _panGestureBeginPoint = [g locationInView:self];
- } else {
- _panGestureBeginPoint = CGPointZero;
- }
- } break;
- case UIGestureRecognizerStateChanged: {
- if (_panGestureBeginPoint.x == 0 && _panGestureBeginPoint.y == 0) return;
- CGPoint p = [g locationInView:self];
- CGFloat deltaY = p.y - _panGestureBeginPoint.y;
- _scrollView.top = deltaY;
-
- CGFloat alphaDelta = 160;
- CGFloat alpha = (alphaDelta - fabs(deltaY) + 50) / alphaDelta;
- alpha = YY_CLAMP(alpha, 0, 1);
- [UIView animateWithDuration:0.1 delay:0 options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionCurveLinear animations:^{
- _blurBackground.alpha = alpha;
- _pager.alpha = alpha;
- } completion:nil];
-
- } break;
- case UIGestureRecognizerStateEnded: {
- if (_panGestureBeginPoint.x == 0 && _panGestureBeginPoint.y == 0) return;
- CGPoint v = [g velocityInView:self];
- CGPoint p = [g locationInView:self];
- CGFloat deltaY = p.y - _panGestureBeginPoint.y;
-
- if (fabs(v.y) > 1000 || fabs(deltaY) > 120) {
- [self cancelAllImageLoad];
- _isPresented = NO;
- [[UIApplication sharedApplication] setStatusBarHidden:_fromNavigationBarHidden withAnimation:UIStatusBarAnimationFade];
-
- BOOL moveToTop = (v.y < - 50 || (v.y < 50 && deltaY < 0));
- CGFloat vy = fabs(v.y);
- if (vy < 1) vy = 1;
- CGFloat duration = (moveToTop ? _scrollView.bottom : self.height - _scrollView.top) / vy;
- duration *= 0.8;
- duration = YY_CLAMP(duration, 0.05, 0.3);
-
- [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveLinear | UIViewAnimationOptionBeginFromCurrentState animations:^{
- _blurBackground.alpha = 0;
- _pager.alpha = 0;
- if (moveToTop) {
- _scrollView.bottom = 0;
- } else {
- _scrollView.top = self.height;
- }
- } completion:^(BOOL finished) {
- [self removeFromSuperview];
- }];
-
- _background.image = _snapshotImage;
- [_background.layer addFadeAnimationWithDuration:0.3 curve:UIViewAnimationCurveEaseInOut];
-
- } else {
- [UIView animateWithDuration:0.4 delay:0 usingSpringWithDamping:0.9 initialSpringVelocity:v.y / 1000 options:UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionBeginFromCurrentState animations:^{
- _scrollView.top = 0;
- _blurBackground.alpha = 1;
- _pager.alpha = 1;
- } completion:^(BOOL finished) {
-
- }];
- }
-
- } break;
- case UIGestureRecognizerStateCancelled : {
- _scrollView.top = 0;
- _blurBackground.alpha = 1;
- }
- default:break;
- }
- }
- @end
|