无限轮播的实现思路
轮播图最核心的部分是如何实现无限轮播。我的实现方式是:
在UIScrollView
上添加三个UIImageView
,要想达到无限轮播的效果,就要在任何停止滚动的时候(只展示一张完整图片的时候),scrollView.contentOffset.x
都应该等于轮播图宽度,即处于中间图片的位置,这样就能保证处在每一张图的位置时,左右都可以滑动。
代码的实现是,在 scrollViewDidScroll
代理方法中,判断当scrollView
滚动到最左或者最右的极限位置时,立即将scrollView.contentOffset.x
设置为轮播图宽度,即恢复到中间位置;
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let contentOffsetX = scrollView.contentOffset.x
// 设置图片信息(滑到最左边或者最右边的时候,立即回正,同时改变图片,不会造成视觉上的误差)
if contentOffsetX == 2 * scrollView.frame.width {// 左滑
currentIndex = getActualCurrentPage(calculatedPage: currentIndex + 1)
resetImageView()
} else if (contentOffsetX == 0) {// 右滑
currentIndex = getActualCurrentPage(calculatedPage: currentIndex - 1)
resetImageView()
}
}
同时,重新设置三张图的图片。这样在视觉效果上,就达到了无限滚动的效果。
fileprivate func resetImageView(){
let preIndex: NSInteger = getActualCurrentPage(calculatedPage: currentIndex - 1)
let nextIndex: NSInteger = getActualCurrentPage(calculatedPage: currentIndex + 1)
if imageUrls.count == 0 {
return
}
imageArray[0].sd_setImage(with: URL(string: imageUrls[preIndex]), placeholderImage: nil, options: [.refreshCached, .retryFailed])
imageArray[1].sd_setImage(with: URL(string: imageUrls[currentIndex]), placeholderImage: nil, options: [.refreshCached, .retryFailed])
imageArray[2].sd_setImage(with: URL(string: imageUrls[nextIndex]), placeholderImage: nil, options: [.refreshCached, .retryFailed])
scrollNode.contentOffset = CGPoint(x: self.frame.width, y: 0)// 这里不可以使用setcontentOffset:animate的方法,否则滑动过快会出现bug
}
/// 根据下一页的计算值获取实际下一页的值
///
/// - Parameter page: 通过+1或-1得到的下一页的值
/// - Returns: 实际值
fileprivate func getActualCurrentPage(calculatedPage page: NSInteger) -> NSInteger {
if page == imageUrls.count {
return 0
} else if page == -1 {
return imageUrls.count - 1
} else {
return page
}
}
自定义UIPageControl
类似于优酷的轮播图中的UIPageControl
,实现起来比较简单,主要是通过改变原点的位置和长度,具体请参考Demo的代码。