swift 轮播图

新建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 可以参考上篇文章

已知问题:手动拖动没有完善。点击事件没有加。

 

你可能感兴趣的:(#,swift)