利用 UIScrollView 有多種方法實現(xiàn)分頁怠蹂,但是各自的效果和用途不盡相同善延,其中方法 2 和方法 3 的區(qū)別也正是一些同類 App 在模仿 Glow 的首頁 Bubble 翻轉效果時跟 Glow 體驗上的的差距所在(但愿他們不會看到本文并且調整他們的實現(xiàn)方式)。本例通過三種方法實現(xiàn)相似的一個場景城侧,你可以通過安裝到手機上來感受三種實現(xiàn)方式的不同用戶體驗易遣。
1.pagingEnabled
這是系統(tǒng)提供的分頁方式,最簡單嫌佑,但是有一些局限性:
<li>只能以 frame size 為單位翻頁豆茫,減速動畫阻尼大,減速過程不超過一頁
<li>需要一些 hacking 實現(xiàn) bleeding 和 padding(即頁與頁之間有 padding歧强,在當前頁可以看到前后頁的部分內容)
有簡單實現(xiàn) bleeding 和 padding 效果的代碼,主要的思路是:
<li>讓 scroll view 的寬度為 page 寬度 + padding澜薄,并且設置 clipsToBounds 為 NO
<li>這樣雖然能看到前后頁的內容,但是無法響應 touch摊册,所以需要另一個覆蓋期望的可觸摸區(qū)域的 view 來實現(xiàn)類似 touch bridging 的功能
適用場景:上述局限性同時也是這種實現(xiàn)方式的優(yōu)點肤京,比如一般 App 的引導頁(教程),Calendar 里的月視圖,都可以用這種方法實現(xiàn)忘分。
2.Snap
這種方法就是在 didEndDragging 且無減速動畫棋枕,或在減速動畫完成時,snap 到一個整數(shù)頁妒峦。核心算法是通過當前 contentOffset 計算最近的整數(shù)頁及其對應的 contentOffset重斑,通過動畫 snap 到該頁。這個方法實現(xiàn)的效果都有個通病肯骇,就是最后的 snap 會在 decelerate 結束以后才發(fā)生窥浪,總感覺很突兀。
修改 targetContentOffset
通過修改 scrollViewWillEndDragging: withVelocity: targetContentOffset: 方法中的 targetContentOffset 直接修改目標 offset 為整數(shù)頁位置笛丙。其中核心代碼:
func nearestTargetOffsetForOffset(offset:CGPoint)->CGPoint{
var pageSize:CGFloat = BUBBLE_DIAMETER2+BUBBLE_PADDING2
var page:Int = Int(roundf(Float(offset.x) / Float(pageSize)))
var targetX:CGFloat = CGFloat(pageSize) * CGFloat(page)
return CGPointMake(targetX, offset.y)
}
func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
var targetOffset:CGPoint = self.nearestTargetOffsetForOffset(targetContentOffset.memory)
targetContentOffset.memory.x = targetOffset.x
targetContentOffset.memory.y = targetOffset.y
}
適用場景:方法 2 和 方法 3 的原理近似漾脂,效果也相近,適用場景也基本相同胚鸯,但方法 3 的體驗會好很多骨稿,snap 到整數(shù)頁的過程很自然,或者說用戶完全感知不到 snap 過程的存在姜钳。這兩種方法的減速過程流暢坦冠,適用于一屏有多頁,但需要按整數(shù)頁滑動的場景哥桥;也適用于如圖表中自動 snap 到整數(shù)天的場景辙浑;還適用于每頁大小不同的情況下 snap 到整數(shù)頁的場景(不做舉例,自行發(fā)揮拟糕,其實只需要修改計算目標 offset 的方法)例衍。