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
- iOS 浏览相册功能实现 —— HERO博客
- iOS 摇一摇功能实现 —— HERO博客
- iOS 扫一扫功能实现 —— HERO博客
- iOS 答题功能实现 —— HERO博客
- iOS UICollectionView实现图片轮播 —— HERO博客
- iOS UIScrollView简介 —— HERO博客
- iOS UICollectionView简介 —— HERO博客
- iOS UITextField简介 —— HERO博客
- iOS UIDynamic简介 —— HERO博客
- iOS 添加字体库 —— HERO博客
- iOS MD5加密 —— HERO博客
- iOS UITableView简介 —— HERO博客
- iOS 预产期计算器 —— HERO博客
- iOS UISearchBar简介 —— HERO博客
- iOS UISearchBar使用 —— HERO博客
- iOS 自定义日历 —— HERO博客
- iOS 自定义键盘 —— HERO博客
- iOS 图片压缩 —— HERO博客
- AndroidStudio开发jni不加载libs的so,只加载jniLibs的so
- 创建SVN的服务
- malloc与new的区别
- Java学习----day5——(1)面对对象程序设计基础篇
- Java动态代理
- iOS 浏览相册功能实现 —— HERO博客
- Unity脚本声明周期
- IIC和SPI总线比较
- 前端框架React
- Fragment嵌套Fragment遇到的问题
- 秒杀多线程
- 前序遍历和中序遍历树构造二叉树
- php __sleep() 和__wakeup()
- 测试