圖片(視圖)輪播是許多 App 中常見界面效果零蓉,打開簡書主頁,我們也能看到類似的效果。對于其實現(xiàn)筐骇,網(wǎng)上也有好多方法,最簡單的方法無非是將所有的 view 添加到一個 UIScrollView
中江滨,然后設(shè)置其 paging 屬性铛纬。這個方法雖然簡單,但是無法實現(xiàn)循環(huán)效果唬滑,而且頁碼控件也需要我們計算一些數(shù)值來設(shè)置告唆,況且,當(dāng) view 多了時無法做到循環(huán)利用晶密,造成同屏 view 過多導(dǎo)致卡頓擒悬。
My First Approach
我嘗試自定義一個 UIView
,然后使用 DataSource 分離稻艰, 實現(xiàn)類似 UITableView
的視圖復(fù)用懂牧,然后添加 UIScrollView
,設(shè)置 delegate尊勿,實現(xiàn)其 func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>)
代理方法僧凤。在這個方法中我們可以得到手指松開后視圖將會滾動到的位置,我們還可以通過指針去修改視圖將會滾動到的位置元扔,這樣我們只需要將 scroll view 的 contentSize.width
設(shè)置為 superview 長度的三倍躯保,從而留出左右滑動的空間,通過上述代理方法澎语,使 contentOffset
始終位于中心位置途事,然后動態(tài)調(diào)整 subview 的位置,從而實現(xiàn)期望效果擅羞。
下面是代理方法的代碼:
func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
let targetOffsetIndex = self.calcIndexWithContentOffset(targetContentOffset.memory)
if targetOffsetIndex == -1 {
scrollView.contentOffset.x += scrollView.frame.width
self._currentPageIndex = self.clampCellIndex(self._currentPageIndex - 1)
} else if targetOffsetIndex == 1 {
scrollView.contentOffset.x -= scrollView.frame.width
self._currentPageIndex = self.clampCellIndex(self._currentPageIndex + 1)
}
targetContentOffset.memory = CGPoint(x: self.frame.width, y: 0)
if targetOffsetIndex != 0 {
self.layoutCarouselCells()
}
}
這段代碼可以說是 "perfectly works"盯孙,但是實現(xiàn)起來比較復(fù)雜。
實際上祟滴,iOS 系統(tǒng)已經(jīng)給我們提供了一個實現(xiàn)輪播的現(xiàn)成方式振惰。
The Final Destination
答案就是 UIPageViewController
~
效果:
實現(xiàn)方法很簡單,先貼代碼垄懂,再解釋:
由于 UIPageViewController
為我們實現(xiàn)好了滾動的所有邏輯骑晶,所有我們直接實例化之痛垛,配置一下 dataSource 和 delegate(實現(xiàn)頁碼)。當(dāng)然我還可以設(shè)置頁邊距桶蛔。接下來我們將其作為一個 child view controller 添加到現(xiàn)有的 view controller 中匙头,固定模式的五段代碼。然后設(shè)置初始頁面仔雷,并添加一個 page control蹂析。
下面來實現(xiàn) DataSource:
非常好的一點是,UIPageController
是用當(dāng)前視圖來推導(dǎo)上一個或下一個視圖的碟婆,所以我們很輕松就能實現(xiàn)循環(huán)輪播电抚。例如現(xiàn)在的視圖是最后一個,然后 "...after..." 方法中我們就可以返回第一個視圖竖共,實現(xiàn)循環(huán)蝙叛。
Delegate 也就更簡單了:
拿到當(dāng)前視圖,直接找到其 index 設(shè)置給 page control 即可公给。
這里要注意的是
UIPageController
需要的是UIViewController
借帘,而不是UIView
。
以上淌铐。