UILabel向下滑动以发送错误消息

时间:2015-06-10 12:07:30

标签: ios swift

我想在视图中添加UILabel,当发生错误时向下滑动以向用户发送错误消息。它的原型就像Facebook或Instagram显示的那样。这是我到目前为止编写的代码:

func sendErrorMessage(errorString: String) {
    self.errorLabel.text = errorString
    UIView.animateWithDuration(1, animations: {
            self.errorLabel.frame.height = 30 //Cannot assign to the result of this expression
            self.topView.layoutIfNeeded()
        }, completion: {
            (finished: Bool) in var timer = NSTimer.scheduledTimerWithTimeInterval(3, target: self, selector: Selector(), userInfo: nil, repeats: false)
    })
}

errorLabel现在已经在故事板中,但高度为0,topViewerrorLabel的超级视图。我对这些方法很陌生,所以我被困在这里。我不明白为什么会发生错误以及selector应该在这里做些什么。还有一个步骤我在这里没有完成,errorLabel应该在三秒后滑动消失,这就是我在这里需要timer的原因。

另外:如果我在需要的时候创建一个新的errorLabel而不是在故事板之前准备好它,那会有什么不同吗?我的意思是应用程序内存管理性能。

更新

我在许多errorLabel中需要ViewController,所以按照@Sajjon的想法,我尝试了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()
    }
}

4 个答案:

答案 0 :(得分:1)

一般来说,视图用于其框架或边界属性的CGRect对象是不可变的。不要试图直接修改视图的框架,而是创建一个包含所需最终大小和位置的新CGRect,并将其分配给动画块中的视图框架。

//Don't do this.
myView.frame.size.height = 30; 

// Do this instead.
CGRect oldRect = myView.frame;
CGRect newFrame = CGRectMake(oldRect.origin.x, oldRect.origin.y, oldRect.size.width, 30);
[UIView animateWithDuration:0.4 animations:^{
    myView.frame = newFrame;
};

另外,我强烈建议让标签显示并隐藏我在屏幕顶部和屏幕顶部更改其y位置,而不是将高度更改为0,这可能会产生一些意想不到的布局后果

答案 1 :(得分:0)

换高度尝试:

self.errorLabel.frame.size.height = 30

答案 2 :(得分:0)

你需要设置Frame of UILable而不是它的高度。

String DATABASE_CREATE_SQL = 
    "CREATE TABLE " + DATABASE_TABLE 
    + " (" + KEY_ROWID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
    + KEY_TRANSACTION + " TEXT NOT NULL, "
    + KEY_ITEM + " TEXT NOT NULL, "
    + KEY_SUM + " TEXT"
    + ");";

答案 3 :(得分:0)

你应该为此使用autolayout,当显示errorLabel(或它在里面的某个容器视图)时,我会给出你想要的值的高度约束(30)。并通过赋予约束值0来再次隐藏它。

我会创建一个UIView扩展并放置代码来设置此高度变化的动画。

这是未经测试的代码,但会让您了解如何实现它。

class MyViewController: UIViewController {
    @IBOutlet weak var errorLabelHeightConstraint: NSLayoutConstraint!
    private let errorLabelHeightVisible: CGFloat = 30
    private let hideDelay: NSTimeInterval = 3
    private var timer: NSTimer!

    func sendErrorMessage(errorString: String) {
        errorLabel.text = errorString
        showOrHideErrorView(false)
    }

    func showOrHideErrorView(hide: Bool = true, animated: Bool = true) {
        if hide {
            errorLabelHeightConstraint.constant = 0
        } else {
            errorLabelHeightConstraint.constant = errorLabelHeightVisible
        }

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

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

    /* Selector method */
    func hideError() {
        showOrHideErrorView()
    }

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


extension UIView {

    static var standardDuration: NSTimeInterval { get { return 0.3 } }

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