🔍 OKay!進入正題 ⋯
如圖 自動輪播且置中的 collectionView, 原來要讓每次滑動cell時置中(左右需各顯示出cell頭/尾),要動這麼多手腳啊 🤯
一、 畫面組成:
在第一筆資料前依序加上最後兩筆資料,在最後一筆資料後方依序加入資料頭兩筆。形成
為什麼是前後各加入*兩筆*資料?
右滑,滑到第五筆,偷換到第二筆
左滑,滑到第一筆,偷換到第四筆
為避免滑到最後一筆在尚未完成偷切換時,顯示空空的下一位資料,因此需各加入兩筆,維持資料左右方都能有資料顯示。
有圖有真相 :
左圖為各加兩筆,右圖則為各加一筆
右圖在滑到資料4時(最後一筆),在偷換前會有一下子空空的gap…
( 圖為自動輪播狀態,若使用者使用手動,滑到最後一筆資料時,空空的gap會更為明顯 😶🌫️。 )
二、 自動輪播:
設置Timer
使自動輪播每兩秒update一次。
timer = Timer.scheduledTimer(
timeInterval: 2,
target: self,
selector: #selector(update),
userInfo: nil,
repeats: true
)
func update
每次更新往後滑一頁並置中。
使用 tuple currentIndex
紀錄當下頁數與 X point。
@objc func update() {
currentIndex.page += 1
let pageX = CGFloat(currentIndex.page)*(itemWidth+itemSpacing)
let screenWidth = UIScreen.main.bounds.width let centerX = (screenWidth-CGFloat(itemWidth))/2
currentIndex.x = pageX-centerX collectionView.setContentOffset(CGPoint(
x: page-centerX,
y: 0), animated: true
)
}
三、 輪播偷切換資料位置:
使用 UIScrollViewDelegate 設置切換位置
觸發條件:
1. 自動/手動皆觸發:
觸發scrollViewDidScroll
,在此紀錄滑動之到達頁數。
2. 手動觸發:scrollViewWillEndDragging
/scrollViewDidEndDecelerating
在此設置scrollView手動滑動後,停下之位置及記錄每次結束滑動時頁數。
func scrollViewDidScroll(_ scrollView: UIScrollView) {
setCurrentIndex(
scrollToPage: currentIndex.page,
x: scrollView.contentOffset.x
)
}
func setCurrentIndex(scrollToPage: Int, x: CGFloat) {
switch scrollToPage {
case 1:
guard x <= currentIndex.x else { return }
let lastTwoPageX = CGFloat(colors.count-3)*(itemWidth+itemSpacing)
let centerX = (width-CGFloat(itemWidth))/2 collectionView.setContentOffset(CGPoint(
x: lastTwoPageX-centerX,
y: 0), animated: false
) currentIndex.page = colors.count-3 case items.count - 2:
guard x >= currentIndex.x else { return }
let SecondPageX = 2*(itemWidth+itemSpacing)
let centerX = (width-CGFloat(itemWidth))/2 collectionView.setContentOffset(CGPoint(
x: SecondPageX-centerX,
y: 0), animated: false
) currentIndex.page = 2 default: // 其他頁數,只紀錄 index
currentIndex.page = scrollToPage
}
}
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) { let pageWidth = Float(itemWidth + itemSpacing)
let targetXContentOffset = Float(targetContentOffset.pointee.x)
let contentWidth = Float(collectionView!.contentSize.width)
var newPage = Float(currentIndex.page) if velocity.x == 0 {
newPage = floor((targetXContentOffset - pageWidth / 2) / pageWidth) + 1.0 } else {
///右滑頁數+1 / 左滑頁數-1
newPage = Float(velocity.x > 0 ? CGFloat(self.currentIndex.page + 1) : CGFloat(self.currentIndex.page - 1)) ///第一筆
if newPage < 0 {
newPage = 0
}
///最後一筆
if (Int(newPage) > colors.count - 2) {
newPage = ceil(contentWidth / pageWidth) - 1.0
}
} let pageX = CGFloat(newPage * pageWidth)
let centerX = (width-CGFloat(itemWidth))/2 ///校正 ContentOffset X 停下位置
let point = CGPoint(
x: pageX-centerX,
y: targetContentOffset.pointee.y
)
targetContentOffset.pointee = point currentIndex.x = point.x
currentIndex.page = Int(newPage)
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let pageWidth = Float(itemWidth + itemSpacing)
let scrollX = Float(scrollView.contentOffset.x)
let page = floor((scrollX - pageWidth / 2) / pageWidth) + 1.0
currentIndex.page = Int(page)
}
以上,打完收工 💻