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. 有哪些新手程序员不知道的小技巧?
  2. P13 最优控制系统-《Matlab/Simulink与控制系统仿真》程序指令总结
  3. 好系统重装助手教您如何设置宽带并连接无线上网
  4. SpringBoot项目优化和Jvm调优及VisualVM远程连接监控JVM(JMX连接)
  5. PHP中的数组建必须为数字吗,PHP检查数组中缺少的数字
  6. python_code_417
  7. 计算机制图的简称市什么,计算机地的图制图复习题.doc
  8. ORM框架之Spring Data JPA(二)spring data jpa方式的基础增删改查
  9. Vuex的State核心概念
  10. skynet 学习笔记-netpack模块(1)
  11. 如何在 iPhone 和 iPad 上关闭 Spotlight 建议?
  12. RESTFeel: 一个企业级的API管理测试平台。RESTFeel帮助你设计、开发、测试您的API...
  13. CC攻击原理及防范新思路
  14. 5.13 广东移动 笔试题
  15. linux根下目录都代表什么,Linux根目录下的各个目录结构及作用
  16. python中的numpy标准正态分布_Numpy创建正态分布和均匀分布
  17. 计算机控制台win10,Win10系统打开Windows控制台的方法
  18. 千峰 音乐播放器 待续
  19. 原本 1.3绿色版-扫描仪/相机/手机拍摄照片变清晰软件
  20. c语言打印红色爱心(程序员的浪漫)

热门文章

  1. SAP QM 检验批号码跳号问题之对策
  2. AI科学家王怀清:机器视觉识别领域 或将出现AI独角兽
  3. 源数据文件(.csv)中的空格串和空串对pandas读取结果的影响
  4. 人工智能,“抛弃”真实数据集?
  5. 中文语言能力评测基准「智源指数」问世:覆盖17种主流任务,19个代表性数据集,更全面、更均衡...
  6. 什么是传感器融合?我们从“盲人摸象”讲起……
  7. 2021世界人工智能大会最高奖项——卓越人工智能引领者奖(Super AI Leader,简称SAIL奖)在大会开幕式揭晓...
  8. AR普及后的未来是怎样的?
  9. 未来五年人工智能将实现的五大突破
  10. 新技术不断涌现,下一代云计算的突破口在哪里?