iOS 瀏覽相簿功能實現 —— HERO部落格
阿新 • • 發佈:2019-01-28
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 HWPhotoVC static 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 HWPhotoView static 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
還有幾個自定義的檢視不貼出來了。
寫部落格的初心是希望大家共同交流成長,博主水平有限難免有偏頗之處,歡迎批評指正。