swift实现文字走马灯的效果
2020-06-17 本文已影响0人
苍眸之宝宝
简介:
在最近的项目中有关MP3播放的需求,且有的MP3的名称较长;如果显示时,固定宽度和不限控件的宽度,都不满足用户能够看到全名的需求;固定宽度可能造成名称显示不全,不限控件的宽度UI显示和布局不够美观和可控;文字走马灯效果是这种问题的解决方案。
1.实现思路:
在 UIScrollView 放置一个 UILabel ;如果 Label 中文字计算所得的长度小于 ScrollView 的宽度时,Label 可以在 ScrollView 完全显示,不用进行其它操作;否则 Label 在 ScrollView 上只是部分显示,我创建一个 CADisplayLink 定时器,用来操控 Label 在 ScrollView 上进行滚动,这样 Label中的文字就可以在 ScrollView 上滚动显示了。 效果.gif2.实现代码:
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)
}
}