2019独角兽企业重金招聘Python工程师标准>>>

一、前言

1、微博、资讯类型的APP客户端应用都会有图片浏览的需求,因此网络上涌现出大量的第三方图片浏览器插件,不管是用什么样的技术,大体的都能满足用户浏览图片的需求,例如单击图片隐藏、双击图片放大、手势缩放、左右切换以及保存图片等功能,就如本文要介绍的SDPhotoBrowser,也是我在研究github代码发现的,然后自己研究了源码;

2、原理大体如下,

(1)点击图片,弹出SDPhotoBrowser视图,此视图中包含scrollview滚动视图;

(2)SDPhotoBrowser视图被添加到window视图中,并在didMoveToSuperview方法中初始化视图;

(3)layoutSubviews布局视图,并加载currentIndex位置的图片,即showFirstImage函数;

(4)关键的部分,SDPhotoBrowser提供两个委托函数,- (UIImage *)photoBrowser:(SDPhotoBrowser *)browser placeholderImageForIndex:(NSInteger)index; - (NSURL *)photoBrowser:(SDPhotoBrowser *)browser highQualityImageURLForIndex:(NSInteger)index;分别获取指定index的缩略图或者是高清图;

(5)SDBrowserImageView自定义UIImageView,用于显示图片以及进行图片缩放与清除缩放等操作;

3、图片放大操作步骤,

(1)添加子视图_zoomingScroolView滚动视图,并在此滚动视图上创建_zoomingImageView显示放大图片的视图;

(2)执行放大操作,_zoomingScroolView的contentSize是临时UIImageView的size的两倍;

(3)所有的视图重新布局。

二、存在的问题与我的改进

1、原来的photoClick方法中,获取sourceView存在比较严重的耦合;

(1)我认为此处应该定义委托方法,执行委托方法获取视图比较稳妥,这个问题其实已有人在github中提出,即- (UIView *)photoBrowser:(SDPhotoBrowser *)browser viewWithIndex:(NSInteger)index;获取当前index的view视图;(同理showFirstImage方法也有这个问题)

- (void)photoClick:(UITapGestureRecognizer *)recognizer
{_scrollView.hidden = YES;_willDisappear = YES;SDBrowserImageView *currentImageView = (SDBrowserImageView *)recognizer.view;NSInteger currentIndex = currentImageView.tag;UIView *sourceView = nil;if ([self.sourceImagesContainerView isKindOfClass:UICollectionView.class]) {UICollectionView *view = (UICollectionView *)self.sourceImagesContainerView;NSIndexPath *path = [NSIndexPath indexPathForItem:currentIndex inSection:0];sourceView = [view cellForItemAtIndexPath:path];}else {sourceView = self.sourceImagesContainerView.subviews[currentIndex];}CGRect targetTemp = [self.sourceImagesContainerView convertRect:sourceView.frame toView:self];UIImageView *tempView = [[UIImageView alloc] init];tempView.contentMode = sourceView.contentMode;tempView.clipsToBounds = YES;tempView.image = currentImageView.image;CGFloat h = (self.bounds.size.width / currentImageView.image.size.width) * currentImageView.image.size.height;if (!currentImageView.image) { // 防止 因imageview的image加载失败 导致 崩溃h = self.bounds.size.height;}tempView.bounds = CGRectMake(0, 0, self.bounds.size.width, h);tempView.center = self.center;[self addSubview:tempView];_saveButton.hidden = YES;[UIView animateWithDuration:SDPhotoBrowserHideImageAnimationDuration animations:^{tempView.frame = targetTemp;self.backgroundColor = [UIColor clearColor];_indexLabel.alpha = 0.1;} completion:^(BOOL finished) {[self removeFromSuperview];}];
}

(2)通过委托对象降低耦合,改进如下;

- (void)photoClick:(UITapGestureRecognizer *)recognizer
{_scrollView.hidden = YES;_willDisappear = YES;SDBrowserImageView *currentImageView = (SDBrowserImageView *)recognizer.view;NSInteger currentIndex = currentImageView.tag;UIView *sourceView = nil;if ([self.sourceImagesContainerView isKindOfClass:UICollectionView.class]) {if ([self.delegate respondsToSelector:@selector(photoBrowser:viewWithIndex:)]) {sourceView = [self.delegate photoBrowser:self viewWithIndex:currentIndex];}} else {sourceView = self.sourceImagesContainerView.subviews[currentIndex];}CGRect targetTemp = [self.sourceImagesContainerView convertRect:sourceView.frame toView:self];UIImageView *tempView = [[UIImageView alloc] init];tempView.contentMode = sourceView.contentMode;tempView.clipsToBounds = YES;tempView.image = currentImageView.image;CGFloat h = (self.bounds.size.width / currentImageView.image.size.width) * currentImageView.image.size.height;if (!currentImageView.image) { // 防止 因imageview的image加载失败 导致 崩溃h = self.bounds.size.height;}tempView.bounds = CGRectMake(0, 0, self.bounds.size.width, h);tempView.center = self.center;[self addSubview:tempView];_saveButton.hidden = YES;[UIView animateWithDuration:SDPhotoBrowserHideImageAnimationDuration animations:^{tempView.frame = targetTemp;self.backgroundColor = [UIColor clearColor];_indexLabel.alpha = 0.1;} completion:^(BOOL finished) {[self removeFromSuperview];}];
}

2、- (void)scrollViewDidScroll:(UIScrollView *)scrollView,滚动视图委托,清除图片的缩放效果有误差,比如快速拖动已缩放图片缩放效果会被清除以及已缩放图片向左拖动会有很大的几率导致无法清除缩放效果;

(1)原本作者的意图是向左或者是向右拖动150的距离后,已缩放图片清除缩放效果,但我在测试的过程中向左拖动会清除缩放,向右拖动有概率不会清除缩放;

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{int index = (scrollView.contentOffset.x + _scrollView.bounds.size.width * 0.5) / _scrollView.bounds.size.width;// 有过缩放的图片在拖动一定距离后清除缩放CGFloat margin = 150;CGFloat x = scrollView.contentOffset.x;if ((x - index * self.bounds.size.width) > margin || (x - index * self.bounds.size.width) < - margin) {SDBrowserImageView *imageView = _scrollView.subviews[index];if (imageView.isScaled) {[UIView animateWithDuration:0.5 animations:^{imageView.transform = CGAffineTransformIdentity;} completion:^(BOOL finished) {[imageView eliminateScale];}];}}if (!_willDisappear) {_indexLabel.text = [NSString stringWithFormat:@"%d/%ld", index + 1, (long)self.imageCount];}[self setupImageOfImageViewForIndex:index];
}

(2)我的改进的思路是当没有成功切换至下一张图片时,不会清除已缩放图片的缩放效果,反之清除;通过visibleZoomingScrollViews保存已经显示的SDBrowserImageView视图,通过计算只保留当前显示在界面上的SDBrowserImageView的缩放效果,然后清除其他视图缩放效果;

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{CGRect visibleBounds = _scrollView.bounds;// 当scrollview滚动停止,firstIndex == lastIndex,即当前显示zoomingImageView的tag值NSInteger firstIndex = floor((CGRectGetMinX(visibleBounds)) / CGRectGetWidth(visibleBounds));NSInteger lastIndex  = floor((CGRectGetMaxX(visibleBounds)-1) / CGRectGetWidth(visibleBounds));if (firstIndex < 0) {firstIndex = 0;}if (firstIndex >= self.imageCount) {firstIndex = self.imageCount - 1;}if (lastIndex < 0){lastIndex = 0;}if (lastIndex >= self.imageCount) {lastIndex = self.imageCount - 1;}// 回收不再显示的zoomingImageViewNSInteger zoomingImageViewIndex = 0;for (SDBrowserImageView *zoomingImageView in self.visibleZoomingScrollViews) {zoomingImageViewIndex = zoomingImageView.tag;if (zoomingImageViewIndex < firstIndex || zoomingImageViewIndex > lastIndex) {zoomingImageView.transform = CGAffineTransformIdentity;[zoomingImageView eliminateScale];}}int index = (scrollView.contentOffset.x + _scrollView.bounds.size.width * 0.5) / _scrollView.bounds.size.width;if (!_willDisappear) {_indexLabel.text = [NSString stringWithFormat:@"%d/%ld", index + 1, (long)self.imageCount];}[self setupImageOfImageViewForIndex:index];
}

3、- (void)didMoveToSuperview执行了两次,官方文档Tells the view that its superview changed,意思是当superview改变的时候会执行此方法,也就是说添加子视图或者是移除子视图,都会执行;因此下面的代码逻辑会执行两遍,移除视图在执行以下逻辑会造成内存泄露;

- (void)didMoveToSuperview
{[self setupScrollView];[self setupToolbars];
}

因此,可以通过- (void)didMoveToWindow官网文档说明如下;

The window property may be nil by the time that this method is called, indicating that the receiver does not currently reside in any window. This occurs when the receiver has just been removed from its superview or when the receiver has just been added to a superview that is not attached to a window. Overrides of this method may choose to ignore such cases if they are not of interest.

意思是说,方法被执行后,window对象有可能为nil,发生此类情况时,比如视图已从父视图中被移除或者是被添加至另外一个并不附加任何window的父视图中。因此可以通过判断self.window是否为空判断SDPhotoBrowser是被添加还是被移除window,而我们需要的是添加至window是初始化view,如下;

- (void)didMoveToWindow
{if (self.window) {[self setupScrollView];[self setupToolbars];}
}

4、由于collectionView的重用机制导致的问题,没有显示在视图界面上的cell是无法获取到的,因此会导致单击关闭图片的动画失效;

我的解决方法,在scrollView切换图片的同时,通过委托方法- (void)photoBrowser:(SDPhotoBrowser *)browser scrollToItemAtIndex:(NSInteger)index滚动collectionView,确保切换图片对应的cell被显示;

// 滚动至指定的indexPath
- (void)photoBrowser:(SDPhotoBrowser *)browser scrollToItemAtIndex:(NSInteger)index
{NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0];[self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionTop animated:NO];
}// 加载图片
- (void)setupImageOfImageViewForIndex:(NSInteger)index
{SDBrowserImageView *imageView = _scrollView.subviews[index];self.currentImageIndex = index;// 加载图片的同时滚动collectionView,确保cell正常显示;if ([self.delegate respondsToSelector:@selector(photoBrowser:scrollToItemAtIndex:)]) {[self.delegate photoBrowser:self scrollToItemAtIndex:index];}if (imageView.hasLoadedImage) return;if ([self highQualityImageURLForIndex:index]) {[imageView setImageWithURL:[self highQualityImageURLForIndex:index] placeholderImage:[self placeholderImageForIndex:index]];} else {imageView.image = [self placeholderImageForIndex:index];}imageView.hasLoadedImage = YES;[self.visibleZoomingScrollViews addObject:imageView];
}

转载于:https://my.oschina.net/u/1450995/blog/804501

iOS-SDPhotoBrowser相关推荐

  1. iOS、mac开源项目及库(转载)

    目录 UI 下拉刷新 模糊效果 AutoLayout 富文本 图表 表相关 隐藏与显示 HUD与Toast 对话框 其他UI 动画 侧滑与右滑返回手势 其他动画 网络相关 网络连接 网络测试 图像获取 ...

  2. 一些iOS实用Demo

    图像浏览及处理 FLAnimatedImage - gif播放处理的工具. CLImageEditor - 超强的图片编辑库,快速帮你实现旋转,防缩,滤镜等等一系列麻烦的事情. ios-image-f ...

  3. iOS开发常用三方库、插件、知名博客

    TimLiu-iOS iOS开发常用三方库.插件.知名博客等等,期待大家和我们一起共同维护,同时也期望大家随时能提出宝贵的意见(直接提交Issues即可). 持续更新... 版本:Objective- ...

  4. iOS最全的三方库、插件、博客汇总

    目录 UI@ 日历三方库@ 下拉刷新@ 模糊效果@ 富文本@ 图表@ 颜色@ 表相关@(TabbleView.Tabbar.即时聊天界面) TableView@ CollectionView@ 隐藏与 ...

  5. iOS及Mac开源项目和学习资料

     iOS UI 下拉刷新 EGOTableViewPullRefresh – 最早的下拉刷新控件. SVPullToRefresh – 下拉刷新控件. MJRefresh – 仅需一行代码就可以为UI ...

  6. iOS - 常用的iOS Mac框架和库以及常用的中文开发博客

    对于iOS以及Mac开发中常用到的一些框架,以及比较好的技术博客做了总结: 主要内容如下: UI 下拉刷新 模糊效果 AutoLayout 富文本 图表 表相关 隐藏与显示 HUD与Toast 对话框 ...

  7. iOS比较好用的第三方框架

    目录 Model 数据库 缓存处理 图像浏览及处理 UI ① 下拉刷新 ②AutoLayout ③富文本 ④HUD与Toast ⑤其他UI 网络相关 ①网络连接 ②图像获取 ③网络测试 其他库 详情 ...

  8. iOS 开发的资源整理

    本文整理了常用的iOS.mac开源项目及类库,是开发者必备的一份资料,现在分享给广大的iOS程序员兄弟们,希望给他们的开发工作带来帮助. UI 下拉刷新 EGOTableViewPullRefresh ...

  9. iOS、mac开源项目及库

    1.用来生成 @3x 的图片资源对应的 @2x 和 @1x 版本,只要拖拽高清图到 @3x 的位置上,然后按Ctrl+Shift+A即可自动生成两张低清的补全空位.当然你也可以从 @2x 的图生成 @ ...

  10. iOS、Mac开源项目记录 - From TimLiu-iOS

    本篇博文并非本人整理,是从下面大神的Github下载,为了方便自己查看所以发布到这里.感谢大神整理. 来自:https://github.com/huang5556019/huang5556019.g ...

最新文章

  1. 创业3年!猎头加价50%!一半中层骨干被挖走,研发就剩2个应届生!绝户套餐真够狠的!...
  2. python图形缝隙填充_Python,如何缝合图像哪些重叠区域?
  3. datagridview显示每次点击都会往后追加_R410A空调安装(或系统维修后)排空及追加制冷剂操作工艺...
  4. Android的Menu状态动态设置方法onPrepareOptionsMenu(Menu menu) (转载)
  5. java8 list切片_java中怎么从一个数组中截取一定长度的元素放到新数组中
  6. 【报告分享】微信视频号新机遇白皮书.pdf
  7. DirectX SDK (June 2010)安装遇到Error Code S1023
  8. mysql实现不重复插入数据
  9. 江西省建设工程安全质量监督管理局全省工程安全质量信息数据维护升级存储及异地备份项目中标公告...
  10. python条形图的间距_Matplotlib有间隙条形图
  11. 在Windows Server 2012R2离线安装.net framework3.5
  12. ORACLE建表sql
  13. 「Injective衍生品市场创意大赛」角逐“最强王者”,就等你来
  14. Win11更改系统文件夹的默认保存位置方法分享
  15. 积化和差、和差化积公式及记忆
  16. Error “Client wants topic A to have B, but our version has C. Dropping connection.“
  17. git pull时遇到的问题
  18. JAVAWEB增删改查武林秘籍
  19. 【vue-router源码】五、router.addRoute、router.removeRoute、router.hasRoute、router.getRoutes源码分析
  20. 计算机视觉 专业术语,计算机视觉中常用的术语.doc

热门文章

  1. AI 产品经理的三重门
  2. 人工智能基础-算法工程师为什么要懂线性代数?
  3. CNN已老,GNN来了:重磅论文讲述深度学习的因果推理
  4. 对话式AI 2019年遇来的新市场
  5. 解读《德勤2017年全球CIO报告》:顶级CIO的炼成之道
  6. 挑战唯物论?诺奖得主彭罗斯:意识产生可能是大脑内的「量子叠加」的结果...
  7. 我国的人工智能芯片的市场规模及发展前景
  8. 量子计算和量子模拟研究获进展
  9. 全球43亿IPv4地址正式耗尽,IPv6才是物联网的菜
  10. 德勤2018TMT八大预测:移动互联网迎来二次革命