swift学习swift 学习

swift实现文字走马灯的效果

2020-06-17  本文已影响0人  苍眸之宝宝

简介:

在最近的项目中有关MP3播放的需求,且有的MP3的名称较长;如果显示时,固定宽度和不限控件的宽度,都不满足用户能够看到全名的需求;固定宽度可能造成名称显示不全,不限控件的宽度UI显示和布局不够美观和可控;文字走马灯效果是这种问题的解决方案。

1.实现思路:

在 UIScrollView 放置一个 UILabel ;如果 Label 中文字计算所得的长度小于 ScrollView 的宽度时,Label 可以在 ScrollView 完全显示,不用进行其它操作;否则 Label 在 ScrollView 上只是部分显示,我创建一个 CADisplayLink 定时器,用来操控 Label 在 ScrollView 上进行滚动,这样 Label中的文字就可以在 ScrollView 上滚动显示了。 效果.gif

2.实现代码:

class AKMP3NameScrollView: UIView {
    
    public var text: String? {
        willSet {
            self.nameLabel?.text = newValue
            self.setNeedsLayout()
        }
    }
    
    public var textColor: UIColor = .init(hex: "#333333") {
        willSet {
            self.nameLabel?.textColor = newValue
        }
    }
    
    public var textFont: UIFont = .systemFont(ofSize: 15, weight: .medium) {
        willSet {
            self.nameLabel?.font = newValue
        }
    }
    
    private weak var displayLink: CADisplayLink?
    
    private var duration: TimeInterval = 0
    
    /// 是否向左滚动标记
    private var isLeft: Bool = true
    
    /// 是否需要滚动标记
    private var isCanRun: Bool = true
    
    private weak var nameLabel: UILabel?
    private weak var scrollView: UIScrollView?
    private weak var leftGlassLayer: CAGradientLayer?
    private weak var rightGlassLayer: CAGradientLayer?

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.initSubviews()
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.displayLink?.isPaused = true
    }
    
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        if self.isCanRun {
            self.displayLink?.isPaused = false
        }
    }
    
    override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
        if self.isCanRun {
            self.displayLink?.isPaused = false
        }
    }
    
    deinit {
        self.displayLink?.invalidate()
        self.displayLink = nil
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        let textSize = self.nameLabel?.text?.stringSize(self.nameLabel!.font) ?? .zero
        let margin: CGFloat = 30
        let textWith = textSize.width + margin * 2
        self.scrollView?.frame = self.bounds
        self.scrollView?.contentSize = CGSize.init(width: 0, height: textWith)
        self.nameLabel?.frame = CGRect.init(x: 0, y: 0, width: textWith, height: textSize.height)
        self.duration = 0
        self.isCanRun = textWith > self.width
        self.displayLink?.isPaused = self.width >= textWith
        
        self.leftGlassLayer?.isHidden = self.width >= textWith
        self.rightGlassLayer?.isHidden = self.width >= textWith
        self.leftGlassLayer?.frame = CGRect.init(x: 0, y: 0, width: 25, height: self.height)
        self.rightGlassLayer?.frame = CGRect.init(x: self.width - 25, y: 0, width: 25, height: self.height)
    }
    
    private func initSubviews() {
        let scrollView = UIScrollView.init()
        scrollView.isUserInteractionEnabled = false
        scrollView.showsVerticalScrollIndicator = false
        scrollView.showsHorizontalScrollIndicator = false
        self.addSubview(scrollView)
        self.scrollView = scrollView
        
        let nameLabel = UILabel.init()
        nameLabel.textAlignment = .center
        nameLabel.font = self.textFont
        nameLabel.textColor = self.textColor
        scrollView.addSubview(nameLabel)
        self.nameLabel = nameLabel
        
        let displayLink = CADisplayLink.init(target: self, selector: #selector(timerEvent))
        displayLink.add(to: RunLoop.current, forMode: RunLoop.Mode.common)
        displayLink.isPaused = true
        self.displayLink = displayLink
        
        let leftGlassLayer = CAGradientLayer.init()
        leftGlassLayer.startPoint = .zero
        leftGlassLayer.endPoint = CGPoint.init(x: 1, y: 0)
        leftGlassLayer.colors = [UIColor.init(hex: "#6DD781").cgColor, UIColor.init(hex: "#6DD781").alpha(0).cgColor]
        self.layer.addSublayer(leftGlassLayer)
        self.leftGlassLayer = leftGlassLayer
        
        let rightGlassLayer = CAGradientLayer.init()
        rightGlassLayer.startPoint = .zero
        rightGlassLayer.endPoint = CGPoint.init(x: 1, y: 0)
        rightGlassLayer.colors = [UIColor.init(hex: "#6DD781").alpha(0).cgColor, UIColor.init(hex: "#6DD781").cgColor]
        self.layer.addSublayer(rightGlassLayer)
        self.rightGlassLayer = rightGlassLayer
    }
    
    /// 定时器事件
    @objc private func timerEvent() {
        let maxWith = (self.nameLabel?.width ?? 0) - self.width
        let scale: TimeInterval = 0.5
        if self.duration < 0 {
            self.isLeft = false
            self.duration += scale
        }
        else if (self.duration >= 0 && self.duration <= TimeInterval(maxWith)) {
            if self.isLeft {
                self.duration -= scale
            }
            else {
                self.duration += scale
            }
        }
        else {
            self.isLeft = true
            self.duration -= scale
        }
        self.scrollView?.setContentOffset(CGPoint.init(x: self.duration, y: 0), animated: false)
    }

}

3.代码说明:

其中 leftGlassLayer 和 rightGlassLayer 是滚动是两边的文字模糊效果的遮罩层;maxWith 为 Label 在 ScrollView 上的x轴方向上的最大滚动宽度;在不超过最大滚动宽度时,进行 self.duration += scale 操作即向右运动;超过最大滚动宽度时宽度,进行 self.duration -= scale 操作即向左运动;调整 scale 大小可以控制滚动的快慢。 效果.gif
上一篇下一篇

猜你喜欢

热点阅读