如何在swift中创建一个简单的UILabel子类用于选框/滚动文本效果?

时间:2017-03-25 20:59:36

标签: swift scroll uilabel subclass marquee

正如您在上面所看到的,我尝试编写UILabel的简单(!)子类,以便在标签文本太长时制作选取框或滚动文本效果。我知道那里已经有很好的课程(例如https://cocoapods.org/pods/MarqueeLabel),但我想自己创作:)

在下面你可以看到我目前的课程。 我也无法解决新标签向右滚动的问题,但也有第三个标签不应该存在。我认为这是标签本身。但是,当我尝试用该标签替换第一个附加标签时,我不会工作。我希望它不会太混乱:/

对我而言,我只需将故事板中的课程分配给标签,这一点非常重要。因此,不需要去视图控制器(在插座旁边)添加代码。我希望它清楚我想要的东西:D

再次:

  • UILabel的简单子类
  • 滚动标签
  • 应该可以在其他类中没有任何其他代码的情况下工作(除了更改标签文本的插座,例如......)

(它是我自己的第一个子类,所以请随时教我如何正确行事:))

非常感谢!

到目前为止还不完美,但这是我现在的课程:

import UIKit

class LoopLabel: UILabel {

    var labelText : String?
    var rect0: CGRect!
    var rect1: CGRect!
    var labelArray = [UILabel]()
    var isStop = false
    var timeInterval: TimeInterval!
    let leadingBuffer = CGFloat(25.0)
    let loopStartDelay = 2.0

   required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.lineBreakMode = .byClipping
   }

    override var text: String? {
        didSet {
            labelText = text
            setup()
        }
    }

    func setup() {
        let label = UILabel()
        label.frame = CGRect.zero
        label.text = labelText

        timeInterval = TimeInterval((labelText?.characters.count)! / 5)
        let sizeOfText = label.sizeThatFits(CGSize.zero)
        let textIsTooLong = sizeOfText.width > frame.size.width ? true : false

        rect0 = CGRect(x: leadingBuffer, y: 0, width: sizeOfText.width, height: self.bounds.size.height)
        rect1 = CGRect(x: rect0.origin.x + rect0.size.width, y: 0, width: sizeOfText.width, height: self.bounds.size.height)
        label.frame = rect0

        super.clipsToBounds = true
        labelArray.append(label)
        self.addSubview(label)

        self.frame = CGRect(origin: self.frame.origin, size: CGSize(width: 0, height: 0))

        if textIsTooLong {
            let additionalLabel = UILabel(frame: rect1)
            additionalLabel.text = labelText
            self.addSubview(additionalLabel)

            labelArray.append(additionalLabel)

            animateLabelText()
        }
    }

    func animateLabelText() {
        if(!isStop) {
            let labelAtIndex0 = labelArray[0]
            let labelAtIndex1 = labelArray[1]

            UIView.animate(withDuration: timeInterval, delay: loopStartDelay, options: [.curveLinear], animations: {
                labelAtIndex0.frame = CGRect(x: -self.rect0.size.width,y: 0,width: self.rect0.size.width,height: self.rect0.size.height)
                labelAtIndex1.frame = CGRect(x: labelAtIndex0.frame.origin.x + labelAtIndex0.frame.size.width,y: 0,width: labelAtIndex1.frame.size.width,height: labelAtIndex1.frame.size.height)
            }, completion: { finishied in
                labelAtIndex0.frame = self.rect1
                labelAtIndex1.frame = self.rect0

                self.labelArray[0] = labelAtIndex1
                self.labelArray[1] = labelAtIndex0
                self.animateLabelText()
            })
        } else {
            self.layer.removeAllAnimations()
        }
    }
}

1 个答案:

答案 0 :(得分:2)

首先,如果您不需要在外部访问它们,我会保持变量私有,尤其是labelText(因为您使用的是计算属性文本)。

其次,由于您要将标签添加为子视图,因此我宁愿使用UIView作为容器而不是UILabel。故事板中唯一的区别是添加View而不是Label。

第三,如果使用这种方法,则不应将(视图的)框架设置为零。

这样的事情可以做到:

import UIKit

class LoopLabelView: UIView {

    private var labelText : String?
    private var rect0: CGRect!
    private var rect1: CGRect!
    private var labelArray = [UILabel]()
    private var isStop = false
    private var timeInterval: TimeInterval!
    private let leadingBuffer = CGFloat(25.0)
    private let loopStartDelay = 2.0

    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    var text: String? {
        didSet {
            labelText = text
            setup()
        }
    }

    func setup() {
        self.backgroundColor = UIColor.yellow
        let label = UILabel()
        label.text = labelText
        label.frame = CGRect.zero

        timeInterval = TimeInterval((labelText?.characters.count)! / 5)
        let sizeOfText = label.sizeThatFits(CGSize.zero)
        let textIsTooLong = sizeOfText.width > frame.size.width ? true : false

        rect0 = CGRect(x: leadingBuffer, y: 0, width: sizeOfText.width, height: self.bounds.size.height)
        rect1 = CGRect(x: rect0.origin.x + rect0.size.width, y: 0, width: sizeOfText.width, height: self.bounds.size.height)
        label.frame = rect0

        super.clipsToBounds = true
        labelArray.append(label)
        self.addSubview(label)

        //self.frame = CGRect(origin: self.frame.origin, size: CGSize(width: 0, height: 0))

        if textIsTooLong {
            let additionalLabel = UILabel(frame: rect1)
            additionalLabel.text = labelText
            self.addSubview(additionalLabel)

            labelArray.append(additionalLabel)

            animateLabelText()
        }
    }

    func animateLabelText() {
        if(!isStop) {
            let labelAtIndex0 = labelArray[0]
            let labelAtIndex1 = labelArray[1]

            UIView.animate(withDuration: timeInterval, delay: loopStartDelay, options: [.curveLinear], animations: {
                labelAtIndex0.frame = CGRect(x: -self.rect0.size.width,y: 0,width: self.rect0.size.width,height: self.rect0.size.height)
                labelAtIndex1.frame = CGRect(x: labelAtIndex0.frame.origin.x + labelAtIndex0.frame.size.width,y: 0,width: labelAtIndex1.frame.size.width,height: labelAtIndex1.frame.size.height)
            }, completion: { finishied in
                labelAtIndex0.frame = self.rect1
                labelAtIndex1.frame = self.rect0

                self.labelArray[0] = labelAtIndex1
                self.labelArray[1] = labelAtIndex0
                self.animateLabelText()
            })
        } else {
            self.layer.removeAllAnimations()
        }
    }
}