iOS图片浏览器二

上一篇文章讲到了图片的浏览 这里就把剩下的完善了吧
现在我们要加入的主要有以下几个点:

  • 图片下载时的进度条
  • UIScrollView的滑动 查看多张图片
  • 长按图片 弹出保存图片的选项 ###效果
    先看一下初步效果 还没做完 边写边做
    photoBrower

画进度圆

首先我们需要一个能显示进度的进度条 那就动手来写一个吧

先说一下思路 这个圆应该是根据不同的进度条 来绘制进度 所以需要及时传进进度 然后绘制图像 主要的代码 还是在drawRect这个方法里面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

- (void)drawRect:(CGRect)rect
{
CGContextRef ctx = UIGraphicsGetCurrentContext();

//在当前的view中心点画圆 画灰色的那个全圆
CGFloat xCenter = rect.size.width * 0.5;
CGFloat yCenter = rect.size.height * 0.5;

//计算圆的半径
CGFloat radius = MIN(rect.size.width * 0.5, rect.size.height * 0.5) - YQProgressViewItemMargin;

// 背景圆
[YQColorMaker(240, 240, 240, 1) set];
//set方法 苹果是这样给出说明的 大致意思就是在当前画的这个view的这个范围内 // 用什么颜色填充
// Set the color: Sets the fill and stroke colors in the current // drawing context. Should be implemented by subclassers.
// - (void)set;

CGFloat w = radius * 2 + 4;
CGFloat h = w;
CGFloat x = (rect.size.width - w) * 0.5;
CGFloat y = (rect.size.height - h) * 0.5;
CGContextAddEllipseInRect(ctx, CGRectMake(x, y, w, h));
CGContextFillPath(ctx);

// 进程圆 画白色的圆
[YQColorMaker(150, 150, 150, 0.8) set];
CGContextMoveToPoint(ctx, xCenter, yCenter);
CGContextAddLineToPoint(ctx, xCenter, 0);
CGFloat to = -M_PI * 0.5 + self.progress * M_PI * 2 + 0.001; // 初始值
CGContextAddArc(ctx, xCenter, yCenter, radius, -M_PI * 0.5, to, 1);
CGContextClosePath(ctx);

CGContextFillPath(ctx);
}

加入单个图片

然后就是在我们之前的设置每张图片的位置 将这个下载进度的view添加进去

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
/**
创建每一张照片 每一张照片都是一个scrollview
scrollview可缩放
*/
-(void)setupphotoScrollViews{
for (int i=0; i<self.photos.count; i++) {
UIScrollView *photoScrollView = [[UIScrollView alloc] init];
photoScrollView.backgroundColor = [UIColor clearColor];
photoScrollView.tag = i;
photoScrollView.frame = CGRectMake(SCREEN_WIDTH*i, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
photoScrollView.delegate = self;
photoScrollView.maximumZoomScale=2.0;
photoScrollView.minimumZoomScale=1;
[self.outScrollView addSubview:photoScrollView];

Photo *photo = self.photos[i];
UITapGestureRecognizer *photoTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(photoTap:)];
UITapGestureRecognizer *zonmTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(zonmTap:)];
zonmTap.numberOfTapsRequired = 2;
[photoScrollView addGestureRecognizer:photoTap];
[photoScrollView addGestureRecognizer:zonmTap];
[photoTap requireGestureRecognizerToFail:zonmTap];

[photoScrollView addSubview:photo];
//有本地高清大图 直接大图显示出来就不需要再次访问网络
if (photo.fullImage) {
photo.image = photo.fullImage;
photo.frame = [self.originRects[i] CGRectValue];
[UIView animateWithDuration:0.3 animations:^{

self.blackView.alpha = 1.0;

CGFloat ratio = (double)photo.image.size.height/(double)photo.image.size.width;

CGFloat bigW = SCREEN_WIDTH;
CGFloat bigH = SCREEN_WIDTH*ratio;

photo.bounds = CGRectMake(0, 0, bigW, bigH);
photo.center = CGPointMake(SCREEN_WIDTH/2, SCREEN_HEIGHT/2);
}];
return;
}
ProgressView *progress = [[ProgressView alloc] initWithFrame:CGRectMake(SCREEN_WIDTH/2.0-30, SCREEN_HEIGHT/2.0-30, 60, 60)];
NSURL *fullImgUrl = [NSURL URLWithString:photo.fullImgUrl];
[photo sd_setImageWithURL:fullImgUrl placeholderImage:nil options:SDWebImageRetryFailed | SDWebImageLowPriority progress:^(NSInteger receivedSize, NSInteger expectedSize) {
//开始下载 这里后面会做一些效果 比如下载的进度条 一个load
photo.frame = CGRectMake(0, 0, SCREEN_WIDTH/2, SCREEN_HEIGHT/3);
photo.center = CGPointMake(SCREEN_WIDTH/2, SCREEN_HEIGHT/2);
photo.image = photo.thumbnail.image;
self.blackView.alpha = 1.0;
[photoScrollView addSubview:progress];
progress.progress = receivedSize*1.0/expectedSize*1.0;

} completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
if (image!=nil) {
[progress dismiss];
photo.frame = [self.originRects[i] CGRectValue];
//如果是网上下载下来的图片 那么改变一下photo的位置 后面做动画 会和已有缓存的图片显示效果不一样
if (cacheType==SDImageCacheTypeNone) {
photo.frame = CGRectMake(0, 0, SCREEN_WIDTH/2, SCREEN_HEIGHT/2);
photo.center = CGPointMake(SCREEN_WIDTH/2, SCREEN_HEIGHT/2);
}
[UIView animateWithDuration:0.3 animations:^{
self.blackView.alpha = 1.0;
CGFloat ratio = (double)photo.image.size.height/(double)photo.image.size.width;
CGFloat bigW = SCREEN_WIDTH;
CGFloat bigH = SCREEN_WIDTH*ratio;
photo.bounds = CGRectMake(0, 0, bigW, bigH);
photo.center = CGPointMake(SCREEN_WIDTH/2, SCREEN_HEIGHT/2);
}];
}else{
//下载错误 提示一个 错误需要 这里可以根据你自己项目的需求 提示错误 alert 还是 一个类似于Android的toast都可以 我觉得alert还是 太不友好了
}
}];
}
}

这样 每张图片都有自己对应的下载进度 下载完成之后 会在complete方法之中 将progress移除掉

再加入uiscrollView的滑动切换图片

在之前我们就已经想到了 所以在写的时候 在show方法中 加入当前UIscrollView偏移量和contentsize

设置外层的UIScrollView

1
2
3
//3.设置滚动距离
self.outScrollView.contentSize = CGSizeMake(SCREEN_WIDTH*self.photos.count, 0);
self.outScrollView.contentOffset = CGPointMake(SCREEN_WIDTH*self.currentIndex, 0);

在展示的时候 只需要调用 photoBrower的show方法

1
2
3
4
5
6
7
/**
显示大图

@param photos 照片数组 装的Photo
@param index 当前的照片是第几张
*/
+ (void)showWithPhotos:(NSArray *)photos index:(NSInteger)index;

同样的测试一下

1
2
3
4
5
6
7
8
9
10
11
UIImageView *thumbnail = (UIImageView *)recognizer.view;
Photo *photo = nil;
Photo *photo1 = nil;
if (thumbnail.tag<3) {//属于有大图的
photo = [[Photo alloc] initWithThumbnail:thumbnail fullImage:thumbnail.image fullImgUrl:nil];
photo1 = [[Photo alloc] initWithThumbnail:thumbnail fullImage:thumbnail.image fullImgUrl:nil];
}else{
photo = [[Photo alloc] initWithThumbnail:thumbnail fullImage:nil fullImgUrl:@"http://pic24.nipic.com/20121003/10754047_140022530392_2.jpg"];
photo1 = [[Photo alloc] initWithThumbnail:thumbnail fullImage:nil fullImgUrl:@"http://e.hiphotos.baidu.com/image/pic/item/14ce36d3d539b600be63e95eed50352ac75cb7ae.jpg"];
}
[PhotoBrower showWithPhotos:@[photo,photo1] index:0];

在photo中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

/**
* 缩略图 imageView
*/
@property (nonatomic, strong) UIImageView *thumbnail;

/**
高清图
如果存在 则在显示的时候优先显示设置的本地大图
*/
@property (nonatomic, strong) UIImage *fullImage;


/**
* 大图URL 存在本地大图时 还是优先显示本地大图
*/
@property (nonatomic,strong) NSString *fullImgUrl;

如果当前查看的图片没有本地图片 那么 只需要传入thumbnail fullImgUrl

如果当前的有本地图和远程图 那么三个都传入 会优先展示本地的图片

因为图片下载使用的SDWebImage 所以下载的图片也是优先使用 缓存

保存图片到相册

再加上保存图片的方法 简单的图片浏览器就基本完成了

先看一下效果是怎样
允许你访问相册 保存成功
saveSuccess

不允许访问相册,保存失败

saveFailes

这个ActionSheet是我自己定义的一个简单的actionsheet
具体可以查看这篇文章:

http://ppsheep.com/2016/10/24/iOS类似于微信的ActionSheet/

在展示大图时 给PhotoScrollView添加一个长按手势

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#pragma mark - 添加手势
- (void)addCustomGestureRecognizer:(UIView *)targetView{
//单击手势
UITapGestureRecognizer *photoTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(photoTap:)];
//双击手势
UITapGestureRecognizer *zonmTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(zonmTap:)];
zonmTap.numberOfTapsRequired = 2;
[targetView addGestureRecognizer:photoTap];
[targetView addGestureRecognizer:zonmTap];
[photoTap requireGestureRecognizerToFail:zonmTap];
//长按手势
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(savePhoto:)];
[longPress requireGestureRecognizerToFail:zonmTap];
[longPress requireGestureRecognizerToFail:photoTap];
[targetView addGestureRecognizer:longPress];
}

在ActionSheet的代理中 保存图片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#pragma mark - PPSActionSheetDelegate
-(void)actionSheet:(PPSActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{
if (buttonIndex == 1) {
Photo *photo = self.photos[self.currentIndex];
if (photo.image) { //保证图片存在 已经下载完成
//判断是否有访问相册权限
PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
if (status == PHAuthorizationStatusRestricted ||
status == PHAuthorizationStatusDenied) {
//没有权限 拒绝
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示" message:@"没有访问相册的权限" delegate:self cancelButtonTitle:nil otherButtonTitles:@"确定", nil];
[alert show];
}else{
UIImageWriteToSavedPhotosAlbum(photo.image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
}
}
}
}

在保存图片的时候 需要注意一点就是 需要判断权限是否 存在

特别是在iOS的时候 访问相机 相册 都需要在info里加上权限 具体可以百度一下 相册权限字段描述是 Privacy - Photo Library Usage Description

好了 一个 基本的图片浏览器 就完成了

项目的源码放在:

https://github.com/yangqian111/blog/tree/master/iOS图片查看器