iOS大图预览和上下拖动退出的逻辑

一般的app大图预览都是使用collectionview布局的,每一个cell对应一张图片
cell里的逻辑如下:

//
// Created by bcy on 2017/9/6.
// Copyright (c) 2017 mirroon. All rights reserved.
//

#import "BCYFoundation.h"

#import <BCYUIKit/BCYUIKit.h>

#import "BCYFullScreenImageCollectionViewCell.h"
#import "BCYFullScreenImageModel.h"
#import "BCYFullScreenImageViewerConfiguration.h"
#import "YYCGUtilities.h"
#import <SDWebImage/UIImage+GIF.h>

#import "StringUtils.h"
#import "UIView+YYAdd.h"
#import "YYAnimatedImageView.h"

@interface BCYFullScreenImageCollectionViewCell () <UIScrollViewDelegate>
@property (nonatomic, strong) YYAnimatedImageView *imageView;
@property (nonatomic, strong) UIScrollView *contentScrollView;
@property (nonatomic, strong) UILabel *waterMarkLabel;
@end

@implementation BCYFullScreenImageCollectionViewCell {
}

#pragma mark -Override Methods

- (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        _contentScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, kScreenWidth, kScreenHeight)];
        _contentScrollView.showsVerticalScrollIndicator = NO;
        _contentScrollView.showsHorizontalScrollIndicator = NO;
        _contentScrollView.backgroundColor = UIColor.from(CAssetBlack);
        _contentScrollView.zoomScale = 1.0;
        _contentScrollView.minimumZoomScale = 1.0;
        _contentScrollView.maximumZoomScale = 2.0f;
        _contentScrollView.delegate = self;
        [self.contentView addSubview:_contentScrollView];

        _imageView = [[YYAnimatedImageView alloc]
            initWithFrame:CGRectMake(0.0f, kScreenHeight / 2.0f - kScreenWidth / 2.0f, kScreenWidth, kScreenWidth)];
        _imageView.image = UIImage.from(IAssetPlaceholder);
        [self.contentScrollView addSubview:_imageView];

        _waterMarkLabel = [[UILabel alloc] init];
        _waterMarkLabel.frame = CGRectMake(0.0f, _imageView.height - 26.0f - 6.0f, _imageView.width - 6.0f, 26.0f);
        _waterMarkLabel.textColor = UIColor.from(CAssetMidGray);
        _waterMarkLabel.font = [UIFont systemFontOfSize:9.0f];
        _waterMarkLabel.numberOfLines = 2;
        _waterMarkLabel.textAlignment = NSTextAlignmentRight;
        [_imageView addSubview:_waterMarkLabel];

        UITapGestureRecognizer *singleTapRecognizer =
            [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(_contentScrollViewSingleTapped:)];
        [_contentScrollView addGestureRecognizer:singleTapRecognizer];

        UITapGestureRecognizer *doubleTapRecognizer =
            [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(_contentScrollViewDoubleTapped:)];
        doubleTapRecognizer.numberOfTapsRequired = 2;
        [_contentScrollView addGestureRecognizer:doubleTapRecognizer];

        [singleTapRecognizer requireGestureRecognizerToFail:doubleTapRecognizer];
        //添加上下拉退出
        UISwipeGestureRecognizer *swipeUpRecognizer =
            [[UISwipeGestureRecognizer alloc] initWithTarget:self
                                                      action:@selector(_contentScrollViewSwipeBackRecognizer:)];
        UISwipeGestureRecognizer *swipeDownRecognizer =
            [[UISwipeGestureRecognizer alloc] initWithTarget:self
                                                      action:@selector(_contentScrollViewSwipeBackRecognizer:)];

        swipeUpRecognizer.direction = UISwipeGestureRecognizerDirectionUp;
        swipeDownRecognizer.direction = UISwipeGestureRecognizerDirectionDown;

        [self addGestureRecognizer:swipeDownRecognizer];
        [self addGestureRecognizer:swipeUpRecognizer];
    }

    return self;
}

#pragma mark -Public Methods

- (void)updateContentWithImageModel:(BCYFullScreenImageModel *)imageModel
                          indexPath:(NSIndexPath *)indexPath
                      configuration:(BCYFullScreenImageViewerConfiguration *)configuration {
    _indexPath = indexPath;
    _imageModel = imageModel;
    _configuration = configuration;

    if (imageModel.rotated) {
        _contentScrollView.transform = CGAffineTransformIdentity;
        _contentScrollView.frame = CGRectMake(0, 0, kScreenHeight, kScreenWidth);
        _contentScrollView.center = [UIApplication sharedApplication].keyWindow.center;
        _contentScrollView.transform = CGAffineTransformMakeRotation((CGFloat)M_PI_2);
        CGFloat top = 0.0f;
        if (imageModel.rotatedSize.height < kScreenWidth) {
            top = (kScreenWidth - imageModel.rotatedSize.height) / 2.0f;
        }
        _imageView.frame = CGRectMake(0, top, kScreenHeight, imageModel.rotatedSize.height);
        _contentScrollView.contentSize = CGSizeMake(kScreenHeight, roundf(imageModel.rotatedSize.height));
    } else {
        _contentScrollView.transform = CGAffineTransformIdentity;
        _contentScrollView.frame = CGRectMake(0, 0, kScreenWidth, kScreenHeight);
        _contentScrollView.center = [UIApplication sharedApplication].keyWindow.center;
        CGFloat top = 0.0f;
        if (imageModel.normalSize.height < kScreenHeight) {
            top = (kScreenHeight - imageModel.normalSize.height) / 2.0f;
        }
        _imageView.frame = CGRectMake(0, top, kScreenWidth, imageModel.normalSize.height);
        _contentScrollView.contentSize = CGSizeMake(kScreenWidth, imageModel.normalSize.height);
    }
    /**优先使用data属性来渲染图片*/
    if (imageModel.data) {
        _imageView.image = [UIImage sd_animatedGIFWithData:imageModel.data];
    } else {
        _imageView.image = imageModel.image;
    }

    _waterMarkLabel.frame = CGRectMake(0.0f, _imageView.height - 26.0f - 6.0f, _imageView.width - 6.0f, 26.0f);
    if (((_configuration.options & BCYFullScreenImageViewerOptionUseNativeWaterMark) > 0)) {
        NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
        paragraphStyle.lineSpacing = 4.0f;
        paragraphStyle.alignment = NSTextAlignmentRight;
        _waterMarkLabel.attributedText = [[NSAttributedString alloc]
            initWithString:[NSString stringWithFormat:@"©%@\n半次元-二次元创作者社区",
                                                      [StringUtils safeString:_configuration.userName
                                                                defaultString:nil]]
                attributes:@{NSParagraphStyleAttributeName : paragraphStyle}];

        _waterMarkLabel.hidden = NO;
        if ([imageModel hasOriginalImageLocalCache]) {
            /**查看原图的情况下,如果用户未设置禁止右键,则隐藏前端水印*/
            _waterMarkLabel.hidden = YES;
        }
    } else {
        _waterMarkLabel.hidden = YES;
    }
}

- (void)rotateImage {
    if (!_imageModel.rotated) {
        _imageModel.rotated = YES;
        _contentScrollView.frame = CGRectMake(0, 0, kScreenHeight, kScreenWidth);
        _contentScrollView.center = [UIApplication sharedApplication].keyWindow.center;
        CGFloat top = 0.0f;
        if (_imageModel.rotatedSize.height < kScreenWidth) {
            top = (kScreenWidth - _imageModel.rotatedSize.height) / 2.0f;
        }
        _imageView.frame = CGRectMake(0, top, kScreenHeight, _imageModel.rotatedSize.height);
        _waterMarkLabel.frame = CGRectMake(0.0f, _imageView.height - 26.0f - 6.0f, _imageView.width - 6.0f, 26.0f);
        _contentScrollView.contentSize = CGSizeMake(kScreenHeight, roundf(_imageModel.rotatedSize.height));
        [[UIApplication sharedApplication] beginIgnoringInteractionEvents];
        [UIView animateWithDuration:0.3f
            animations:^{
                self.contentScrollView.transform = CGAffineTransformIdentity;
                self.contentScrollView.transform = CGAffineTransformMakeRotation((CGFloat)M_PI_2);
            }
            completion:^(BOOL finished) {
                if (finished) {
                    [[UIApplication sharedApplication] endIgnoringInteractionEvents];
                }
            }];
    } else {
        _imageModel.rotated = NO;
        CGFloat top = 0.0f;
        if (_imageModel.normalSize.height < kScreenHeight) {
            top = (kScreenHeight - _imageModel.normalSize.height) / 2.0f;
        }
        _imageModel.rotated = NO;
        _imageView.frame = CGRectMake(0, top, kScreenWidth, _imageModel.normalSize.height);
        _waterMarkLabel.frame = CGRectMake(0.0f, _imageView.height - 26.0f - 6.0f, _imageView.width - 6.0f, 26.0f);
        _contentScrollView.contentSize = CGSizeMake(kScreenWidth, _imageModel.normalSize.height);
        [[UIApplication sharedApplication] beginIgnoringInteractionEvents];
        [UIView animateWithDuration:0.3f
            animations:^{
                self.contentScrollView.transform = CGAffineTransformIdentity;
                self.contentScrollView.frame = CGRectMake(0, 0, kScreenWidth, kScreenHeight);
                self.contentScrollView.center = [UIApplication sharedApplication].keyWindow.center;
            }
            completion:^(BOOL finished) {
                if (finished) {
                    [[UIApplication sharedApplication] endIgnoringInteractionEvents];
                }
            }];
    }
}

#pragma mark -UIScrollView Delegate Methods

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
}

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
    return _imageView;
}
- (void)scrollViewDidZoom:(UIScrollView *)scrollView {
    CGFloat offsetX = (scrollView.bounds.size.width > scrollView.contentSize.width)
                          ? (scrollView.bounds.size.width - scrollView.contentSize.width) * 0.5f
                          : 0.f;
    CGFloat offsetY = (scrollView.bounds.size.height > scrollView.contentSize.height)
                          ? (scrollView.bounds.size.height - scrollView.contentSize.height) * 0.5f
                          : 0.f;

    _imageView.center =
        CGPointMake(scrollView.contentSize.width * 0.5f + offsetX, scrollView.contentSize.height * 0.5f + offsetY);
}

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
    //大图手势返回,因为大图会优先处理ScrollView的滑动,在这里判断是否滑动越界,如果是就触发对应的返回动画
    //在图片未被放大和旋转时触发
    if (scrollView.zoomScale <= 1.0f && !_imageModel.rotated) {
        CGFloat offset = scrollView.contentOffset.y;
        if (offset < -20) {
            [self moveScrollView:BCYScrollViewDirectionDown];
        } else if (offset + kScreenHeight > scrollView.contentSize.height + 20) {
            //长图上拉
            [self moveScrollView:BCYScrollViewDirectionUp];
        }
    }

    if (_imageModel.rotated) {
        if (_contentScrollView.contentOffset.y < -20) {
            /**注意防越界!!!*/
            if (_delegate && [_delegate respondsToSelector:@selector(getTotalItemCount)]) {
                if (_indexPath.item + 1 < [_delegate getTotalItemCount]) {
                    if ([_delegate respondsToSelector:@selector(scrollToIndex:)]) {
                        [_delegate scrollToIndex:_indexPath.item + 1];
                    }
                }
            }
        } else if (_contentScrollView.contentOffset.y + kScreenWidth > _contentScrollView.contentSize.height + 20) {
            if (_indexPath.item - 1 >= 0) {
                if ([_delegate respondsToSelector:@selector(scrollToIndex:)]) {
                    [_delegate scrollToIndex:_indexPath.item - 1];
                }
            }
        }
    }
}

#pragma mark -Action Methods
//单击屏幕触发隐藏工具栏事件
- (void)_contentScrollViewSingleTapped:(id)sender {
    if ([self.delegate respondsToSelector:@selector(hideToolBar)]) {
        [self.delegate hideToolBar];
    }
}

- (void)_contentScrollViewDoubleTapped:(id)sender {
    if (_contentScrollView.zoomScale > 1.f) {
        [_contentScrollView setZoomScale:1.f animated:YES];
    } else {
        [_contentScrollView setZoomScale:2.f animated:YES];
    }
}

- (void)_contentScrollViewSwipeBackRecognizer:(UISwipeGestureRecognizer *)sender {
    //小图上下拉手势响应
    if (sender.direction == UISwipeGestureRecognizerDirectionDown) {
        [self moveScrollView:BCYScrollViewDirectionDown];
    } else {
        [self moveScrollView:BCYScrollViewDirectionUp];
    }
}

- (void)moveScrollView:(BCYScrollViewDirection)direction {
    //预览器移动滑出动画
    if ([self.delegate respondsToSelector:@selector(setBackgroundTranslucent)] &&
        [self.delegate respondsToSelector:@selector(hideToolBar)]) {
        [self.delegate setBackgroundTranslucent];
        [self.delegate hideToolBar];
    }
    //旋转复位
    if (self.imageModel.rotated) {
        self.contentScrollView.transform = CGAffineTransformIdentity;
        self.contentScrollView.frame = CGRectMake(0, 0, kScreenWidth, kScreenHeight);
        self.contentScrollView.center = [UIApplication sharedApplication].keyWindow.center;
    }
    //根据滑动方向执行对应方向的动画
    [UIView animateWithDuration:BCY_DEFAULT_ANIMATION_DURATION
        animations:^(void) {
            self.contentScrollView.transform =
                CGAffineTransformTranslate(self.contentScrollView.transform, 0,
                                           direction == BCYScrollViewDirectionDown ? kScreenHeight : -kScreenHeight);
        }
        completion:^(BOOL isFinish) {
            if ([self.delegate respondsToSelector:@selector(dismiss)]) {
                [self.delegate dismiss];
            }
        }];
}

@end

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,367评论 6 512
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,959评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,750评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,226评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,252评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,975评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,592评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,497评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,027评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,147评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,274评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,953评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,623评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,143评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,260评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,607评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,271评论 2 358

推荐阅读更多精彩内容