美文网首页Swift开发
最新版本Swift实现iOS跑马灯效果

最新版本Swift实现iOS跑马灯效果

作者: 夏天然后 | 来源:发表于2020-07-16 17:58 被阅读0次

    前言: 考虑到Swift ABI已经稳定, 然后最近公司项目考虑部分功能开始用Swift重构,所以又要开始认真学习Swift了, 这是一个学习Swift语言的演示Demo, 当然稳定性也是没问题的, 重在学习语言特性, 顺带实现一些功能, 需要可以自取
    最新版本Swift跑马灯实现DemoXTMovingView这个文件夹

    优化:

    • 匀速设置枚举
    • 多种方向选择

    另外:

    • 有什么好的想法可以提给我
    • 喜欢点个star

    效果图如下


    image
    ///  跑马灯移动的四个方向, 如果有需要可以自己扩展
    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
        }
    

    以上~

    相关文章

      网友评论

        本文标题:最新版本Swift实现iOS跑马灯效果

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