转载

iOS详细写一个功能完善的PhotoBrowser同时支持GIF(一)

写一个功能完善的图片浏览器

最终效果 源码

iOS详细写一个功能完善的PhotoBrowser同时支持GIF(一)

网络.gif

iOS详细写一个功能完善的PhotoBrowser同时支持GIF(一)

本地图片.gif

本篇文章后完成的效果

iOS详细写一个功能完善的PhotoBrowser同时支持GIF(一)

效果.gif

首先来列出我们可能会实现的功能

1.基本功能

  • 支持双击缩小和放大点击的区域
  • 单击退出
  • 支持响应长按手势
  • 支持图片的捏合实现缩放
  • 支持浏览的时候显示页数(例如 12/40)
  • 支持点击保存图片
  • 支持加载本地图片

2. 高级功能

  • 支持加载网络图片
  • 支持显示加载的进度条
  • 支持网络图片的缓存
  • 支持指定下标到特定的图片
  • 支持gif
  • 可选择的显示每一张图片的描述文字

清楚了这些可能会实现的功能,接下来就从简单的开始分布实现

首先处理每一张图片共有的功能, 比如单击和双击以及缩放, 在本篇中,我们主要是来实现每一张图片拥有的一些功能

一. 提到单击和双击,大家可能就直接想到了直接在相应的ImageView上添加两个UITap手势即可完成, 没错可能要实现手势的响应确实是这么简单, 但是想想我们是要在双击的时候处理缩放, 那么一个难点就是怎样实现图片的缩放

  • 我们可以在双击的时候直接处理ImageView的transform来实现缩放, 而且还可以加上一点动画让这个过程更自然, 看上去这还是个可操作易行的方法
  • 我们知道UIScrollView本身帮我们处理好了缩放的功能, 使用它来响应双击手势也许也是可行的, 不过现在我还么没有完全确定, 就是要使用UIScrollView, 因为还有其他的功能没有分析怎么实现

二. 支持图片的捏合实现缩放, 要实现这个功能, 看到捏合两个字, 我们的第一反应,一定是在ImageVIew上添加一个UIPinchGestureRecognizer手势来处理, 没错添加pinch这个手势确实可以考虑

  • 添加UIPinchGestureRecognizer到ImageVIew上, 然后在手势的响应中对应的处理ImageView的transform实现捏合, 不过,要怎么来处理这个过程中的transform确实还是很麻烦的
  • 我们知道UIScrollView本身帮我们处理好了缩放的功能,只需要很简单的配置就能事项捏合的功能

清楚了上面两点,选择UIScrollView来实现图片的各种手势效果无疑是简单的, 所以就选择了UIScrollView, 所以这样很自然的就想到了每一张图片的View层次, 最底层是一个UIView做容器,同时用来成为UIScrollView的代理, 然后在上面添加UIScrollView来响应手势和缩放, 最后在上面添加ImageView来添加图片

实现部分

  1. 新建一个PhotoView类继承自UIView
  2. 在PhotoView中依次添加UIScrollView和UIImageView
    iOS详细写一个功能完善的PhotoBrowser同时支持GIF(一)

    懒加载子控件.png

  3. 设置UIScrollView和UIImageView的frame

    这里需要注意的是设置UIImageView的frame的时候, 如果你是设置他的frame为UIScrollView的bounds, 那么会出现的情况是进行图片放大的时候, 因为是对ImageView整体放大, 所以图片以外的区域也被放大,浏览的效果就是这样的, 不得不吐槽有些app就是这么简单的处理的

    iOS详细写一个功能完善的PhotoBrowser同时支持GIF(一)

    空白区域被放大.gif


    而我们希望的imageView的宽高是和设置的图片宽高相同或者成比例的缩放, 就是说图片会全部充满imageView, 效果就是这样的

    iOS详细写一个功能完善的PhotoBrowser同时支持GIF(一)

    空白区域不放大.gif

  4. 处理UIScrollView实现缩放

      要实现缩放, 只需要设置三个地方   1. 设置scrollView的最大最小缩放倍数, 注意最大倍数必须要大于最小倍数(注意不是大于等于)  scrollView.maximumZoomScale = 2.0  scrollView.minimumZoomScale = 1.0  2. 设置代理  scrollView.delegate = self  3. 实现缩放的代理方法, 在这个代理方法中返回要缩放的对象, 当然在我们这里就是imageView, 完成这三步后就可以实现捏合的缩放了       func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {      return imageView  }

    恩好完成上面几步后, 我们就已经完成了图片的捏合缩放功能, 不过这里有个问题, 在缩小的时候, 我发现图片没有居中, 我们肯定希望图片居中缩放

    iOS详细写一个功能完善的PhotoBrowser同时支持GIF(一)

    不能居中缩放.gif


    于是在UIScrollView的这个代理方法允许我们监控缩放的过程, 所以我们可以处理imageView的位置

      func scrollViewDidZoom(scrollView: UIScrollView) {      // 居中显示图片, 大家可以使用if语句来理解, 不过我发现使用if后居然效果不对(##<>##), 没有找到原因      let offsetX = (scrollView.zj_width > scrollView.contentSize.width) ? (scrollView.zj_width - scrollView.contentSize.width)*0.5 : 0.0      let offsetY = (scrollView.zj_height > scrollView.contentSize.height) ? (scrollView.zj_height - scrollView.contentSize.height)*0.5 : 0.0       imageView.center = CGPoint(x: scrollView.contentSize.width * 0.5 + offsetX, y: scrollView.contentSize.height * 0.5 + offsetY)  }

    添加完这一小段代码后效果是这样的,还是很满意

    iOS详细写一个功能完善的PhotoBrowser同时支持GIF(一)

    居中缩放.gif

  5. 添加单击和双击手势, 注意需要解决单击和双击手势的冲突

          let singleTap = UITapGestureRecognizer(target: self, action: #selector(self.handleSingleTap(_:)))      singleTap.numberOfTapsRequired = 1      singleTap.numberOfTouchesRequired = 1       let doubleTap = UITapGestureRecognizer(target: self, action: #selector(self.handleDoubleTap(_:)))      doubleTap.numberOfTapsRequired = 2      doubleTap.numberOfTouchesRequired = 1       // 允许优先执行doubleTap, 在doubleTap执行失败的时候执行singleTap      // 如果没有设置这个, 那么将只会执行singleTap 不会执行doubleTap      singleTap.requireGestureRecognizerToFail(doubleTap)       addGestureRecognizer(singleTap)      addGestureRecognizer(doubleTap)

    单击手势的响应, 每一张图片自身不处理单击手势, 我们希望由之后的PhotoBrowser来处理, 所以这里使用了Closure

      // 单击手势, 给外界处理  func handleSingleTap(ges: UITapGestureRecognizer) {       singleTapAction?(gesture: ges)  }

    双击手势处理, 放大或者缩小

          if scrollView.zoomScale <= scrollView.minimumZoomScale { // 放大          scrollView.setZoomScale(scrollView.maximumZoomScale, animated: true)      } else {// 缩小很简单, 直接设置缩小到的倍数, 这里我希望缩放到最小          scrollView.setZoomScale(scrollView.minimumZoomScale, animated: true)       }

    这样就处理好了双击的放大和缩小, 但是目前的放大到最大区域的时候, 并不是我们想要的放大点击区域的效果, 所以放大肯定还需要单独的处理

    iOS详细写一个功能完善的PhotoBrowser同时支持GIF(一)

    固定放大.gif

经过一番的研究, 如下处理效果还比较满意

         if scrollView.zoomScale <= scrollView.minimumZoomScale { // 放大              let location = ges.locationInView(scrollView)             // 放大scrollView.maximumZoomScale倍, 将它的宽高缩小这么多倍             let width = scrollView.zj_width/scrollView.maximumZoomScale             let height = scrollView.zj_height/scrollView.maximumZoomScale             // 这里需要进行一点的数学换算得来             let rect = CGRect(x: location.x * (1 - 1/scrollView.maximumZoomScale), y: location.y * (1 - 1/scrollView.maximumZoomScale), width: width, height: height)             // 这个方法会根据提供的rect来缩放, 如果给的宽高小余scrollView的宽高, 将进行相应的倍数放大的操作, 如果大于, 就会进行缩小到最小操作             scrollView.zoomToRect(rect, animated: true)          } else {// 缩小             scrollView.setZoomScale(scrollView.minimumZoomScale, animated: true)          }

到目前为止, 单张图片的处理基本就完整了,运行的效果就和最初给的单张相似 如果你只是需要显示一张图片, 那么这个图片浏览器就已经很完善了, 当然我相信,你肯定也希望能处理多张图片, 具体实现将会在下一篇介绍, 欢迎关注

文/ZeroJ(简书)
 

 

正文到此结束
Loading...