iOS 浏览相册功能实现 —— HERO博客

来源:互联网 发布:淘宝刷店铺收藏有用吗 编辑:程序博客网 时间:2024/06/06 14:13

iOS 浏览相册功能实现,可缩放,画笔标记,缓存图片,记录下载进度。

首先看一下效果图:

   

  


下面简述下主要思路及相关代码:

HWPhotoVC(控制器,用collcetView展示缩略图,点击cell展示大图片):

#import <UIKit/UIKit.h>@interface HWPhotoVC : UIViewController@end/*** ---------------分割线--------------- ***/#import "HWPhotoVC.h"#import "HWPhotoView.h"#import "HWNavBar.h"#import "HWLoadingView.h"#import "HWPhotoManger.h"#define KItemW 111#define KItemH 111#define KMargin 10@interface HWPhotoVC ()<UICollectionViewDelegate, UICollectionViewDataSource>@property (nonatomic, strong) NSArray *photos;@property (nonatomic, strong) NSArray *thumPhotos;@property (nonatomic, strong) UICollectionView *collectionView;@property (nonatomic, weak) HWPhotoView *photoView;@property (nonatomic, weak) HWLoadingView *loadingView;@end@implementation HWPhotoVCstatic NSString *const reuseIdentifier = @"HWPhotosCell";- (void)viewDidLoad {    [super viewDidLoad];        self.view.backgroundColor = [UIColor whiteColor];        //创建控件    [self creatControl];}- (void)creatControl{    CGFloat navBarH = 64.0f;        //导航条    HWNavBar *navBar = [[HWNavBar alloc] initWithFrame:CGRectMake(0, 0, KMainW, navBarH)];    navBar.title = @"相册";    [navBar addBackButtonWithAction:@selector(photoVCBackAction)];    [self.view addSubview:navBar];        //展示视图布局    UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];    flowLayout.sectionInset = UIEdgeInsetsMake(KMargin, KMargin, KMargin, KMargin);        //展示视图    _collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, navBarH, KMainW, KMainH - navBarH) collectionViewLayout:flowLayout];    _collectionView.backgroundColor = [UIColor clearColor];    _collectionView.showsVerticalScrollIndicator = NO;    _collectionView.dataSource = self;    _collectionView.delegate = self;    [self.view addSubview:_collectionView];        //加载视图    HWLoadingView *loadingView = [[HWLoadingView alloc] initWithFrame:CGRectMake(0, 0, KMainW, KMainH)];    loadingView.progress = 0.0f;    weakify(self);    loadingView.back = ^() {        strongify(weakSelf);        [strongSelf photoVCBackAction];    };    [self.view addSubview:loadingView];    self.loadingView = loadingView;        //注册标识    [_collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:reuseIdentifier];        //获取信息    [self getInfo];}- (HWPhotoView *)photoView{    if (!_photoView) {         HWPhotoView *photoView = [[HWPhotoView alloc] initWithFrame:CGRectMake(0, 0, KMainW, KMainH)];        photoView.photos = _photos;        photoView.thumPhotos = _thumPhotos;        weakify(self);        photoView.back = ^(CGRect imageViewFrame, NSInteger item) {            strongify(weakSelf);            [strongSelf photoDismissAnimationWithFrame:imageViewFrame item:item];        };        [self.view addSubview:photoView];        _photoView = photoView;    }        return _photoView;}- (void)photoDismissAnimationWithFrame:(CGRect)frame item:(NSInteger)item{    //根据item宽度计算每行可显示的个数    int colCount = (int)((KMainW - KMargin) / (KItemW + KMargin));        //创建图片并设置初始frame    UIImageView __block *imageView = [[UIImageView alloc] initWithFrame:frame];        imageView.image = [UIImage imageWithContentsOfFile:[HWPhotoManger getImagePathWithImageName:_photos[item]]];    [self.view addSubview:imageView];        //点击图片时左上第一张是否能完整显示    BOOL isIntact = (int)_collectionView.contentOffset.y % (KMargin + KItemH) <= KMargin;        //点击图片时左下第一张是否能完整显示    BOOL isIntactBottom = (int)(_collectionView.contentOffset.y + _collectionView.bounds.size.height) % (KMargin + KItemH) <= KMargin;        //点击图片时左上第一张图片item    NSInteger currentFirstItem = (int)_collectionView.contentOffset.y / (KMargin + KItemH) * colCount;        //点击图片时左下第一张图片item    NSInteger currentBottomFirstItem = (int)(_collectionView.contentOffset.y + _collectionView.bounds.size.height) / (KMargin + KItemH) * colCount;    if (isIntactBottom) currentBottomFirstItem = currentBottomFirstItem - colCount;        //视图可以展示的最大item数量    NSInteger showMaxItemCount = currentBottomFirstItem - currentFirstItem + colCount;        //当结束点击图片在最上一行,并且图片不能完整显示时,下移CollectionView使图片完整显示    if (!isIntact && (item - currentFirstItem < colCount && item - currentFirstItem > - 1)) {        [_collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:item inSection:0] atScrollPosition:UICollectionViewScrollPositionTop animated:NO];    }        //当结束点击图片在最下一行,并且图片不能完整显示时,上移CollectionView使图片完整显示    if (!isIntactBottom && (item - currentFirstItem > showMaxItemCount - colCount - 1 && item - currentFirstItem < showMaxItemCount)) {        CGFloat movePadding = KItemH - ((int)(_collectionView.contentOffset.y + _collectionView.bounds.size.height) % (KItemH + KMargin) - KMargin);        [_collectionView setContentOffset:CGPointMake(0, _collectionView.contentOffset.y + movePadding)];    }        //当结束点击item小于左上第一张图片时,下移CollectionView至选中行为最上一行    if (item < currentFirstItem) {        [_collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:item inSection:0] atScrollPosition:UICollectionViewScrollPositionTop animated:NO];    }        //当结束点击item大于右下(左上第一张图片item + 可最大展示item数)时,上移CollectionView至选中行为最下一行    if (item > currentFirstItem + showMaxItemCount - 1) {        CGFloat movePadding = KItemH - ((int)(_collectionView.contentOffset.y + _collectionView.bounds.size.height) % (KItemH + KMargin) - KMargin) + (KItemH + KMargin) * (item / colCount - currentBottomFirstItem / colCount);        if (isIntactBottom) movePadding = movePadding - (KItemH + KMargin);        [_collectionView setContentOffset:CGPointMake(0, _collectionView.contentOffset.y + movePadding)];    }        //加延时确保获取到的cellFrame是collectionView移动之后的    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{        //获取图片缩小后的frame        UICollectionViewCell *cell = [_collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:item inSection:0]];                //消失动画        [UIView animateWithDuration:0.25f animations:^{            imageView.frame = [self.view convertRect:cell.frame fromView:_collectionView];        }completion:^(BOOL finished) {            [imageView removeFromSuperview];            imageView = nil;        }];    });}- (void)getInfo{    [_loadingView show];            //网络请求获取相册相关信息这里省略了,直接模拟获取到图片数组、缩略图数组、相册版本号、相册id    NSArray *urlArray = @[@"http://a2.qpic.cn/psb?/V13GwxkT2AqZnq/axUD1TxyazB3vSFQkDQLn5M0QPSZQB5WWLaDW0V5Xj4!/b/dGkBAAAAAAAA&bo=cQSAAgAAAAAFB9M!&rf=viewer_4", @"http://a2.qpic.cn/psb?/V13GwxkT2AqZnq/D0m2YadD0efgMEFUzxDI.VP54dmoNLE6jXG4q3Hu39Q!/b/dGkBAAAAAAAA&bo=AASAAgAAAAAFB6I!&rf=viewer_4", @"http://a2.qpic.cn/psb?/V13GwxkT2AqZnq/ajOssbYw05gPzrifwEeHYJQm63nINjpnDNk3lXV7utQ!/b/dGkBAAAAAAAA&bo=cgSAAgAAAAAFANc!&rf=viewer_4", @"http://a1.qpic.cn/psb?/V13GwxkT2AqZnq/Y2bx7nPZOo*xK9CnWnEuMOIvnAOeMDLnvFGuE325tSg!/b/dGgBAAAAAAAA&bo=FQIsAQAAAAAFABk!&rf=viewer_4", @"http://a1.qpic.cn/psb?/V13GwxkT2AqZnq/yJZVj17bdMMR3sCLT1YWwNFKgK057vNjw0zL1IH6FTg!/b/dGgBAAAAAAAA&bo=4AEsAQAAAAAFAO8!&rf=viewer_4", @"http://a1.qpic.cn/psb?/V13GwxkT2AqZnq/HJUjYRFTxYElxuIP00GzRWHoymfiyylKmisGK9gbDUc!/b/dGgBAAAAAAAA&bo=VQOAAgAAAAAFAPc!&rf=viewer_4", @"http://a1.qpic.cn/psb?/V13GwxkT2AqZnq/lNbl.keTXojot43.i4eLl5EDrrrhim3Wxo225dBOQTg!/b/dGgBAAAAAAAA&bo=AASAAgAAAAAFAKU!&rf=viewer_4", @"http://a2.qpic.cn/psb?/V13GwxkT2AqZnq/iB6SdannBkn0b8SVuTSpS6H.Mttkwj*YF.i58ge7bp4!/b/dGkBAAAAAAAA&bo=AASAAgAAAAAFAKU!&rf=viewer_4", @"http://a1.qpic.cn/psb?/V13GwxkT2AqZnq/Li0El90EOY0E6*Haw4qtPP5i2C8dtUxxfL8RfvTTyrs!/b/dGgBAAAAAAAA&bo=AASAAgAAAAAFAKU!&rf=viewer_4", @"http://a2.qpic.cn/psb?/V13GwxkT2AqZnq/Vtg11LWJ*osQp*WkGRAwfAi89j3Bbk5v3EZM8b3H2q0!/b/dGkBAAAAAAAA&bo=wQOAAgAAAAAFAGM!&rf=viewer_4", @"http://a1.qpic.cn/psb?/V13GwxkT2AqZnq/K2fNvk13QaUO4punmxpIAL1kZFDy4AeNRkfZmdItWyM!/b/dFYBAAAAAAAA&bo=wgH9AgAAAAAFBxg!&rf=viewer_4", @"http://a2.qpic.cn/psb?/V13GwxkT2AqZnq/7RzzUgvozabfIqwfX8rv4utG9aT3n2e3Asi4zzxvnmI!/b/dGkBAAAAAAAA&bo=gAI1AwAAAAAFB5A!&rf=viewer_4", @"http://a2.qpic.cn/psb?/V13GwxkT2AqZnq/eXRrjOn0pBOFf.7m3yaXyEztQEkoGtYcg8EBoJpaO0U!/b/dGkBAAAAAAAA&bo=yADIAAAAAAAFByQ!&rf=viewer_4", @"http://a2.qpic.cn/psb?/V13GwxkT2AqZnq/pw5plnw3LsocGQlRQSgrnZCPy2KV5LvWb*Nz3UNCvJQ!/b/dGkBAAAAAAAA&bo=AASAAgAAAAAFB6I!&rf=viewer_4", @"http://a1.qpic.cn/psb?/V13GwxkT2AqZnq/7EO.WlDqMcvVBYcc27XFLNplGjwdYx2p56TZNwc.Tn4!/b/dFYBAAAAAAAA&bo=ZwJnAgAAAAAFByQ!&rf=viewer_4", @"http://a2.qpic.cn/psb?/V13GwxkT2AqZnq/axUD1TxyazB3vSFQkDQLn5M0QPSZQB5WWLaDW0V5Xj4!/b/dGkBAAAAAAAA&bo=cQSAAgAAAAAFB9M!&rf=viewer_4", @"http://a2.qpic.cn/psb?/V13GwxkT2AqZnq/D0m2YadD0efgMEFUzxDI.VP54dmoNLE6jXG4q3Hu39Q!/b/dGkBAAAAAAAA&bo=AASAAgAAAAAFB6I!&rf=viewer_4", @"http://a2.qpic.cn/psb?/V13GwxkT2AqZnq/ajOssbYw05gPzrifwEeHYJQm63nINjpnDNk3lXV7utQ!/b/dGkBAAAAAAAA&bo=cgSAAgAAAAAFANc!&rf=viewer_4", @"http://a1.qpic.cn/psb?/V13GwxkT2AqZnq/Y2bx7nPZOo*xK9CnWnEuMOIvnAOeMDLnvFGuE325tSg!/b/dGgBAAAAAAAA&bo=FQIsAQAAAAAFABk!&rf=viewer_4", @"http://a1.qpic.cn/psb?/V13GwxkT2AqZnq/yJZVj17bdMMR3sCLT1YWwNFKgK057vNjw0zL1IH6FTg!/b/dGgBAAAAAAAA&bo=4AEsAQAAAAAFAO8!&rf=viewer_4", @"http://a1.qpic.cn/psb?/V13GwxkT2AqZnq/HJUjYRFTxYElxuIP00GzRWHoymfiyylKmisGK9gbDUc!/b/dGgBAAAAAAAA&bo=VQOAAgAAAAAFAPc!&rf=viewer_4", @"http://a1.qpic.cn/psb?/V13GwxkT2AqZnq/lNbl.keTXojot43.i4eLl5EDrrrhim3Wxo225dBOQTg!/b/dGgBAAAAAAAA&bo=AASAAgAAAAAFAKU!&rf=viewer_4", @"http://a2.qpic.cn/psb?/V13GwxkT2AqZnq/iB6SdannBkn0b8SVuTSpS6H.Mttkwj*YF.i58ge7bp4!/b/dGkBAAAAAAAA&bo=AASAAgAAAAAFAKU!&rf=viewer_4", @"http://a1.qpic.cn/psb?/V13GwxkT2AqZnq/Li0El90EOY0E6*Haw4qtPP5i2C8dtUxxfL8RfvTTyrs!/b/dGgBAAAAAAAA&bo=AASAAgAAAAAFAKU!&rf=viewer_4", @"http://a2.qpic.cn/psb?/V13GwxkT2AqZnq/Vtg11LWJ*osQp*WkGRAwfAi89j3Bbk5v3EZM8b3H2q0!/b/dGkBAAAAAAAA&bo=wQOAAgAAAAAFAGM!&rf=viewer_4", @"http://a1.qpic.cn/psb?/V13GwxkT2AqZnq/K2fNvk13QaUO4punmxpIAL1kZFDy4AeNRkfZmdItWyM!/b/dFYBAAAAAAAA&bo=wgH9AgAAAAAFBxg!&rf=viewer_4", @"http://a2.qpic.cn/psb?/V13GwxkT2AqZnq/7RzzUgvozabfIqwfX8rv4utG9aT3n2e3Asi4zzxvnmI!/b/dGkBAAAAAAAA&bo=gAI1AwAAAAAFB5A!&rf=viewer_4", @"http://a2.qpic.cn/psb?/V13GwxkT2AqZnq/eXRrjOn0pBOFf.7m3yaXyEztQEkoGtYcg8EBoJpaO0U!/b/dGkBAAAAAAAA&bo=yADIAAAAAAAFByQ!&rf=viewer_4", @"http://a2.qpic.cn/psb?/V13GwxkT2AqZnq/pw5plnw3LsocGQlRQSgrnZCPy2KV5LvWb*Nz3UNCvJQ!/b/dGkBAAAAAAAA&bo=AASAAgAAAAAFB6I!&rf=viewer_4", @"http://a1.qpic.cn/psb?/V13GwxkT2AqZnq/7EO.WlDqMcvVBYcc27XFLNplGjwdYx2p56TZNwc.Tn4!/b/dFYBAAAAAAAA&bo=ZwJnAgAAAAAFByQ!&rf=viewer_4"];    NSArray *thumUrlArray = @[@"http://a2.qpic.cn/psb?/V13GwxkT2AqZnq/oDM0rERpn5N83a2QFuXUHu8L*xSgOy0z7lcjNxiGZW4!/b/dGkBAAAAAAAA&bo=lgBUAAAAAAAFAOE!&rf=viewer_4", @"http://a2.qpic.cn/psb?/V13GwxkT2AqZnq/q*CPyLxw3XhsNW71p.iNXZ0cY53CpFn884sLFYkj1cs!/b/dGkBAAAAAAAA&bo=lgBeAAAAAAAFB.w!&rf=viewer_4", @"http://a2.qpic.cn/psb?/V13GwxkT2AqZnq/1PTuUpFR*aLa2mT6Lxgq1f3TrDAsDF.7wlAvjgLjUvQ!/b/dGkBAAAAAAAA&bo=lgBUAAAAAAAFB.Y!&rf=viewer_4", @"http://a2.qpic.cn/psb?/V13GwxkT2AqZnq/FGhSAze1L1rYWEWU4cA45zTtJYp4rvsSSuOM1TvAWT8!/b/dGkBAAAAAAAA&bo=lgBUAAAAAAAFAOE!&rf=viewer_4", @"http://a2.qpic.cn/psb?/V13GwxkT2AqZnq/uR*1kuC7oM12uYffpYboQwDNyPUA8Q.9xLNbyMkx.zE!/b/dGYBAAAAAAAA&bo=lgBeAAAAAAAFAOs!&rf=viewer_4", @"http://a2.qpic.cn/psb?/V13GwxkT2AqZnq/iI1t618fi94LzYwkJk0zRX8SMQWr8XGHQ98ioZYhUKM!/b/dGkBAAAAAAAA&bo=lgBxAAAAAAAFAMQ!&rf=viewer_4", @"http://a2.qpic.cn/psb?/V13GwxkT2AqZnq/tEfmzbb22KtoJwohbUIkNXG9U3348pk7cI1HdlDD3OE!/b/dGkBAAAAAAAA&bo=lgBeAAAAAAAFB.w!&rf=viewer_4", @"http://a1.qpic.cn/psb?/V13GwxkT2AqZnq/fc0EInMMxEzeMqRUfr4n8oDjvjxRSKkAxi0.UTwMcuQ!/b/dGgBAAAAAAAA&bo=lgBeAAAAAAAFB.w!&rf=viewer_4", @"http://a1.qpic.cn/psb?/V13GwxkT2AqZnq/0kKI.OxxnonRO*PamJT8IrvEqFL0YX254sbitqXU9z0!/b/dGgBAAAAAAAA&bo=lgBeAAAAAAAFB.w!&rf=viewer_4", @"http://a1.qpic.cn/psb?/V13GwxkT2AqZnq/4QPH9RB7lBVeZNbUsp0xXUAPm1Iku1Dz*9sdvrVDEns!/b/dGgBAAAAAAAA&bo=lgBkAAAAAAAFB9Y!&rf=viewer_4", @"http://a2.qpic.cn/psb?/V13GwxkT2AqZnq/xkR2EkWlq.gBmIq0cWKoUG1qrvl86lDljdBeHRENlug!/b/dGkBAAAAAAAA&bo=WACWAAAAAAAFB.o!&rf=viewer_4", @"http://a2.qpic.cn/psb?/V13GwxkT2AqZnq/8jl5H11.QX4iGBJ3j6JS2Fvoy.WlG6IVcoNCEzKMVBU!/b/dGkBAAAAAAAA&bo=dQCWAAAAAAAFB8c!&rf=viewer_4", @"http://a1.qpic.cn/psb?/V13GwxkT2AqZnq/Xwn7NLeHycrnrLJ.w4hzcmq9QmS7FW09gYXsxtLPORc!/b/dGgBAAAAAAAA&bo=lgCWAAAAAAAFByQ!&rf=viewer_4", @"http://a1.qpic.cn/psb?/V13GwxkT2AqZnq/*lg6dH6TTg.qe4HttnA1v4J7G3ucQeJ2s06xuVc1zgU!/b/dFYBAAAAAAAA&bo=lgBeAAAAAAAFB.w!&rf=viewer_4", @"http://a2.qpic.cn/psb?/V13GwxkT2AqZnq/pfhX5nA5usc0IqoFItZMJT4EgYloUC8bd5cElsp4FI8!/b/dGkBAAAAAAAA&bo=lgCWAAAAAAAFByQ!&rf=viewer_4", @"http://a2.qpic.cn/psb?/V13GwxkT2AqZnq/oDM0rERpn5N83a2QFuXUHu8L*xSgOy0z7lcjNxiGZW4!/b/dGkBAAAAAAAA&bo=lgBUAAAAAAAFAOE!&rf=viewer_4", @"http://a2.qpic.cn/psb?/V13GwxkT2AqZnq/q*CPyLxw3XhsNW71p.iNXZ0cY53CpFn884sLFYkj1cs!/b/dGkBAAAAAAAA&bo=lgBeAAAAAAAFB.w!&rf=viewer_4", @"http://a2.qpic.cn/psb?/V13GwxkT2AqZnq/1PTuUpFR*aLa2mT6Lxgq1f3TrDAsDF.7wlAvjgLjUvQ!/b/dGkBAAAAAAAA&bo=lgBUAAAAAAAFB.Y!&rf=viewer_4", @"http://a2.qpic.cn/psb?/V13GwxkT2AqZnq/FGhSAze1L1rYWEWU4cA45zTtJYp4rvsSSuOM1TvAWT8!/b/dGkBAAAAAAAA&bo=lgBUAAAAAAAFAOE!&rf=viewer_4", @"http://a2.qpic.cn/psb?/V13GwxkT2AqZnq/uR*1kuC7oM12uYffpYboQwDNyPUA8Q.9xLNbyMkx.zE!/b/dGYBAAAAAAAA&bo=lgBeAAAAAAAFAOs!&rf=viewer_4", @"http://a2.qpic.cn/psb?/V13GwxkT2AqZnq/iI1t618fi94LzYwkJk0zRX8SMQWr8XGHQ98ioZYhUKM!/b/dGkBAAAAAAAA&bo=lgBxAAAAAAAFAMQ!&rf=viewer_4", @"http://a2.qpic.cn/psb?/V13GwxkT2AqZnq/tEfmzbb22KtoJwohbUIkNXG9U3348pk7cI1HdlDD3OE!/b/dGkBAAAAAAAA&bo=lgBeAAAAAAAFB.w!&rf=viewer_4", @"http://a1.qpic.cn/psb?/V13GwxkT2AqZnq/fc0EInMMxEzeMqRUfr4n8oDjvjxRSKkAxi0.UTwMcuQ!/b/dGgBAAAAAAAA&bo=lgBeAAAAAAAFB.w!&rf=viewer_4", @"http://a1.qpic.cn/psb?/V13GwxkT2AqZnq/0kKI.OxxnonRO*PamJT8IrvEqFL0YX254sbitqXU9z0!/b/dGgBAAAAAAAA&bo=lgBeAAAAAAAFB.w!&rf=viewer_4", @"http://a1.qpic.cn/psb?/V13GwxkT2AqZnq/4QPH9RB7lBVeZNbUsp0xXUAPm1Iku1Dz*9sdvrVDEns!/b/dGgBAAAAAAAA&bo=lgBkAAAAAAAFB9Y!&rf=viewer_4", @"http://a2.qpic.cn/psb?/V13GwxkT2AqZnq/xkR2EkWlq.gBmIq0cWKoUG1qrvl86lDljdBeHRENlug!/b/dGkBAAAAAAAA&bo=WACWAAAAAAAFB.o!&rf=viewer_4", @"http://a2.qpic.cn/psb?/V13GwxkT2AqZnq/8jl5H11.QX4iGBJ3j6JS2Fvoy.WlG6IVcoNCEzKMVBU!/b/dGkBAAAAAAAA&bo=dQCWAAAAAAAFB8c!&rf=viewer_4", @"http://a1.qpic.cn/psb?/V13GwxkT2AqZnq/Xwn7NLeHycrnrLJ.w4hzcmq9QmS7FW09gYXsxtLPORc!/b/dGgBAAAAAAAA&bo=lgCWAAAAAAAFByQ!&rf=viewer_4", @"http://a1.qpic.cn/psb?/V13GwxkT2AqZnq/*lg6dH6TTg.qe4HttnA1v4J7G3ucQeJ2s06xuVc1zgU!/b/dFYBAAAAAAAA&bo=lgBeAAAAAAAFB.w!&rf=viewer_4", @"http://a2.qpic.cn/psb?/V13GwxkT2AqZnq/pfhX5nA5usc0IqoFItZMJT4EgYloUC8bd5cElsp4FI8!/b/dGkBAAAAAAAA&bo=lgCWAAAAAAAFByQ!&rf=viewer_4"];    //相册版本号,相册内部有更新时更新版本号,这样做的缺点是需要全部更新,如果更新频繁还是单张缓存吧,有很多优秀的开源库    NSString *newVersion = @"1.0.0";    //相册id,本地缓存路径是通过这个id拼接的,多个相册不会互绕    NSString *photoID = @"1000";        //获取本保存的相册版本号    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];    NSString *currentVersion = [defaults objectForKey:[HWPhotoManger getPhotoVersionKeyWithPhotoID:photoID]];        //如果有本地缓存    if ([newVersion isEqualToString:currentVersion]) {        //取本地图片        _photos = [NSKeyedUnarchiver unarchiveObjectWithFile:[HWPhotoManger getPhotoPathWithPhotoID:photoID]];        _thumPhotos = [NSKeyedUnarchiver unarchiveObjectWithFile:[HWPhotoManger getThumPhotoPathWithPhotoID:photoID]];                //刷新        [_loadingView dismiss];        [_collectionView reloadData];            //如果没有本地缓存    }else {         HWPhotoManger *photoManger = [HWPhotoManger sharePhotoManger];                //加载图片        if (!photoManger.isLoading) {            [photoManger getImageWithUrlArray:urlArray thumUrlArray:thumUrlArray photoID:photoID version:newVersion];        }else {            _loadingView.progress = photoManger.progress;        }                //加载失败        photoManger.error = ^() {            NSLog(@"加载失败,请检查网络");            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{                [self photoVCBackAction];            });        };                //刷新进度        photoManger.progressBlock = ^(CGFloat progress) {            _loadingView.progress = progress;        };                //刷新视图        photoManger.finishBlock = ^(NSArray *array, NSArray *thumArray) {            _photos = array;            _thumPhotos = thumArray;            [_loadingView dismiss];            [_collectionView reloadData];        };    }}- (void)photoVCBackAction{    [self dismissViewControllerAnimated:YES completion:nil];}#pragma mark - UICollectionViewDataSource- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{    return _thumPhotos.count;}- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];        cell.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageWithContentsOfFile:[HWPhotoManger getImagePathWithImageName:_thumPhotos[indexPath.item]]]];        return cell;}- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{    return CGSizeMake(KItemW, KItemH);}#pragma mark - UICollectionViewDelegate- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{    UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];        CGRect selectPhotoFrame = [self.view convertRect:cell.frame fromView:collectionView];        [self.photoView showWithSelectPhotoFrame:selectPhotoFrame selectItem:indexPath.item];}@end

HWPhotoView(图片展示视图,用scrollView做为容器展示图片,设置缩放、点击、滑动事件,添加了一个collectionView做为快速浏览视图,画笔功能是添加了一个空视图覆盖在图片上,并未与图片融合):

#import <UIKit/UIKit.h>@interface HWPhotoView : UIView@property (nonatomic, strong) NSArray *photos;@property (nonatomic, strong) NSArray *thumPhotos;@property (nonatomic, copy) void(^ back)(CGRect imageFrame, NSInteger item);- (void)showWithSelectPhotoFrame:(CGRect)selectPhotoFrame selectItem:(NSInteger)selectItem;@end/*** ---------------分割线--------------- ***/#import "HWPhotoView.h"#import "HWPaintView.h"#import "HWPaintBar.h"#import "HWPhotoManger.h"#import "HWNavBar.h"#define KHWPhotoViewMargin 2#define KCollectionViewHeigth 100#define KPicMinScale 1.0#define KPicMaxScale 2.4#define KItemW 70#define KItemH 96@interface HWPhotoView ()<UICollectionViewDelegate, UICollectionViewDataSource, UIScrollViewDelegate, HWPaintBarDelegate>@property (nonatomic, weak) UILabel *label;@property (nonatomic, weak) UIImageView *imageView;@property (nonatomic, weak) UIScrollView *scrollView;@property (nonatomic, weak) HWNavBar *navBar;@property (nonatomic, weak) HWPaintView *paintView;@property (nonatomic, weak) HWPaintBar *paintBar;@property (nonatomic, strong) UICollectionView *collectionView;@property (nonatomic, assign) NSInteger index;@property (nonatomic, assign) CGFloat startCollectionViewX;@property (nonatomic, assign) CGFloat lastScrContX;@end@implementation HWPhotoViewstatic NSString *const reuseIdentifier = @"HWPhotoViewCell";- (instancetype)initWithFrame:(CGRect)frame{    if (self = [super initWithFrame:frame]) {        self.backgroundColor = [UIColor blackColor];        //容器        UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:self.bounds];        scrollView.minimumZoomScale = KPicMinScale;        scrollView.maximumZoomScale = KPicMaxScale;        scrollView.showsVerticalScrollIndicator = NO;        scrollView.showsHorizontalScrollIndicator = NO;        scrollView.delegate = self;        [self addSubview:scrollView];        self.scrollView = scrollView;                //单击        UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(click)];        tap.numberOfTouchesRequired = 1;        tap.numberOfTapsRequired = 1;        [scrollView addGestureRecognizer:tap];                //双击        UITapGestureRecognizer *tap2 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleClick)];        tap2.numberOfTapsRequired = 2;        [scrollView addGestureRecognizer:tap2];        [tap requireGestureRecognizerToFail:tap2];                //右滑手势        UISwipeGestureRecognizer *rightSwip = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(nextPage)];        rightSwip.direction = UISwipeGestureRecognizerDirectionLeft;        [scrollView addGestureRecognizer:rightSwip];                //左滑手势        UISwipeGestureRecognizer *leftSwip = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(forwardPage)];        leftSwip.direction = UISwipeGestureRecognizerDirectionRight;        [scrollView addGestureRecognizer:leftSwip];                //下滑手势        UISwipeGestureRecognizer *downSwip = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(downSwipAction)];        downSwip.direction = UISwipeGestureRecognizerDirectionDown;        [scrollView addGestureRecognizer:downSwip];                //图片        UIImageView *imageView = [[UIImageView alloc] init];        [self.scrollView addSubview:imageView];        self.imageView = imageView;                //手绘板        HWPaintView *paintView = [[HWPaintView alloc] initWithFrame:self.bounds];        paintView.hidden = YES;        [self addSubview:paintView];        self.paintView = paintView;                //导航条        HWNavBar *navBar = [[HWNavBar alloc] initWithFrame:CGRectMake(0, 0, KMainW, 64)];        navBar.title = @"相册";        [navBar addBackButtonWithAction:@selector(photoViewBackAction)];        [self addSubview:navBar];        self.navBar = navBar;                //开启手绘按钮        UIButton *paintBtn = [[UIButton alloc] initWithFrame:CGRectMake(KMainW - 95, 20, 80, 44)];        paintBtn.selected = YES;        [paintBtn setTitle:@"显示画笔" forState:UIControlStateNormal];        [paintBtn setTitle:@"隐藏画笔" forState:UIControlStateSelected];        [paintBtn addTarget:self action:@selector(paintBtnOnClick:) forControlEvents:UIControlEventTouchUpInside];        [navBar addSubview:paintBtn];                //画笔工具条        HWPaintBar *paintBar = [[HWPaintBar alloc] initWithFrame:CGRectMake(KMainW - 60, 80, 44, 412)];        paintBar.delegate = self;        [self addSubview:paintBar];        self.paintBar = paintBar;                //布局        UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];        layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;        layout.minimumLineSpacing = KHWPhotoViewMargin;        layout.sectionInset = UIEdgeInsetsMake(KHWPhotoViewMargin, KHWPhotoViewMargin, KHWPhotoViewMargin, KHWPhotoViewMargin);                //浏览条        _collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, KMainH - KCollectionViewHeigth, KMainW, KCollectionViewHeigth) collectionViewLayout:layout];        _collectionView.backgroundColor = [UIColor colorWithHexString:@"003c65"];        _collectionView.dataSource = self;        _collectionView.delegate = self;        [self addSubview:_collectionView];                //注册标识        [_collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:reuseIdentifier];    }        return self;}//左滑事件- (void)nextPage{    if (_index < _photos.count - 1) {        _index ++;                //当滑动展示视图超出展示范围,未选中时进行翻页,先恢复到原位置        [_collectionView setContentOffset:CGPointMake(_startCollectionViewX, 0)];                //滑动时展示图最右边图片是否能完全显示        BOOL isIntactRight = (int)(_collectionView.contentOffset.x + KMainW) % (KHWPhotoViewMargin + KItemW) <= KHWPhotoViewMargin;                //滑动时展示图最右边图片item        NSInteger currentRightItem = (int)(_collectionView.contentOffset.x + KMainW) / (KHWPhotoViewMargin + KItemW);        if (isIntactRight) currentRightItem--;                //如果最右边item不能完全显示,并滑动到该item,左移视图至item完全显示        if (!isIntactRight && _index == currentRightItem) {            CGFloat movePadding = KItemW - ((int)(_collectionView.contentOffset.x + KMainW) % (KItemW + KHWPhotoViewMargin) - KHWPhotoViewMargin);            [_collectionView setContentOffset:CGPointMake(_collectionView.contentOffset.x + movePadding, 0)];        }                //如果滑动超出展示视图最大item,左移视图至item显示        if (_index > currentRightItem) {            CGFloat movePadding = KItemW - ((int)(_collectionView.contentOffset.x + KMainW) % (KItemW + KHWPhotoViewMargin) - KHWPhotoViewMargin) + (KItemW + KHWPhotoViewMargin);            if (isIntactRight) movePadding = movePadding - (KItemW + KHWPhotoViewMargin);            [_collectionView setContentOffset:CGPointMake(_collectionView.contentOffset.x + movePadding, 0)];        }                //刷新视图        [self reloadPhotoView];        [self transitionWithType:@"pageCurl" WithSubtype:kCATransitionFromRight ForView:self];            }else {        NSLog(@"已经是最后一页了");    }}//右滑事件- (void)forwardPage{    if (_index > 0) {        _index --;                //当滑动展示视图超出展示范围,未选中时进行翻页,先恢复到原位置        [_collectionView setContentOffset:CGPointMake(_startCollectionViewX, 0)];                //滑动时展示图最左边图片是否能完全显示        BOOL isIntactLeft = (int)_collectionView.contentOffset.x % (KHWPhotoViewMargin + KItemW) <= KHWPhotoViewMargin;                //滑动时展示图最左边图片item        NSInteger currentLeftItem = (int)_collectionView.contentOffset.x / (KHWPhotoViewMargin + KItemW);                //如果最左边item不能完全显示,并滑动到该item,右移视图至item完全显示        if (!isIntactLeft && _index == currentLeftItem) {            CGFloat movePadding = (int)_collectionView.contentOffset.x % (KItemW + KHWPhotoViewMargin);            [_collectionView setContentOffset:CGPointMake(_collectionView.contentOffset.x - movePadding, 0)];        }                //如果滑动超出展示视图最小item,右移视图至item显示        if (_index < currentLeftItem) {            CGFloat movePadding = (int)_collectionView.contentOffset.x % (KItemW + KHWPhotoViewMargin) + (KItemW + KHWPhotoViewMargin);            [_collectionView setContentOffset:CGPointMake(_collectionView.contentOffset.x - movePadding, 0)];        }                //刷新视图        [self reloadPhotoView];        [self transitionWithType:@"pageUnCurl" WithSubtype:kCATransitionFromRight ForView:self];            }else {        NSLog(@"已经是第一页了");    }}//下滑事件- (void)downSwipAction{    [self dismiss];    [[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationNone];        if (_back) _back(_imageView.frame, _index);}//更新视图信息- (void)reloadPhotoView{    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{        [self reloadSelectItem];    });    _scrollView.zoomScale = KPicMinScale;    _imageView.image = [UIImage imageWithContentsOfFile:[HWPhotoManger getImagePathWithImageName:_photos[_index]]];    [self setImageViewFrame];    _label.text = [NSString stringWithFormat:@"%ld / %ld", _index + 1, _photos.count];}//更新展示视图选中项- (void)reloadSelectItem{    _startCollectionViewX = _collectionView.contentOffset.x;        UICollectionViewCell *cell;    for (int i = 0; i < _photos.count; i++) {        cell = [_collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];        cell.backgroundView.layer.borderWidth = i == _index ? 5.0f : 0.0f;    }}//设置翻页动画效果- (void)transitionWithType:(NSString *)type WithSubtype:(NSString *)subtype ForView:(UIView *)view{    CATransition *animation = [CATransition animation];    animation.duration = 0.7f;    animation.type = type;    if (subtype != nil) {        animation.subtype = subtype;    }    animation.timingFunction = UIViewAnimationOptionCurveEaseInOut;    [view.layer addAnimation:animation forKey:@"animation"];}//单击屏幕显示隐藏菜单- (void)click{    if (_navBar.hidden == YES) {        _navBar.hidden = NO;        _collectionView.hidden = NO;        [[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationNone];            }else {        _navBar.hidden = YES;        _collectionView.hidden = YES;        [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationNone];    }}//双击屏幕放大缩小图片- (void)doubleClick{    [UIView animateWithDuration:0.25f animations:^{        _scrollView.zoomScale = _scrollView.zoomScale == KPicMinScale ? KPicMaxScale : KPicMinScale;    }];}//返回按钮点击事件- (void)photoViewBackAction{    [self dismiss];        if (_back) _back(_imageView.frame, _index);}//开启编辑按钮点击事件- (void)paintBtnOnClick:(UIButton *)btn{    btn.selected = !btn.selected;        _paintBar.hidden = !btn.selected;}//显示- (void)showWithSelectPhotoFrame:(CGRect)selectPhotoFrame selectItem:(NSInteger)selectItem{    self.hidden = NO;        _index = selectItem;        _label.text = [NSString stringWithFormat:@"%ld / %ld", _index + 1, _photos.count];    [_collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:_index inSection:0] atScrollPosition:UICollectionViewScrollPositionLeft animated:NO];        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{        [self reloadSelectItem];    });        _imageView.image = [UIImage imageWithContentsOfFile:[HWPhotoManger getImagePathWithImageName:_photos[_index]]];    _imageView.frame = selectPhotoFrame;        [UIView animateWithDuration:0.25f animations:^{        [self setImageViewFrame];    }];}//更新图片frame- (void)setImageViewFrame{    CGRect frame = _imageView.frame;    frame.size.width = _imageView.image.size.width > KMainW ? KMainW : _imageView.image.size.width;    frame.size.height = frame.size.width * (_imageView.image.size.height / _imageView.image.size.width);    if (frame.size.height > KMainH) {        frame.size.height = KMainH;        frame.size.width = KMainH * (_imageView.image.size.width / _imageView.image.size.height);    }    frame.origin.x = (KMainW - frame.size.width) * 0.5;    frame.origin.y = (KMainH - frame.size.height) * 0.5;    _imageView.frame = frame;}//隐藏- (void)dismiss{    _scrollView.zoomScale = KPicMinScale;    self.hidden = YES;}#pragma mark - HWPaintBarDelegate- (void)didClickClearBtnInHWPaintBar:(HWPaintBar *)paintBar{    [_paintView clear];}- (void)didClickCancelBtnInHWPaintBar:(HWPaintBar *)paintBar{    [_paintView cancel];}- (void)paintBar:(HWPaintBar *)paintBar didClickBrushBtnWithState:(BOOL)isOpen{    _paintView.hidden = !isOpen;        if (!isOpen) [_paintView clear];}- (void)paintBar:(HWPaintBar *)paintBar didClickStateBtnWithState:(int)state{    _paintView.lineState = state;}- (void)paintBar:(HWPaintBar *)paintBar didClickColorBtnWithColor:(UIColor *)color{    _paintView.lineColor = color;}#pragma mark - UICollectionViewDataSource- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{    return _thumPhotos.count;}- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];        cell.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageWithContentsOfFile:[HWPhotoManger getImagePathWithImageName:_thumPhotos[indexPath.item]]]];    cell.backgroundView.layer.borderColor = [[UIColor colorWithHexString:@"#00BFFF"] CGColor];    if (indexPath.item == _index) cell.backgroundView.layer.borderWidth = 5.0f;        return cell;}- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{    return CGSizeMake(KItemW, KItemH);}- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{    _index = indexPath.item;        [_paintView clear];        [self reloadPhotoView];}#pragma mark - UIScrollViewDelegate- (void)scrollViewDidZoom:(UIScrollView *)scrollView{    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;    self.imageView.center = CGPointMake(scrollView.contentSize.width * 0.5 + offsetX, scrollView.contentSize.height * 0.5 + offsetY);}- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView{    return self.imageView;}- (void)scrollViewDidScroll:(UIScrollView *)scrollView{    if (scrollView.isZooming) return;        //设置允许翻页的偏移量    CGFloat movePadding = 70;        //仿苹果原生相册,图片放大后,滑动前在边界时才允许翻页,这里加了±10的偏移量    if (scrollView.contentOffset.x < - movePadding && self.lastScrContX < 10) {        _scrollView.zoomScale = KPicMinScale;        [self forwardPage];    }        if (scrollView.contentSize.width - scrollView.contentOffset.x < KMainW - movePadding && scrollView.contentSize.width != 0 && fabs(self.lastScrContX + KMainW - scrollView.contentSize.width) < 10) {        _scrollView.zoomScale = KPicMinScale;        [self nextPage];    }}//滑动自然停止时调用- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{    //记录滑动停止时的偏移量    self.lastScrContX = scrollView.contentOffset.x;}//滑动手动停止时调用- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{    self.lastScrContX = scrollView.contentOffset.x;}@end

HWPaintView(绘画视图):

#import <UIKit/UIKit.h>typedef enum {    HWPaintLineStateNormal = 0,    HWPaintLineStateLight,} HWPaintLineState;@interface HWPaintView : UIView@property (nonatomic, assign) HWPaintLineState lineState;@property (nonatomic, strong) UIColor *lineColor;- (void)clear;- (void)cancel;@end/*** ---------------分割线--------------- ***/#import "HWPaintView.h"@interface HWPaintView ()@property (nonatomic, strong) NSMutableArray *paths;@end@implementation HWPaintView- (NSMutableArray *)paths{    if (!_paths) {        _paths = [NSMutableArray array];    }        return _paths;}- (instancetype)initWithFrame:(CGRect)frame{    if (self = [super initWithFrame:frame]) {        self.backgroundColor = [UIColor clearColor];        self.lineColor = [UIColor colorWithHexString:@"#fa4d32"];    }        return self;}- (void)clear{    [self.paths removeAllObjects];        [self setNeedsDisplay];}- (void)cancel{    [self.paths removeLastObject];        [self setNeedsDisplay];}- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{    UITouch *touch = [touches anyObject];    CGPoint startPoint = [touch locationInView:touch.view];        UIBezierPath *path = [UIBezierPath bezierPath];    path.lineCapStyle = kCGLineCapRound;    path.lineJoinStyle = kCGLineJoinRound;    path.lineWidth = 5;    [path moveToPoint:startPoint];    [path addLineToPoint:startPoint];    [self.paths addObject:path];        [self setNeedsDisplay];}- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{    UITouch *touch = [touches anyObject];    CGPoint currentPoint = [touch locationInView:touch.view];        UIBezierPath *path = [self.paths lastObject];    [path addLineToPoint:currentPoint];        [self setNeedsDisplay];}- (void)drawRect:(CGRect)rect{    for (UIBezierPath *path in self.paths) {        if (self.lineState == HWPaintLineStateNormal) {            [self.lineColor set];                    }else if (self.lineState == HWPaintLineStateLight) {            [[UIColor whiteColor] set];            CGContextSetShadowWithColor(UIGraphicsGetCurrentContext(), CGSizeMake(0, 0), 8, [self.lineColor CGColor]);        }                [path stroke];    }}@end

HWPhotoManger(图片加载缓存管理类,在这里获取图片、路径、进度):

#import <Foundation/Foundation.h>#import <UIKit/UIKit.h>@interface HWPhotoManger : NSObject@property (nonatomic, copy) void(^progressBlock)(CGFloat progress);@property (nonatomic, copy) void(^finishBlock)(NSArray *array, NSArray *thumArray);@property (nonatomic, copy) void(^error)();@property (nonatomic, assign, readonly) BOOL isLoading;@property (nonatomic, assign) CGFloat progress;+ (instancetype)sharePhotoManger;+ (NSString *)getPhotoVersionKeyWithPhotoID:(NSString *)photoID;+ (NSString *)getPhotoPathWithPhotoID:(NSString *)photoID;+ (NSString *)getThumPhotoPathWithPhotoID:(NSString *)photoID;+ (NSString *)getImagePathWithImageName:(NSString *)imageName;- (void)getImageWithUrlArray:(NSArray *)urlArray thumUrlArray:(NSArray *)thumUrlArray photoID:(NSString *)photoID version:(NSString *)version;@end/*** ---------------分割线--------------- ***/#import "HWPhotoManger.h"#define KPhotoCachesPath [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]@interface HWPhotoManger ()@property (nonatomic, assign, readwrite) BOOL isLoading;@end@implementation HWPhotoManger+ (instancetype)sharePhotoManger{    static HWPhotoManger *instance;        static dispatch_once_t onceToken;    dispatch_once(&onceToken, ^{        instance = [[self alloc] init];    });        return instance;}- (void)getImageWithUrlArray:(NSArray *)urlArray thumUrlArray:(NSArray *)thumUrlArray photoID:(NSString *)photoID version:(NSString *)version{    _isLoading = YES;    if (_progressBlock == nil) _progressBlock = ^(CGFloat progress) {};    if (_finishBlock == nil) _finishBlock = ^(NSArray *array, NSArray *thumArray) {};    if (_error == nil) _error = ^(){};        NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];    NSString *versionKey = [NSString stringWithFormat:@"photosVersionKey%@", photoID];        //本地相册路径(原图)    NSString *photoName = [@"HWPhotosCache" stringByAppendingString:photoID];    NSString *photoPath = [KPhotoCachesPath stringByAppendingPathComponent:photoName];    //本地相册路径(缩略图)    NSString *thumPhotoName = [@"HWThumPhotosCache" stringByAppendingString:photoID];    NSString *thumPhotoPath = [KPhotoCachesPath stringByAppendingPathComponent:thumPhotoName];        NSMutableArray *temArr = [NSMutableArray array];    NSMutableArray *thumTemArr = [NSMutableArray array];        __block int i = 0;    weakify(self);    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{        strongify(weakSelf);        for (NSString *url in urlArray) {            //加载图片(这个方式并不好)            UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:url]]];            if (image == nil) {                dispatch_async(dispatch_get_main_queue(), ^{                    strongSelf.error();                    strongSelf.isLoading = NO;                    strongSelf.progress = 0;                });                return;            }            //将图片保存到本地            NSString *imageName = [NSString stringWithFormat:@"%@image%d", photoName, i];            NSString *iamgePath = [KPhotoCachesPath stringByAppendingPathComponent:imageName];            [UIImagePNGRepresentation(image) writeToFile:iamgePath atomically:YES];            [temArr addObject:imageName];                        UIImage *thumImage = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:thumUrlArray[i++]]]];            if (thumImage == nil) {                dispatch_async(dispatch_get_main_queue(), ^{                    strongSelf.error();                    strongSelf.isLoading = NO;                    strongSelf.progress = 0;                });                return;            }            NSString *thumImageName = [NSString stringWithFormat:@"%@thumImage%d", thumPhotoName, i];            NSString *thumIamgePath = [KPhotoCachesPath stringByAppendingPathComponent:thumImageName];            [UIImagePNGRepresentation(thumImage) writeToFile:thumIamgePath atomically:YES];            [thumTemArr addObject:thumImageName];                        dispatch_async(dispatch_get_main_queue(), ^{                strongSelf.progress = (CGFloat)thumTemArr.count / urlArray.count;                strongSelf.progressBlock(strongSelf.progress);                                if (urlArray.count == thumTemArr.count) {                    strongSelf.finishBlock(temArr, thumTemArr);                    strongSelf.isLoading = NO;                    strongSelf.progress = 0;                                        //保存                    [defaults setObject:version forKey:versionKey];                    [NSKeyedArchiver archiveRootObject:temArr toFile:photoPath];                    [NSKeyedArchiver archiveRootObject:thumTemArr toFile:thumPhotoPath];                }            });        }    });}+ (NSString *)getPhotoVersionKeyWithPhotoID:(NSString *)photoID{    return [NSString stringWithFormat:@"photosVersionKey%@", photoID];}+ (NSString *)getPhotoPathWithPhotoID:(NSString *)photoID{    return [KPhotoCachesPath stringByAppendingPathComponent:[@"HWPhotosCache" stringByAppendingString:photoID]];}+ (NSString *)getThumPhotoPathWithPhotoID:(NSString *)photoID{    return [KPhotoCachesPath stringByAppendingPathComponent:[@"HWThumPhotosCache" stringByAppendingString:photoID]];}+ (NSString *)getImagePathWithImageName:(NSString *)imageName{    return [KPhotoCachesPath stringByAppendingPathComponent:imageName];}@end


还有几个自定义的视图不贴出来了。

相册Demo下载链接:http://code.cocoachina.com/view/134624

写博客的初心是希望大家共同交流成长,博主水平有限难免有偏颇之处,欢迎批评指正。

2 0
原创粉丝点击