iOS 自定義圖片選擇器 2 - UIScrollView縮放

【 寫在前面:筆者按照Instagram的圖片選取器寫了個(gè)小Demo,
該系列文章為筆者實(shí)現(xiàn)Demo的步驟,若有不正確的地方還望指出來(lái),共同學(xué)習(xí)。
地址:https://github.com/BigBigPo/RJPhotoPicker

前一篇簡(jiǎn)單的介紹了PhotoKit的使用,圖片資源我們已經(jīng)拿到了,接下來(lái)就該寫選擇器了。我們先看看Instagram的圖片選擇器是什么樣子——


Insshow.gif

可以看出,界面上分為兩大塊,“展示區(qū)”與“列表區(qū)”,兩個(gè)區(qū)域具有聯(lián)動(dòng)屬性。我們先看上方的展示區(qū),這個(gè)區(qū)域最主要的功能是展示用戶當(dāng)前選中的圖片,并且具有縮放,拖動(dòng)改變圖片填充方式等功能。

看到“縮放”,“拉伸”這些字眼時(shí),筆者第一反應(yīng)就想到了UIScrollView,其完全具備上述功能,在使用中也有需要注意的事項(xiàng),下面我們就以UIScrollView來(lái)實(shí)現(xiàn)展示區(qū)的功能。


0.思考

要實(shí)現(xiàn)縮放功能很簡(jiǎn)單,Instagram的展示區(qū)還有很多細(xì)節(jié):
1、 默認(rèn)情況下,圖片將會(huì)按比例填充整個(gè)展示區(qū)(類似.ScaleAspectFill的填充效果)
2、展示區(qū)默認(rèn)中心定位在圖片中央
3、圖片的四周均具有彈簧效果。

最主要的是這三個(gè)特性,當(dāng)然還有其他次要的效果,如線框、更改填充樣式等等,這些都是錦上添花的功能,上述三個(gè)效果是其基本功能(展示,縮放)所必須具有的,權(quán)重也是最高的。

對(duì)于細(xì)節(jié)1,筆者一開始直接想到的是UIImageView的ContentMode,這個(gè)是UIImageView自身的展示方式,僅僅只是展示圖片是沒(méi)有問(wèn)題的,但現(xiàn)在需要將其加入到ScrollView中還需要達(dá)到細(xì)節(jié)2,但有點(diǎn)多余。

為什么?

細(xì)節(jié)2的實(shí)現(xiàn)上,因?yàn)槲覀兊恼故緟^(qū)域的大小是固定的,所以需要將圖片視圖進(jìn)行適配,需要獲取圖片視圖的大小,再根據(jù)contentView的大小重設(shè)UIImageView的大小來(lái)進(jìn)行適配,以此為依據(jù)來(lái)確定ScrollView的區(qū)域位置。若我們使用了UIImageView的ContentMode,我們還是要獲取圖片的大小。
這樣看來(lái),UIImageView的contentMode顯得多余了,我們會(huì)重設(shè)UIImageView的尺寸,而根據(jù)需求來(lái)看,這個(gè)重設(shè)UIImageView的尺寸就包含了我們需要的“ .ScaleAspectFill”效果。

若被繞暈了沒(méi)有關(guān)系,我們一步一步來(lái),文章最后有Demo以供參考。

接下來(lái)

1.準(zhǔn)備工作

新建一個(gè)項(xiàng)目,在場(chǎng)景中加入一個(gè)UIScrollView,并在該ScrollView中加入一個(gè)UIImageView,設(shè)置好約束(筆者用的XIB,代碼也可以,后面統(tǒng)一以XIB來(lái)講)。

因?yàn)槲覀円獙?shí)時(shí)的重置展示區(qū)的約束,所以我們需要拿到UIImageView的“寬”、“高”、“左距”、“右距”。以方便后續(xù)操作。


views.png

如上圖,界面十分簡(jiǎn)單,Next按鈕只是Demo為了切換不同尺寸的圖片。XIB中的效果如下:

viewsShow.png

2.縮放功能

單獨(dú)的縮放功能十分簡(jiǎn)單,只需要設(shè)置好UIScrollView的縮放系數(shù),以及在代理中返回需要縮放的視圖即可。

    [_scrollView setDelegate:self];         //不要忘記添加代理
    [_scrollView setMinimumZoomScale:1];    //最小縮放系數(shù)
    [_scrollView setMaximumZoomScale:2];    //最大縮放系數(shù)
//該代理方法需要返回一個(gè)需要縮放的view,若返回nil,將沒(méi)有任何效果。
//注:在TableView、UICollectionView中使用UIScrollView來(lái)完成縮放效果時(shí),直接返回imageView可能不能達(dá)到效果,需要給imageView套一層View,在此代理中返回該view即可解決。
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
    return _imageView;
}

單純的縮放功能就實(shí)現(xiàn)了,但圖片的大小,位置特別的奇怪,我們需要優(yōu)化一下。順便提一下,UIScrollView還提供了關(guān)于縮放更多代理,可以據(jù)此實(shí)現(xiàn)許多功能。

- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view;
- (void)scrollViewDidZoom:(UIScrollView *)scrollView;
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale

3.適配圖片的大小與位置

首先要確定圖片視圖的大小,才能更好的確定展示區(qū)具體的位置。圖片的大小適配,其實(shí)就是根據(jù)圖片的大小按照填充的類型(鋪滿,填充),保持比例縮放至容器(UIScrollView)的大小。也就是一個(gè)計(jì)算尺寸的過(guò)程。

/**
 根據(jù)圖片的大小來(lái)獲得合適的容器大小
 */
- (CGSize)getImageVeiwSizeWithImage:(UIImage *)image {
    //獲取scrollView的尺寸(在Demo中,我們把scrollView的長(zhǎng)寬都設(shè)置成了屏寬,是相等的)
    CGFloat scrollViewSize = [UIScreen mainScreen].bounds.size.width;
    
    //注:下方的 +1 只是為了方便實(shí)現(xiàn)ScrollView的邊界彈簧效果,并無(wú)其他用處
    CGFloat width = scrollViewSize + 1;
    CGFloat height = width / image.size.width * image.size.height;
    if (height < scrollViewSize) {
        height = scrollViewSize + 1;
        width = height / image.size.height * image.size.width;
    }
    return CGSizeMake(width, height);
}

圖片的位置也就是UIScrollView的contentOffset,來(lái)實(shí)現(xiàn)。現(xiàn)在已經(jīng)計(jì)算出了圖片的展示尺寸,就可以知道圖片的位置(UIScrollView的contentOffset)

/**
 根據(jù)圖片視圖大小來(lái)確定圖片位置
 */
- (void)setScrollViewCenterWithImageSize:(CGSize)size {
    //獲取scrollView的尺寸(在Demo中,我們把scrollView的長(zhǎng)寬都設(shè)置成了屏寬,是相等的)
    CGFloat scrollViewSize = [UIScreen mainScreen].bounds.size.width;
    
    //獲取圖片中心以此為依據(jù)計(jì)算scrollView的contentOffset
    CGPoint imageCenter = CGPointMake(size.width / 2, size.height / 2);
    CGPoint point = CGPointMake(imageCenter.x - scrollViewSize / 2, imageCenter.y - scrollViewSize / 2);
    [_scrollView setContentOffset:point];
}

展示區(qū)的主要功能到此就全部實(shí)現(xiàn)了,UIScrollView來(lái)實(shí)現(xiàn)縮放是比較簡(jiǎn)單的,代碼中我也舉出了自己遇到的一個(gè)問(wèn)題,以及解決辦法:
在UIScrollView在另一個(gè)ScrollView中時(shí),可能出現(xiàn)縮放無(wú)效的問(wèn)題,例如,UITabelView 或 UICollectionVewi的Cell中。筆者的解決辦法是在imageView外套一層View,這樣可以解決問(wèn)題,但還未知道其中的原理,也許是兩個(gè)ScrollView嵌套的問(wèn)題,或者是列表控件的內(nèi)部機(jī)制?

本節(jié)的Demo:https://github.com/BigBigPo/UIScrollViewScaleDemo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請(qǐng)通過(guò)簡(jiǎn)信或評(píng)論聯(lián)系作者。

相關(guān)閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,438評(píng)論 4 61
  • 昨天,我去參加了我外公的兄弟的外孫女的婚禮。 從小到大,和這個(gè)遠(yuǎn)房表妹見(jiàn)面的次數(shù),十根手指頭都數(shù)得過(guò)來(lái)。 印象中這...
    尼莫魚閱讀 1,492評(píng)論 4 4
  • kvc:鍵 - 值編碼是一種間接訪問(wèn)對(duì)象的屬性使用字符串來(lái)標(biāo)識(shí)屬性,而不是通過(guò)調(diào)用存取方法,直接或通過(guò)實(shí)例變量訪問(wèn)...
    xing_zhu閱讀 234評(píng)論 0 0
  • 五點(diǎn)半醒,拿起手機(jī)看看微信和qq,看著朋友們都幸福,也想想今天工作安排,年齡增長(zhǎng),心反而更潔凈了,因?yàn)橹?..
    探路者tanluzhe閱讀 268評(píng)論 2 3
  • 洛陽(yáng)深閨,倚欄睡 幾夜流蘇垂 蝶舞繞屏飛 點(diǎn)不清,相思淚 又憶君曾把我手 共煮青梅; 滿樓春碎,月初胐 一盞孤燈陪...
    會(huì)說(shuō)話的啞巴_閱讀 263評(píng)論 0 0

友情鏈接更多精彩內(nèi)容