子类化UILabel无法按预期工作

时间:2015-06-11 03:32:51

标签: ios swift uilabel

我想在视图中添加UILabel,当发生错误时向下滑动以向用户发送错误消息,3秒后它将向上滑动消失。它的原型就像Facebook或Instagram显示的那样。我在许多errorLabel中需要ViewController,因此我尝试将UILabel子类化。这是我的子类ErrorLabel

class ErrorLabel: UILabel {
    var errorString: String?

    func sendErrorMessage() {
        self.text = errorString

        showErrorLabel()
        let timer = NSTimer.scheduledTimerWithTimeInterval(3, target: self, selector: "hideErrorLabel", userInfo: nil, repeats: false)
    }
    func animateFrameChange() {
        UIView.animateWithDuration(1, animations: { self.layoutIfNeeded() }, completion: nil)
    }
    func showErrorLabel() {
        let oldFrame = self.frame
        let newFrame = CGRectMake(oldFrame.origin.x, oldFrame.origin.y, oldFrame.height + 30, oldFrame.width)
        self.frame = newFrame
        self.animateFrameChange()
    }
    func hideErrorLabel() {
        let oldFrame = self.frame
        let newFrame = CGRectMake(oldFrame.origin.x, oldFrame.origin.y, oldFrame.height - 30, oldFrame.width)
        self.frame = newFrame
        self.animateFrameChange()
    }
}

然后,我尝试将errorLabel添加到ViewController之一,如下所示:

class ViewController: UIViewController {
    var errorLabel = ErrorLabel()

    override func viewDidLoad() {
        super.viewDidLoad()

        let errorLabelFrame = CGRectMake(0, 20, self.view.frame.width, 0)
        self.errorLabel.frame = errorLabelFrame
        self.errorLabel.backgroundColor = translucentTurquoise
        self.errorLabel.font = UIFont.systemFontOfSize(18)
        self.errorLabel.textColor = UIColor.whiteColor()
        self.errorLabel.textAlignment = NSTextAlignment.Center
        self.view.addSubview(errorLabel)
        self.view.bringSubviewToFront(errorLabel)
    }

    func aFunc(errorString: String) {
        self.errorLabel.errorString = errorString
        self.errorLabel.sendErrorMessage()
    }
}

当我在iOS模拟器中运行它时,它无法正常工作:

  1. errorLabel左侧水平显示,中间垂直显示,I...只有Invalid parameters
  2. 1秒后,它会按预期进入位置,但宽度仍然不是self.view.frame.width
  3. 之后,没有任何反应,但它应该在3秒后滑动。
  4. 你能告诉我什么是错的以及如何解决错误吗?

2 个答案:

答案 0 :(得分:0)

我可能会部分解决您的问题。希望它有所帮助。

  • 当字符串比视图长时,会发生I...。为此,您需要增加UILabel的大小。
  • 要在UILable中对齐文本,请参阅this
  • 要设置动画,请在UIView.animateWithDuration的完成块中使用相同的代码。请参阅此link

我建议你考虑使用Extensions来完成你想要做的事情。

答案 1 :(得分:0)

我不是子类化UILabel,而是继承UIViewController,也许你已经完成了吗?让我们调用子类--BaseViewController,让我们所有的UIViewControllers子类化这个类。

然后我将以编程方式创建一个UIView,其中包含此BaseViewController类中的垂直和水平居中的UILabel。这里重要的部分是为它创建NSLayoutConstraints。然后我会通过更改约束的值来隐藏和显示它。

我会使用名为pod的优秀Cartography来创建约束,这使得它非常简单和干净!

使用此解决方案,您应该能够在任何UIViewControllers中显示或隐藏错误消息

这是未经测试的代码,但希望非常接近您问题的解决方案。

import Cartography /* Requires that you have included Cartography in your Podfile */
class BaseViewController: UIViewController {

    private var yPositionForErrorViewWhenVisible: Int { return 0 }
    private var yPositionForErrorViewWhenInvisible: Int { return -50 }
    private let hideDelay: NSTimeInterval = 3
    private var timer: NSTimer!

    var yConstraintForErrorView: NSLayoutConstraint!
    var errorView: UIView!
    var errorLabel: UILabel!

    //MARK: - Initialization
    required init(aDecoder: NSCoder) {
        super.init(aDecoder)
        setup()
    }

    //MARK: - Private Methods
    private func setup() {
        setupErrorView()
    }

    private func setupErrorView() {
        errorView = UIView()
        errorLabel = UILabel()

        errorView.addSubview(errorLabel)
        view.addSubview(errorView)

        /* Set constraints between viewController and errorView and errorLabel */
        layout(view, errorView, errorLabel) {
            parent, errorView, errorLabel in

            errorView.width == parent.width
            errorView.centerX == parent.centerX
            errorView.height == 50

            /* Capture the y constraint, which defaults to be 50 points out of screen, so that it is not visible */
            self.yConstraintForErrorView = (errorView.top == parent.top - self.yPositionForErrorViewWhenInvisible)

            errorLabel.height = 30
            errorLabel.width == errorView.width
            errorLabel.centerX == errorView.centerX
            errorLabel.centerY = errorView.centerY
        }
    }

    private func hideOrShowErrorMessage(hide: Bool, animated: Bool) {
         if hide {
            yConstraintForErrorView.constant = yPositionForErrorViewWhenInvisible
        } else {
            yConstraintForErrorView.constant = yPositionForErrorViewWhenVisible
        }

        let automaticallyHideErrorViewClosure: () -> Void = {
            /* Only scheduling hiding of error message, if we just showed it. */
            if show {
                automaticallyHideErrorMessage()
            }
        }

        if animated {
            view.animateConstraintChange(completion: {
                (finished: Bool) -> Void in
                automaticallyHideErrorViewClosure()
            })
        } else {
            view.layoutIfNeeded()
            automaticallyHideErrorViewClosure()
        }
    }

    private func automaticallyHideErrorMessage() {
        if timer != nil {
            if timer.valid {
                timer.invalidate()
            }
            timer = nil
        }
        timer = NSTimer.scheduledTimerWithTimeInterval(hideDelay, target: self, selector: "hideErrorMessage", userInfo: nil, repeats: false)    
    }

    //MARK: - Internal Methods
    func showErrorMessage(message: String, animated: Bool = true) {
        errorLabel.text = message
        hideOrShowErrorMessage(false, animated: animated)
    }

    //MARK: - Selector Methods
    func hideErrorMessage(animated: Bool = true) {
        hideOrShowErrorMessage(true, animated: animated)
    }
}

extension UIView {

    static var standardDuration: NSTimeInterval { return 0.3 }

    func animateConstraintChange(duration: NSTimeInterval = standardDuration, completion: ((Bool) -> Void)? = nil) {
        UIView.animate(durationUsed: duration, animations: {
            () -> Void in
            self.layoutIfNeeded()
        }, completion: completion)
    }
}