新建BannerView.swift
//
// BannerView.swift
// geekTime
//
// Created by liuan on 2020/9/15.
// Copyright © 2020 liuan. All rights reserved.
//
import Foundation
import UIKit
import SnapKit
protocol BannerViewDataSource: AnyObject {
func numberOfBanner(_ bannerView: BannerView)-> Int
func viewForBanner(_ bannerView:BannerView,index:Int,convertView: UIView?)-> UIView
}
protocol BannerViewDelegate: AnyObject {
func didSelectBanner(_ bannerView:BannerView,index : Int)
}
class BannerView: UIView,UICollectionViewDataSource,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout{
var collectionView:UICollectionView
var flowLayout: UICollectionViewFlowLayout
var pageControl: UIPageControl
weak var dataSource: BannerViewDataSource!{
didSet{
pageControl.numberOfPages = self.dataSource.numberOfBanner(self)
collectionView.reloadData()
if isInfinite{
DispatchQueue.main.async {
self.collectionView.setContentOffset(CGPoint(x: self.collectionView.frame.width, y: 0), animated: false)
}
}
}
}
weak var delegate: BannerViewDelegate?
var autoScrollInterval: Float = 0 {
didSet{
if self.autoScrollInterval > 0 {
self.statrAutoScroll()
}else {
self.stopAutoSctoll()
}
}
}
var isInfinite:Bool = true
var timer:Timer?
static var cellId = "BannerViewCellId"
static var convertViewTag = 1001
override init(frame: CGRect) {
flowLayout = UICollectionViewFlowLayout()
flowLayout.headerReferenceSize = .zero
flowLayout.footerReferenceSize = .zero
flowLayout.minimumLineSpacing = 0
flowLayout.minimumInteritemSpacing = 0
flowLayout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
flowLayout.scrollDirection = .horizontal
collectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: frame.width, height: frame.height),collectionViewLayout: flowLayout)
pageControl = UIPageControl()
super.init(frame:frame)
self.setupViews()
}
func setupViews(){
collectionView.backgroundColor = .white
collectionView.isPagingEnabled = true
collectionView.showsHorizontalScrollIndicator = false
collectionView.contentInsetAdjustmentBehavior = .never
collectionView.register(UICollectionViewCell.self,forCellWithReuseIdentifier: BannerView.cellId)
collectionView.dataSource = self
collectionView.delegate = self
self.addSubview(collectionView)
self.addSubview(pageControl)
collectionView.snp.makeConstraints({(make) in
make.edges.equalToSuperview()
})
pageControl.snp.makeConstraints({(make) in
make.centerX.equalToSuperview()
make.bottom.equalToSuperview().offset(-15)
})
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
let pageNumer = dataSource.numberOfBanner(self)
if isInfinite{
if pageNumer == 1 {
return 1
}else {
return pageNumer + 2
}
}else{
return pageNumer
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: BannerView.cellId, for: indexPath)
var index = indexPath.row
if isInfinite {
let pageNumer = dataSource.numberOfBanner(self)
if pageNumer>1{
if indexPath.row == 0 {
index = pageNumer - 1
}else if indexPath.row == pageNumer+1 {
index = 0
}else {
index = indexPath.row - 1
}
}
}
if let view = cell.contentView.viewWithTag(BannerView.convertViewTag){
let _ = dataSource.viewForBanner(self, index: index, convertView: view)
}else {
let newView = dataSource.viewForBanner(self, index: index, convertView: nil)
newView.tag = BannerView.convertViewTag
cell.contentView.addSubview(newView)
newView.snp.makeConstraints({make in
make.edges.equalToSuperview()
})
}
return cell
}
//自动轮播
func statrAutoScroll(){
guard autoScrollInterval > 0 && timer == nil else{
return
}
timer = Timer.scheduledTimer(timeInterval: TimeInterval(autoScrollInterval), target: self, selector: #selector(flipNext), userInfo: nil, repeats: true)
RunLoop.current.add(timer!, forMode: .common)
}
@objc func flipNext(){
guard let _ = superview,let _ = window else {
return
}
let totalPagerNumber = dataSource.numberOfBanner(self)
guard totalPagerNumber>1 else {
return
}
let currentPagerNumber = Int(round(collectionView.contentOffset.x / collectionView.frame.width))
if isInfinite {
let nextPagerNumber = currentPagerNumber + 1
collectionView.setContentOffset(CGPoint(x: collectionView.frame.width * CGFloat(nextPagerNumber), y: 0), animated: true)
if nextPagerNumber >= totalPagerNumber+1 {
pageControl.currentPage = 0
}else{
pageControl.currentPage = nextPagerNumber - 1
}
}else{
var nextPageNumber = currentPagerNumber + 1
if nextPageNumber >= totalPagerNumber {
nextPageNumber = 0
}
collectionView.setContentOffset(CGPoint(x: collectionView.frame.width * CGFloat(nextPageNumber), y: 0), animated: true)
pageControl.currentPage = nextPageNumber
}
}
func stopAutoSctoll(){
if let t = timer{
t.invalidate()
timer = nil
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return self.bounds.size
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
let total = dataSource.numberOfBanner(self)
let current = Int(round(collectionView.contentOffset.x / collectionView.frame.width))
if current >= total + 1 {
collectionView.setContentOffset(CGPoint(x: collectionView.frame.width, y: 0), animated: false)
}
}
}
创造假的数据适配器
//
// FakeData.swift
// geekTime
//
// Created by liuan on 2020/9/14.
// Copyright © 2020 liuan. All rights reserved.
//
import Foundation
class FakeData {
private static var bannerList = [String]()
private static var products = [Product]()
private static var deals=[Deal]()
static func createBanners()->[String]{
if bannerList.count == 0 {
bannerList = [
"https://via.placeholder.com/450x150",
"https://via.placeholder.com/450x151",
"https://via.placeholder.com/450x152"
]
}
return bannerList
}
}
在用到控件中加载
//
// HomeViewController.swift
// geekTime
//
// Created by liuan on 2020/9/14.
// Copyright © 2020 liuan. All rights reserved.
//
import UIKit
import Kingfisher
class HomeViewController: BaseViewController,BannerViewDataSource {
func numberOfBanner(_ bannerView: BannerView) -> Int {
return FakeData.createBanners().count
}
func viewForBanner(_ bannerView: BannerView, index: Int, convertView: UIView?) -> UIView {
if let view = convertView as? UIImageView{
view.kf.setImage(with: URL(string: FakeData.createBanners()[index]))
return view
}else {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
imageView.kf.setImage(with: URL(string: FakeData.createBanners()[index]))
return imageView
}
}
override func viewDidLoad() {
super.viewDidLoad()
let bannerView = BannerView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 176))
bannerView.autoScrollInterval = 2
bannerView.isInfinite = true
bannerView.dataSource = self
view.addSubview(bannerView)
}
}
完成
底部的UITabbar 可以参考上篇文章
已知问题:手动拖动没有完善。点击事件没有加。