Swift: Images carousel with a Collection View and Timer Function

Jru
12 min readMay 25, 2023

--

[Auto-Scrolling]自動輪播

Go to see → Manual-scrolling手動滑動輪播效果

介紹

使用元件:collection view, image view, page control

使用函數: scheduledTimer(timeInterval:target:selector:, userInfo: repeats:), selectItem(at:animated:scrollPosition:)

輪播效果製作

一、向右輪播到最後一張圖片時,會往左拉,回到第一張。

最後一筆山景圖硬拉回第一筆樹林圖

import UIKit

class ViewController: UIViewController,UICollectionViewDelegate,UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {

@IBOutlet weak var bannerCollectionView: UICollectionView!

@IBOutlet weak var pageControl: UIPageControl!

var time:Timer?
//紀錄目前banner播放到第幾個cell
var imageIndex = 0
var banners = ["1","2","3"]

override func viewDidLoad() {
super.viewDidLoad()
bannerCollectionView.delegate = self
bannerCollectionView.dataSource = self

configureCellSize()

//每兩秒輪播下一個圖片
time = Timer.scheduledTimer(timeInterval: 2, target: self, selector: #selector(changeBanner), userInfo: nil, repeats: true)

}

func configureCellSize(){
if let layout = bannerCollectionView.collectionViewLayout as? UICollectionViewFlowLayout{
layout.scrollDirection = .horizontal

}
}

@objc func changeBanner(){

//imageIndex加一轉動圖片到下一張
imageIndex += 1
if imageIndex == banners.count{
imageIndex = 0
}
//用imageIndex去產生一個indexPath
let indexPath = IndexPath(item: imageIndex, section: 0)
//讓collectionView去選indexPath
bannerCollectionView.selectItem(at: indexPath, animated: true, scrollPosition: .centeredHorizontally)

}


//MARK: - Collection view
func numberOfSections(in collectionView: UICollectionView) -> Int {
1
}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
banners.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "BannerCollectionViewCell", for: indexPath) as! BannerCollectionViewCell
let indexPath = banners[indexPath.item]
cell.bannerImageView.contentMode = .scaleAspectFill
cell.bannerImageView.image = UIImage(named: "\(indexPath)")
return cell

}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return bannerCollectionView.bounds.size
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
}

二、向右輪播到最後一張圖時,繼續向右播第一張圖

  1. 先在儲存圖片的banners陣列裡多加最後一筆資料,新增的資料就是陣列裡的第一筆資料。
var banners = ["1","2","3","1"]

2. 用imageIndex記錄圖片為第幾張,並帶入selectItem 函式,將圖片顯示在cell所屬的位置上。

https://developer.apple.com/documentation/uikit/uicollectionview/1618057-selectitem

當跑到最後一張圖時,也就是剛剛自行新增的最後一筆資料,設定imageIndex0selectItem動畫效果設為 false,並重新呼叫自己changeBanner()

import UIKit

class ViewController: UIViewController,UICollectionViewDelegate,UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {

@IBOutlet weak var bannerCollectionView: UICollectionView!

@IBOutlet weak var pageControl: UIPageControl!

var time:Timer?
//紀錄目前banner播放到第幾個cell
var imageIndex = 0
var banners = ["1","2","3","1"]

override func viewDidLoad() {
super.viewDidLoad()
bannerCollectionView.delegate = self
bannerCollectionView.dataSource = self

configureCellSize()

pageControl.numberOfPages = banners.count - 1
pageControl.backgroundStyle = .prominent

//每兩秒輪播下一個圖片
time = Timer.scheduledTimer(timeInterval: 2, target: self, selector: #selector(changeBanner), userInfo: nil, repeats: true)

}

func configureCellSize(){
if let layout = bannerCollectionView.collectionViewLayout as? UICollectionViewFlowLayout{
layout.scrollDirection = .horizontal

}
}

@objc func changeBanner(){

var indexPath:IndexPath

//imageIndex加一轉動圖片到下一張
imageIndex += 1

//在banner陣列裡再加入第一筆圖片名稱,當不是最後一筆資料時
if imageIndex < banners.count{

//用imageIndex去產生一個indexPath
indexPath = IndexPath(item: imageIndex, section: 0)
//讓collectionView去選indexPath
bannerCollectionView.selectItem(at: indexPath, animated: true, scrollPosition: .centeredHorizontally)

pageControl.currentPage = imageIndex
//當imageIndex是banner陣列裡的最後一筆資料時,將page control設為0,是第一張圖也是第一個page control圈圈
if imageIndex == banners.count - 1{
pageControl.currentPage = 0
}

}
else
{
//當banner數量等於banner陣列的最後一筆資料,回到第一筆資料,page control也回到第一個圈
imageIndex = 0
pageControl.currentPage = 0
indexPath = IndexPath(item: imageIndex, section: 0)
//不要動畫先回到第一張圖
bannerCollectionView.selectItem(at: indexPath, animated: false, scrollPosition: .centeredHorizontally)

//再重新輪播
changeBanner()
}

}


//MARK: - Collection view
func numberOfSections(in collectionView: UICollectionView) -> Int {
1
}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
banners.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "BannerCollectionViewCell", for: indexPath) as! BannerCollectionViewCell
let indexPath = banners[indexPath.item]
cell.bannerImageView.contentMode = .scaleAspectFill
cell.bannerImageView.image = UIImage(named: "\(indexPath)")
return cell

}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return bannerCollectionView.bounds.size
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}

}

--

--