Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Update SnapKit Constraint offset

I am using SnapKit and can't find a clean way to update the offset of a constraint. It's a simple loading bar view whose inner view (expiredTime) has to fill the parent (left to right) according to percentage.

I create the constraint in the awakeFromNib of a custom UIView

    self.expiredTime.snp.makeConstraints { (make) in
        make.left.equalTo(self)
        make.top.equalTo(self)
        make.bottom.equalTo(self)
        self.constraintWidth = make.width.equalTo(self).constraint 
    }
    setNeedsUpdateConstraints()

then whenever the time is updated i call setNeedsUpdateConstraints() which will trigger the default updateConstraints() which has been overloaded as by apple hint:

Does not work: (the expiredTime view always fit with the parent view)

override func updateConstraints() {

    let offset = self.frame.width * CGFloat(percentage)

    self.expiredTime.snp.updateConstraints { (make) in
        make.width.equalTo(self).offset(offset).constraint
    }
    super.updateConstraints()
}

This also does not work:

override func updateConstraints() {
    let offset = self.frame.width * CGFloat(percentage)
    self.constraintWidth?.update(offset: offset)
    super.updateConstraints()
}

Rebuilding all the constraint works but i would like to avoid it

override func updateConstraints() {

    self.expiredTime.snp.remakeConstraints() { (make) in
        make.left.equalTo(self)
        make.top.equalTo(self)
        make.bottom.equalTo(self)
        self.constraintWidth = make.width.equalTo(self).multipliedBy(self.percentage).constraint
    }
    super.updateConstraints()
}
like image 919
jalone Avatar asked Feb 03 '17 10:02

jalone


1 Answers

Your first solution does not work, because you already set the width of your expiredTime view to the full width before adding the offset. To make it work you have to set the width to 0 and then add the offset. But the offset is not really needed here, you can simply set the width to the calculated width:

override func updateConstraints() {
    let width = self.frame.width * CGFloat(percentage)
    self.expiredTime.snp.updateConstraints { (make) in
        make.width.equalTo(width)
    }
    super.updateConstraints()
}

Or if you keep a reference to the constraint you don't have to override updateConstraints() at all. You can simply call the constraint's update method (without calling setNeedsUpdateConstraints() afterwards)

constraintWidth?.update(offset: CGFloat(percentage) * view.bounds.width)

Just remember to set the width to 0 when you initialize constraintWidth:

self.expiredTime.snp.makeConstraints { (make) in
    make.left.top.bottom.equalTo(self)
    self.constraintWidth = make.width.equalTo(0).constraint 
}
like image 134
joern Avatar answered Nov 10 '22 12:11

joern