iOS詳細寫一個功能完善的PhotoBrowser同時支持GIF(一)

nwah8807 9年前發布 | 15K 次閱讀 IOS GIF iOS開發 移動開發 PhotoBrowser

寫一個功能完善的圖片瀏覽器

最終效果 源碼

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(簡書)
 

 

 本文由用戶 nwah8807 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!