0

Inside my app I'm animating the height constraint of a view and when the height constraint changes the view does translate for a while a little bit down despite I set the constraint to the top as 0. Here's the code I used to animate the change:

UIView.animate(withDuration: 0.5) {
    if finalHeight >= mediumY {
        self.heightConstraintConstant = self.maxHeight
    } else {
        self.heightConstraintConstant = self.minHeight
    }
}

And here's the one for creating all the expandable view:

    //
//  ExpandibleView.swift
//  PhotoMapping
//
//  Created by Lorenzo Santini on 04/09/18.
//  Copyright © 2018 Lorenzo Santini. All rights reserved.
//

import Foundation
import UIKit

class ExpandableView: UIView {
    let panGestureRecognizer = UIPanGestureRecognizer()

    var minHeight: CGFloat = 0 {
        didSet {
            initialHeight = minHeight
        }
    }
    var maxHeight: CGFloat = 0

    var initialHeight: CGFloat = 0
    var initialPoint: CGPoint? = nil

    var heightConstraintConstant: CGFloat {
        get {
            if !self.constraints.filter({ $0.firstAttribute == .height}).isEmpty {
                return self.constraints.filter({$0.firstAttribute == .height && $0.secondItem == nil}).first!.constant
            } else {
                let constrain = NSLayoutConstraint(item: self, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1.0, constant: initialHeight)
                constrain.priority = .defaultHigh
                self.addConstraint(constrain)
                return constrain.constant
            }
        }

        set(newConstant){
            if !self.constraints.filter({ $0.firstAttribute == .height}).isEmpty {
                self.constraints.filter({$0.firstAttribute == .height && $0.secondItem == nil}).first?.constant = newConstant
            } else {
                let constrain = NSLayoutConstraint(item: self, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1.0, constant: newConstant)
                self.addConstraint(constrain)
            }
            //self.layoutIfNeeded()
        }

    }

    func initialize(minHeight: CGFloat, maxHeight: CGFloat) {
        //Create panGestureRecognizer
        panGestureRecognizer.addTarget(self, action: #selector(handlePan(_:)))
        panGestureRecognizer.minimumNumberOfTouches = 1
        panGestureRecognizer.maximumNumberOfTouches = 1
        self.addGestureRecognizer(panGestureRecognizer)

        //Set min and max height
        self.minHeight = minHeight
        self.maxHeight = maxHeight

        self.translatesAutoresizingMaskIntoConstraints = false

        self.subviews.map{$0.translatesAutoresizingMaskIntoConstraints = false}
    }

    @objc func handlePan(_ sender: Any) {
        let translation = panGestureRecognizer.translation(in: self)

        if initialPoint == nil {
            initialPoint = translation
        }

        let translationHeight = CGFloat(translation.y - initialPoint!.y)
        let finalHeight = translationHeight + initialHeight

        if panGestureRecognizer.state == .changed {
            if finalHeight <= maxHeight && finalHeight >= minHeight {
                heightConstraintConstant = finalHeight
            } else if finalHeight >= maxHeight {
                heightConstraintConstant = maxHeight
            } else if finalHeight <= minHeight {
                heightConstraintConstant = minHeight
            }
        } else if panGestureRecognizer.state == .ended {

            let mediumY = maxHeight / 2 + minHeight / 2

            if finalHeight >= mediumY {
                self.heightConstraintConstant = self.maxHeight
            } else {
                self.heightConstraintConstant = self.minHeight
            }
            UIView.animate(withDuration: 0.5) {
                self.layoutIfNeeded()
            }

            initialPoint = nil
            initialHeight = heightConstraintConstant
        }

        //layoutIfNeeded()
    }

}

The problem for me isn't how animate the height change because that works but instead is solve the fact that for a while the app seems to ignore the constraint to the top. Here's the gif showing the animation

Lorenzo Santini
  • 655
  • 7
  • 13
  • But that is not how to animate a constraint change. – matt Sep 14 '18 at 18:35
  • Possible duplicate of [iOS: How does one animate to new autolayout constraint (height)](https://stackoverflow.com/questions/13296232/ios-how-does-one-animate-to-new-autolayout-constraint-height). – rmaddy Sep 14 '18 at 18:39
  • I’ve never done anything similar...how should I do? – Lorenzo Santini Sep 14 '18 at 18:40
  • Possible duplicate of [iOS: How does one animate to new autolayout constraint (height)](https://stackoverflow.com/questions/13296232/ios-how-does-one-animate-to-new-autolayout-constraint-height) – Rakesha Shastri Sep 14 '18 at 18:40
  • @RakeshaShastri I did not find the explanation to animate a constraint change – Lorenzo Santini Sep 14 '18 at 18:57
  • I understand that. Which is probably why you put up the question. But the answer is there. This is a pretty basic problem when you learn autolayout. – Rakesha Shastri Sep 14 '18 at 19:00
  • @RakeshaShastri the fact is that the height change is animated but while doing that the view doesn't remain sticked to the top but for a while goes down and then comes back up – Lorenzo Santini Sep 14 '18 at 19:05
  • @rmaddy My problem isn't that the height change isn't animated but that the view doesn't remain sticked to the top as defined in its constraints during the animation – Lorenzo Santini Sep 14 '18 at 19:24
  • @LorenzoSantini can you share a gif? – Rakesha Shastri Sep 15 '18 at 03:00
  • @LorenzoSantini you should probably share the rest of your code for the class. – Rakesha Shastri Sep 15 '18 at 07:15
  • Try calling layoutIfNeeded on the superview – Rakesha Shastri Sep 15 '18 at 07:28
  • @RakeshaShastri Thank you very much...I called inside the animation block the self.superview.layoutIfNeeded() method and know it works perfectly...Can you explain me why? And also why the animation appears slower than before (nothing problematic I just had to change the duration but it's weird to me. – Lorenzo Santini Sep 15 '18 at 07:34

1 Answers1

3

I believe what you need to do is actually animate the layout being updated. More specifically something like this

if finalHeight >= mediumY {
    self.heightConstraintConstant = self.maxHeight
} else {
    self.heightConstraintConstant = self.minHeight
}
UIView.animate(withDuration: 0.5) {
    viewThatTheConstraintBelongsTo.layoutIfNeeded()
}
TNguyen
  • 1,041
  • 9
  • 24