簡要

接下來要做上方Banner
原APP上方有個輪播裝置
負責打廣告或是顯示優惠

在APP也是時常出現
呈現方式很多種都可以做出來
可以使用collectionView
或是scrollView+pageControl
但我之前在OC寫的都是用scrollView+pageControl

之前OC 實作Banner

效果也有左右滑動
點擊事件以及單獨新建一個class去呼叫
但是現在Swfit功力太淺
先做出來再說

正題

初始設定

因為我們要使用ScrollView
所以先把UIScrollViewDelegate設定好
currentIndex 紀錄目前的index
imageArray 圖片名稱儲存在這裡
timer 幾秒切換下一張
leftImageView, rightImageView, currentImageView 宣告三個是為了 你在滑動前後需要預載圖片 才不會滑動後還要等待用意

class ViewController: UIViewController,UIScrollViewDelegate {
    let width = UIScreen.main.bounds.size.width
    var currentIndex : NSInteger = 0
    var leftImageView = UIImageView()
    var rightImageView = UIImageView()
    var currentImageView = UIImageView()
    var imageArray = [String]()
    var timer = Timer()

懶加載

scrollView

這裡將scrollView 範圍寬度已手機寬度3倍設定好
並且將剛剛三張圖片
平均分布在scrollView的三等份裡面

// 上方banner
lazy var scrollView: UIScrollView = {
    let scrollView = UIScrollView()
    scrollView.contentSize = CGSize(width: width * 3, height: 200)
    scrollView.contentOffset = CGPoint(x: width, y: 50)
    scrollView.isPagingEnabled = true
    scrollView.frame = CGRect(x: 0, y: 50, width: width, height: 200)
    rightImageView.frame = CGRect(x: width * 2, y: 50, width: width, height: 200)
    currentImageView.frame = CGRect(x: width * 1, y: 50, width: width, height: 200)
    leftImageView.frame = CGRect(x: width * 0, y: 50, width: width, height: 200)
    scrollView.addSubview(rightImageView)
    scrollView.addSubview(currentImageView)
    scrollView.addSubview(leftImageView)
    scrollView.delegate = self
    return scrollView
}()

pageControl

pageControl 負責頁數
以及下方小圓點
顏色部分
currentPageIndicatorTintColor 選取時
pageIndicatorTintColor 為選取時

位置部分設置在
scrollViewmaxY
並且扣掉自己的高度

// 下方小圓點
lazy var pageControl: UIPageControl = {
    let pageControl = UIPageControl()
    pageControl.frame = CGRect(x: 0, y: scrollView.frame.maxY-20, width: width, height: 20)
    pageControl.backgroundColor = UIColor.clear
    //小圓點選取時顏色
    pageControl.currentPageIndicatorTintColor = UIColor.init(displayP3Red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
    //小圓點未選取顏色
    pageControl.pageIndicatorTintColor = UIColor.init(displayP3Red: 1.0, green: 1.0, blue: 1.0, alpha: 0.2)
    pageControl.numberOfPages = imageArray.count
    pageControl.currentPage = 0
    return pageControl
}()

更新圖片

每次pageView 變動時
更新三個imageView
並且將scrollView setContentOffset 移動回來中間
因為剛剛已經移動過了

/**
 * 更新圖片
 */
func reloadImage(){
    var leftIndex = 0
    var rightIndex = 0
    currentIndex = currentIndex % imageArray.count
    scrollView.setContentOffset(CGPoint(x: width, y: 50), animated: false)
    pageControl.currentPage = (currentIndex - 1 + imageArray.count) % imageArray.count //防止越界
    leftIndex = (currentIndex - 1 + imageArray.count) % imageArray.count //防止越界
    rightIndex = (currentIndex + 1) % imageArray.count
    rightImageView.image = UIImage(named: imageArray[rightIndex])
    currentImageView.image = UIImage(named: imageArray[currentIndex])
    leftImageView.image = UIImage(named: imageArray[leftIndex])

}

Timer

這裡就設定每2秒更新一次
並且讓index + 1

/**
 * 更新timer
 */
func setupTimer() {
    timer = Timer.scheduledTimer(timeInterval: 2,target:self,selector:#selector(timeChanged),userInfo:nil,repeats:true)
    RunLoop.current.add(timer, forMode: RunLoop.Mode.common)
}

/**
 * time 事件
 */
@objc func timeChanged(){
    currentIndex = currentIndex + 1
    //更新圖片+scrollView
    reloadImage()
}

scrollView 監聽事件

因為剛剛有設置 scrollViewdelegate
所以可以監聽一些事件
scrollViewWillBeginDragging 滑動開始時
scrollViewDidEndDecelerating 滑動結束時

這邊開始時需要停止timer
因為滑動的時候就不用自動輪播
不然會衝突到 使用者體驗不好

停止判斷位置
是否偏向於某一邊
如果是的話+1 或是 -1
往前或是往後

/**
 * scrollView 滑動開始監聽
 */
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
    timer.invalidate()
}

/**
 * scrollView 滑動坄停止監聽
 */
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {

    //向右拖動
    if scrollView.contentOffset.x > width {
        currentIndex = (currentIndex + 1) % imageArray.count
    }

    //向左拖動
    if scrollView.contentOffset.x < width{
        currentIndex = (currentIndex - 1 + imageArray.count) % imageArray.count
    }

    //更新小圓點當前位置
    pageControl.currentPage = (currentIndex - 1 + imageArray.count) % imageArray.count
    reloadImage()
    setupTimer()
}

viewDidLoad

最後全部設置好後
將圖片塞進 imageArray
並且 addSubview
打開 timer
圖片部分我先截圖Uber eat
然後修完圖了 可以到Github看

override func viewDidLoad() {
    super.viewDidLoad()
    imageArray = ["banner1","banner2","banner3","banner4","banner5","banner6","banner7"]
    self.view.addSubview(self.scrollView)
    self.view.addSubview(self.pageControl)
    reloadImage()
    setupTimer()
}

Demo

看起來還不錯
只差塞回去collectionView
以及換頁特效

Github連結:
https://github.com/Bgihe/BannerTest


Categorized in: