前言: 考虑到Swift ABI已经稳定, 然后最近公司项目考虑部分功能开始用Swift重构,所以又要开始认真学习Swift了, 这是一个学习Swift语言的演示Demo, 当然稳定性也是没问题的, 重在学习语言特性, 顺带实现一些功能, 需要可以自取
最新版本Swift跑马灯实现Demo在 XTMovingView
这个文件夹
优化:
- 匀速设置枚举
- 多种方向选择
另外:
- 有什么好的想法可以提给我
- 喜欢点个star
效果图如下
![](https://img.haomeiwen.com/i1506501/3beff6579351a308.gif)
/// 跑马灯移动的四个方向, 如果有需要可以自己扩展
enum MovingDirectionType {
case left
case right
case bottom
case top
}
/// 速度类型
enum SpeedType {
/// 长文字慢, 短文字快
case special
/// 不根据文字长短, 都是匀速
case normal
}
/// 必选协议做到循环播放
protocol XTMovingViewProtocol {
func drawMarqueeView(drawMarqueeView: XTMovingView, animationDidStopFinished: Bool) -> Void
}
class XTMovingView: UIView, CAAnimationDelegate {
/// 速度
var speed: Float = 1.0
/// 宽
var width: Float = 0.0
/// 高
var height: Float = 0.0
/// 动画视图宽
var animationViewWidth: Float = 0.0
/// 动画视图高
var animationViewHeight: Float = 0.0
/// 是否停止
var stop: Bool = true
/// 方向
var moveType: MovingDirectionType = .left
/// 速度类型
var speedType: SpeedType = .special
/// 内容
var contentView = UIView()
/// 动画视图
var animationView = UIView()
/// 协议
var delegate : XTMovingViewProtocol?
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override init(frame: CGRect) {
super.init(frame: frame)
width = Float(frame.size.width)
height = Float(frame.size.height)
speed = 1
self.layer.masksToBounds = true
moveType = .left
animationView = UIView.init(frame: CGRect.init())
self.addSubview(animationView)
}
/// 添加Content视图
func addContentView(v: UIView) -> Void {
contentView.removeFromSuperview()
v.frame = v.bounds
contentView = v
animationView.frame = v.bounds
animationView.addSubview(contentView)
/// 内部空间W
animationViewWidth = Float(animationView.frame.size.width)
/// 内部空间H
animationViewHeight = Float(animationView.frame.size.height)
}
/// 开始动画
func startAnimation() -> Void {
animationView.layer.removeAnimation(forKey: "animationViewPosition")
stop = false
/// 右边的中心
let pointRightCenter = CGPoint.init(x: Int(width + animationViewWidth / 2), y: Int(animationViewHeight) / 2)
/// 左边的中信
let pointLeftCenter = CGPoint.init(x: -Int(animationViewWidth / 2), y: Int(animationViewHeight) / 2)
/// 下中心
let pointBottomCenter = CGPoint.init(x: Int(animationViewWidth / 2), y: Int(animationViewHeight) / 2 + Int(height))
/// 上中心
let pointUpCenter = CGPoint.init(x: Int(animationViewWidth) / 2, y: -Int(animationViewHeight) / 2)
var fromPoint = CGPoint.init()
var toPoint = CGPoint.init()
switch moveType {
case .left:
fromPoint = pointRightCenter
toPoint = pointLeftCenter
case .right:
fromPoint = pointLeftCenter
toPoint = pointRightCenter
case .bottom:
fromPoint = pointBottomCenter
toPoint = pointUpCenter
case .top:
fromPoint = pointUpCenter
toPoint = pointBottomCenter
}
animationView.center = fromPoint
let movePath = UIBezierPath.init()
movePath.move(to: fromPoint)
movePath.addLine(to: toPoint)
let moveAnimation = CAKeyframeAnimation.init(keyPath: "position")
moveAnimation.path = movePath.cgPath
moveAnimation.isRemovedOnCompletion = true
if self.speedType == .special {
moveAnimation.duration = CFTimeInterval(animationViewWidth / 30 * (1 / speed))
}
if self.speedType == .normal {
moveAnimation.duration = CFTimeInterval(2 * (1 / speed))
}
moveAnimation.delegate = self
animationView.layer.add(moveAnimation, forKey: "animationViewPosition")
}
/// 停止动画
func stopAnimation() -> Void {
stop = true
animationView.layer.removeAnimation(forKey: "animationViewPosition")
}
func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
delegate?.drawMarqueeView(drawMarqueeView: self, animationDidStopFinished: flag)
if flag && !stop {
self.startAnimation()
}
}
/// 暂停
func pauseAnimation() -> Void {
let layer = animationView.layer
let pausedTime = layer.convertTime(CACurrentMediaTime(), from: nil)
layer.speed = 0
layer.timeOffset = pausedTime
}
/// 重启
func resumeAnimation() -> Void {
let layer = animationView.layer
let pausedTime = layer.timeOffset
layer.speed = 1
layer.timeOffset = 0
layer.beginTime = 0
let timeSincePause = layer .convertTime(CACurrentMediaTime(), from: nil) - pausedTime
layer.beginTime = timeSincePause
}
}
以上是全部内部实现
如何使用呢
drawMarqueeView0 = XTMovingView.init(frame: CGRect.init(x: 0, y: 104, width: screenWidth, height: 20.0))
drawMarqueeView0.delegate = self
drawMarqueeView0.speed = 1
drawMarqueeView0.backgroundColor = UIColor.clear
drawMarqueeView0.moveType = .right
drawMarqueeView0.speedType = .normal
self.view.addSubview(drawMarqueeView0)
drawMarqueeView0.addContentView(v: self.createLabelWithText(text: "夏天然后😁", color: UIColor.black))
drawMarqueeView0.startAnimation()
之后放上一个子视图来承载内容
/// 创建AmationView的子视图, 这里我放置的是Label
func createLabelWithText(text: NSString, color: UIColor) -> UILabel {
let font:UIFont! = UIFont.systemFont(ofSize: 12)
let attributes = [NSAttributedString.Key.font:font]
let str = text
let w = str.calculateWidthWithAttributeText(dic: attributes as Dictionary<NSAttributedString.Key, Any>)
let label = UILabel.init(frame: CGRect.init(x: 0.0, y: 0.0, width: Double(w), height: 20.0))
label.font = font
label.text = text as String
label.textColor = color
label.backgroundColor = UIColor.green
label.sizeToFit()
return label
}
以上~
网友评论