Swift 轮播图

作者: 单抽律化娜 | 来源:发表于2019-12-10 11:04 被阅读0次
/// 代理方法
@objc protocol CycleScrollViewDelegate: NSObjectProtocol {
    
    /// 有多少图片
    func cycleImageCount() -> Int
    
    /// 图片和当前下标
    func cycleImageView(_ imageView: UIImageView, index: Int)
    
    /// 点击图片下标
    @objc optional func cycleImageViewClick(_ index: Int)
}

/// 轮播图
class CycleScrollView: UIView, UIScrollViewDelegate {

    /// 图片数组
    private var imageViews = [UIImageView(), UIImageView(), UIImageView()]
    
    /// 滚动页面
    private var scrollView: UIScrollView!
    
    /// 图片个数
    private var imageCount: Int = 0
    
    /// 计时器
    private var timer: Timer? = nil
    
    /// 存储下标
    private var index: Int = 0
    
    /// 当前显示下标
    public var currentIndex: Int {
        get {
            return index
        }
        set {
            index = min(newValue, imageCount)
            updateImage()
        }
    }
    
    /// 是否滚动
    public var rollingEnable: Bool = false {
        willSet {
            newValue ? startTimer() : stopTimer()
        }
    }
    
    /// 滚动间隔
    public var duration: TimeInterval = 3.0
    
    /// 代理
    public weak var delegate: CycleScrollViewDelegate? {
        didSet {
            if let delegate = delegate {
                imageCount = delegate.cycleImageCount()
                scrollView.isScrollEnabled = imageCount > 1
            }
        }
    }
    
    /// 初始化
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        scrollView = UIScrollView()
        scrollView.isPagingEnabled = true
        scrollView.bounces = false 
        scrollView.showsHorizontalScrollIndicator = false
        scrollView.showsVerticalScrollIndicator = false
        scrollView.delegate = self
        addSubview(scrollView)
        
        for item in imageViews {
            scrollView.addSubview(item)
        }
        
        addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(tap(_:))))
    }
    
    /// 设置
    override func layoutSubviews() {
        super.layoutSubviews()
        if (imageViews[0].frame == .zero) {
            let width = frame.width, height = frame.height
            scrollView.frame = CGRect(x: 0, y: 0, width: width, height: height)
            scrollView.contentSize = CGSize(width: width * 3, height: height)
            for (i, obj) in imageViews.enumerated() {
                obj.frame = CGRect(x: CGFloat(i) * width, y: 0, width: width, height: height)
            }
            currentIndex = index
        }
    }
    
    /// 点击
    @objc private func tap(_ gesture: UITapGestureRecognizer) {
        delegate?.cycleImageViewClick?(currentIndex)
    }
    
    /// 更新图片
    private func updateImage() {
        if (imageCount < 2) {
            delegate?.cycleImageView(imageViews[1], index: index)
        } else {
            for (i, index) in [getLast(currentIndex), currentIndex, getNext(currentIndex)].enumerated() {
                delegate?.cycleImageView(imageViews[i], index: index)
            }
        }
        scrollView.contentOffset.x = frame.width
    }
    
    /// 开始计时器
    private func startTimer() {
        if (imageCount < 2) {
            return
        }
        timer = Timer.scheduledTimer(timeInterval: duration, target: self, selector: #selector(rolling), userInfo: nil, repeats: true)
        RunLoop.current.add(timer!, forMode: .commonModes)
    }
    
    /// 暂停计时器
    private func stopTimer() {
        if (imageCount < 2) {
            return
        }
        timer?.invalidate()
        timer = nil
    }
    
    /// 计时方法
    @objc private func rolling() {
        scrollView.setContentOffset(CGPoint(x: frame.width * 2, y: 0), animated: true)
    }
    
    /// scrollView开始拖拽
    func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
        if rollingEnable {
            stopTimer()
        }
    }
    
    /// scrollView结束拖拽
    func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
        if rollingEnable {
            startTimer()
        }
    }
    
    /// scrollView滚动
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        if scrollView.contentOffset.x <= 0 {
            currentIndex = getLast(currentIndex)
        } else if scrollView.contentOffset.x >= 2 * scrollView.frame.width {
            currentIndex = getNext(currentIndex)
        }
        /// 修复automaticallyAdjustsScrollViewInsets问题
        if (scrollView.contentOffset.y != 0) {
            scrollView.contentOffset.y = 0
        }
    }
    
    /// 获取下一页页码
    private func getNext(_ current: Int) -> Int {
        let count = imageCount - 1
        if (count < 1) {
            return 0
        }
        return current + 1 > count ? 0 : current + 1
    }
    
    /// 获取上一页页码
    private func getLast(_ current: Int) -> Int {
        let count = imageCount - 1
        if (count < 1) {
            return 0
        }
        return current - 1 < 0 ? count : current - 1
    }
    
    /// 如果有计时器存在,必须停止计时器才能释放
    override func removeFromSuperview() {
        super.removeFromSuperview()
        stopTimer()
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}
import UIKit

class ViewController: UIViewController, CycleScrollViewDelegate {
    
    var images: [String] = ["image1.jpeg", "image2.jpeg", "image3.jpeg", "image4.jpeg"]
    
    var cycleView: CycleScrollView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        cycleView = CycleScrollView(frame: CGRect.init(x: 0, y: 0, width: view.frame.width, height: 200))
        cycleView.delegate = self 
        cycleView.rollingEnable = true
        view.addSubview(cycleView)
    }

    /// 设置图片数量
    func cycleImageCount() -> Int {
        return images.count
    }
    
    /// 设置显示的图片
    func cycleImageView(_ imageView: UIImageView, index: Int) {
        imageView.image = UIImage(named: images[index])
    }
    
    /// 点击图片,返回下标
    func cycleImageViewClick(_ index: Int) {
        print(index)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

相关文章

网友评论

    本文标题:Swift 轮播图

    本文链接:https://www.haomeiwen.com/subject/hrgwgctx.html