iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 28
1

精彩到我看到忘記發文了嗚嗚嗚被工作室通緝QQ


scroll view是個可允許使用者對其內容捲動或縮放的view。看到捲動相信大家就不難想像,他94先前把我折騰一番的UITableView和UITextView的大家長。

scroll view的核心價值就是會偵測手指的運動並依此調整content view的原點,藉由與scroll view原點的偏移量決定顯示的內容。
而scroll view本身除了水平和垂直的scroll bar以外,並不會對內容本身進行處理,而是管理了內容的哪個區塊要加進subview裡。當使用者捲動畫面時,將內容從subview中加入/移除。

scroll view會儲存視圖大小,以確定何處要停止捲動。
在default的情況下如果你爆滑一波,讓scroll view更新的原點超過了視圖內容的位置,則scroll view會出現一個反彈的動畫將原點彈回視圖內。

但是當你不是拖拉scroll bar而是手指直接在螢幕上滑動時,系統是怎麼知道你要點擊還是捲動的?說不定有人手抖得很厲害,只是要點擊按鈕而已螢幕卻一直小幅度抖動,不是很傷腦筋嗎?
所以scroll view有一個機制,去追蹤使用者到底是想要捲動還是點擊。
當使用者觸控螢幕之後,scroll view會先攔截touchDown的UIEvent並且啟動一個nonrepeating timer,timer失效後scroll view會去偵測點擊位置是否有顯著的移動。如果沒有顯著的移動,scroll view就會發出tracking event給被點擊的物件;如果有顯著的移動,scroll view就會自己開始滾爆。

而繼承的子類別可以覆寫touchesShouldBegin(_:with:in:)、isPagingEnabled和touchesShouldCancel(in:)以影響滑動手勢。

scroll view除了滾動外,也處理了內容的縮放與平移。
當使用者做出放大或縮小的手勢時,scroll view會調整內文的比例與原點的偏移量,並在手勢結束之後更新subview。
手勢進行時,scroll view不會發送任何信息給subview。

Delegate

UIScrollViewDelegate接收了scroll view發送的消息,呼叫function並影響滾動、縮放,還有滾動時的減速及動畫等動作。

Scroll

當使用者捲動畫面時,scroll view發送訊息給delegate的順序如下:

  • 使用者做出捲動畫面的手勢時,畫面在實際開始捲動前會先發送訊息給delegate並呼叫scrollViewWillBeginDragging(_:),告訴scroll view捲動時機。
  • 捲動時會持續發出訊息給並呼叫scrollViewDidScroll(_:),藉此取得原點偏移量以繪製scroll view內容。
  • 使用者結束捲動畫面的手勢時會發送當下的速度及期望的位移距離給delegate,並呼叫scrollViewWillEndDragging(_:withVelocity:targetContentOffset:)。
  • 使用者結束捲動畫面的手勢,scroll view發出touchUp的UIEvent之後會發送訊息並呼叫scrollViewDidEndDragging(_:willDecelerate:)。
    此時如果isDecelerating為true,則willDecelerate收到的訊息為true,也就是scroll view會慢慢減速到停止,如果收到false則會在touchUp發送的的當下瞬間停止。
    而isDecelerating為true的話,則會在以下時機再發送訊息給delegate:
    • 在收到touchUp event的同時發送訊息並呼叫scrollViewWillBeginDecelerating(_:)。
    • 在減速到速度為0,畫面完全停止後發送訊息並呼叫scrollViewDidEndDecelerating(_:)。

scroll view delegate另外還有一個function是scrollViewShouldScrollToTop(:),會回傳一個布林值。
如果回傳值為true,代表允許使用者利用點擊狀態列來捲動到視圖的最頂端,不額外定義則預設值為true。
而當視圖捲到最頂端後,scroll view會發送訊息給delegate並呼叫scrollViewDidScrollToTop(
:)。

Zoom In / Out

當使用者做出縮放及平移的手勢時,scroll view傳送訊息給UIScrollViewDelegate的順序如下

  • scroll view接收到動作後呼叫viewForZooming(in:)。
    viewForZooming(in:)會回傳一個UIView進入縮放的等待序列裡,如果不希望任何view被縮放的話,可以回傳nil。
  • UIView進入縮放的等待序列後,在開始縮放之前會先呼叫scrollViewWillBeginZooming(_:with:)。
    可以藉由這個function儲存UIView的狀態。
  • 在縮放的途中呼叫scrollViewDidZoom(_:),以告知scroll view狀態的改變。
  • 當縮放結束時會呼叫scrollViewDidEndZooming(:with:atScale:),並傳送當前的縮放比例給這個function。
    當前的縮放比例會介於scroll view的maximumZoomScale及minimumZoomScale兩個property之間,而這2個值不能相等。
    除此之外,反彈的動畫也會呼叫scrollViewDidEndZooming(
    :with:atScale:)。

上一篇
Day 27: 文字終結之時-UITextView
下一篇
Day 29: 來玩拉和服腰帶轉圈圈吧UIScrollView
系列文
Hey! UIKit, 做個朋友吧~30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0

還敢看 RNG 啊

我要留言

立即登入留言