1. 程式人生 > >iOS swift跑馬燈滾動可以點選

iOS swift跑馬燈滾動可以點選

跑馬燈,從右至左迴圈滾動顯示資訊,並且支援點選事件,使用swift4.0語法完成,更加簡介,通用性強,佈局部分全部使用snpkit

程式碼:

//
//  HXQMarqueeView.swift
//  hxquan-swift
//
//  Created by Tiny on 2018/11/20.
//  Copyright © 2018年 hxq. All rights reserved.
//  跑馬燈

import UIKit

class MarqueeModel: Equatable{
    
    var title: String?  //內容
    
    var img: String?  //頭像圖片 url
    
    var textColor: UIColor = .black   //字型預設顏色
    
    var font: UIFont = .systemFont(ofSize: 14)  //字型大小

    var imageHolder: UIImage = HXQDefaultUserImage    //頭像預設圖片
    
    static func == (lhs: MarqueeModel, rhs: MarqueeModel) -> Bool {
        return  lhs.title == rhs.title &&
                lhs.img == rhs.img &&
                lhs.textColor == rhs.textColor &&
                lhs.font == rhs.font &&
                lhs.imageHolder == rhs.imageHolder
    }
}

class MarqueeItem: UIView {
    
    private var textLb: UILabel!  //文字label
    
    private var imgView: UIImageView!  //圖片
    
    /// 重寫setModel並賦值
    fileprivate var model: MarqueeModel?{
        didSet{
            if model != nil {
                textLb.text = model?.title
                textLb.textColor = model!.textColor
                textLb.font = model!.font
                imgView.sd_setImage(with: URL(string: model!.img ?? ""), placeholderImage: model!.imageHolder)
            }
        }
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupUI()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    
    private func setupUI(){
        
        let gesture = UITapGestureRecognizer(target: self, action: #selector(itemClick))
        addGestureRecognizer(gesture)
        textLb = UILabel()
        textLb.font = UIFont.systemFont(ofSize: 14)
        textLb.textColor = UIColor.black
        addSubview(textLb)
        
        imgView = UIImageView()
        imgView.layer.masksToBounds = true
        addSubview(imgView)
        
        imgView.snp.makeConstraints { (make) in
            make.left.equalTo(5)
            make.top.equalTo(5)
            make.bottom.equalTo(-5)
            make.width.equalTo(imgView.snp.height)
        }
        
        textLb.snp.makeConstraints { (make) in
            make.centerY.equalToSuperview()
            make.left.equalTo(imgView.snp.right).offset(5)
            make.right.equalTo(-5)
        }
    }
    /// item被點選事件回撥
    fileprivate var itemDidTap:(() -> Void)?
    
    @objc private func itemClick(){
        //將事件傳遞出去
        itemDidTap?()
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        imgView.layer.cornerRadius = imgView.bounds.size.width*0.5
    }
}


class HXQMarqueeView: UIView {
    
    /// 初始化scrollView
    private lazy var scrollView: UIScrollView = {
        let scrollView = UIScrollView(frame: .zero)
        scrollView.scrollsToTop = false
        scrollView.showsVerticalScrollIndicator = false
        scrollView.showsHorizontalScrollIndicator = false
        return scrollView
    }()
    
    
    /// 初始化定時器
    private lazy var timer: Timer = {[unowned self] in
        let timer = Timer(timeInterval: 0.008, target: self, selector: #selector(startToMove), userInfo: nil, repeats: true)
        RunLoop.current.add(timer, forMode: .common)
        return timer
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupUI()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    
    private func setupUI(){
        layer.masksToBounds = true
        
        addSubview(scrollView)
        scrollView.snp.makeConstraints { (make) in
            make.top.left.bottom.equalToSuperview()
            make.width.equalToSuperview()
        }
    }
    
    var marqueeHolder: String?
    
    var marqueeFontSize: CGFloat = 14
    
    var marqueeTextColor = UIColor.black
    
    public var items = [MarqueeModel](){
        didSet{
            
            //判斷2次資料是否相同
            if oldValue == items {
                return
            }
            
            //關閉定時器
            if timer.isValid {
                timer.fireDate = Date.distantFuture
            }
            //移除scrollView中所有控制元件
            for v in scrollView.subviews{
                v.removeFromSuperview()
            }
            //顯示預設
            if items.isEmpty{
                //如果需要顯示預設值的話
                if marqueeHolder != nil{
                    let lb = UILabel()
                    lb.textAlignment = .center
                    lb.text = marqueeHolder
                    lb.font = UIFont.systemFont(ofSize: marqueeFontSize)
                    lb.textColor = marqueeTextColor
                    scrollView.addSubview(lb)
                    lb.snp.makeConstraints { (make) in
                        make.height.equalToSuperview()
                        make.left.equalTo(20)
                    }
                    //更新scrollView的ContentSize
                    scrollView.snp.makeConstraints { (make) in
                        make.right.equalTo(lb.snp.right)
                    }
                    layoutIfNeeded()
                    scrollView.x = 0;
                }
            }else{
                let margin: CGFloat = 10
                let gap: CGFloat = 20
                var last: MarqueeItem?
                for (i,model) in items.enumerated(){
                    let item = MarqueeItem()
                    item.model = model
                    item.itemDidTap = { [unowned self] in
                        self.selectionBlock?(model,i)
                    }
                    scrollView.addSubview(item)
                    item.snp.makeConstraints { (make) in
                        if last == nil{
                            make.left.equalTo(margin)
                        }else{
                            make.left.equalTo(last!.snp.right).offset(gap)
                        }
                        make.height.equalToSuperview()
                    }
                    last = item
                }
                //更新scrollView的ContentSize
                scrollView.snp.makeConstraints { (make) in
                    make.right.equalTo(last!.snp.right).offset(margin)
                }
                
                layoutIfNeeded()
                
                //拿到contentSize重新更新scrollView約束
                scrollView.snp.remakeConstraints { (make) in
                    make.width.equalTo(scrollView.contentSize.width)
                    make.top.bottom.equalToSuperview()
                    make.right.equalTo(last!.snp.right).offset(margin)
                    make.left.equalTo(self.snp.right)
                }
                //開始啟動定時器
                timer.fireDate = Date(timeIntervalSinceNow: 0)
            }
        }
    }
    
    private var selectionBlock: ((MarqueeModel,Int) -> Void)?
    
    public func queeSelection(_ callBack: ((MarqueeModel,Int) -> Void)?){
        selectionBlock = callBack
    }
    
    @objc private func startToMove(){
        scrollView.x = scrollView.x - 0.5 ;
        if scrollView.x <= -scrollView.contentSize.width {
            scrollView.x = self.bounds.size.width;
        }
    }
    
    deinit {
        if timer.isValid {
            timer.invalidate()
        }
    }
}

使用方法:

        //建立
        let marquee = HXQMarqueeView()
        view.addSubview(marquee)
        //設定約束
        marquee.snp.makeConstraints { (make) in
            make.left.equalTo(20)
            make.right.equalTo(-20)
            make.top.equalTo(100)
            make.height.equalTo(30)
        }
        //初始化資料來源
        var array = [MarqueeModel]()
        for i in 0..<5 {
            let item = MarqueeModel()
            item.title = "我完事了,你們呢\(i)"
            item.img = ""
            item.textColor = UIColor.black
            item.font = UIFont.systemFont(ofSize: 14)
            array.append(item)
        }
        //賦值
        marquee.items = array
        //監聽點選
        marquee.queeSelection { (model, index) in
            print("\(model.title ?? "") + \(index)")
        }