I have a custom view , CustomLayout (blue, custom UIView), and this view contains 3 subviews vertical aligned by using constraints (Layout Anchors), each view are aligned following this order:
- 1 view: SlideLayout (red, custom UIView)
- 2 view: UIButton (yellow)
- 3 view: UIView (dry gray)
I want when I clicked on the button (yellow), the height size of SlideLayout (red) increase if open or decrease if close by using animation. And other views must change position during animation and the parent view (CustomLayout) must increase/decrease his height size (animation) if SlideLayout increase/decrease.
What method is called when I use this method:
UIView.animate(withDuration, delay, options, animations, completion)
I override layoutIfNeeded() method by adding a simple print but it does not call every time during animation
I try this but It doesn’t work as I expect. How I can fix that thank you.
Codes:
class CustomLayout: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
private func setup() {
onLayout()
}
public func onLayout() {
print("\(frame.size.height)")
let MARGIN: CGFloat = 10
for i in 0 ..< subviews.count {
let child = subviews[i]
if i == 0 { // slide layout
child.translatesAutoresizingMaskIntoConstraints = false
child.topAnchor.constraint(equalTo: topAnchor, constant: MARGIN).isActive = true
child.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
child.widthAnchor.constraint(equalToConstant: frame.size.width - (MARGIN * 2)).isActive = true
let enchorHeight = child.heightAnchor.constraint(equalToConstant: child.frame.size.height);
enchorHeight.isActive = true
(subviews[0] as! SlideDownLayout).enchorHeight = enchorHeight
}
else if i == 1 { // button
child.translatesAutoresizingMaskIntoConstraints = false
child.topAnchor.constraint(equalTo: subviews[0].bottomAnchor, constant: MARGIN).isActive = true
child.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
child.widthAnchor.constraint(equalToConstant: child.frame.size.width).isActive = true
child.heightAnchor.constraint(equalToConstant: child.frame.size.height).isActive = true
}
else if i == 2 { // uiview
child.translatesAutoresizingMaskIntoConstraints = false
child.topAnchor.constraint(equalTo: subviews[1].bottomAnchor, constant: MARGIN).isActive = true
child.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
child.widthAnchor.constraint(equalToConstant: frame.size.width - (MARGIN * 4)).isActive = true
child.heightAnchor.constraint(equalToConstant: 300).isActive = true
bottomAnchor.constraint(equalTo: child.bottomAnchor, constant: MARGIN).isActive = true
}
}
}
}
class SlideDownLayout: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
private var HEIGHT: CGFloat = 0
private var isClosed: Bool = true
private func setup() {
HEIGHT = frame.height
frame.size.height = 0
}
public func slideAnimation(view: UIView) {
print("\(HEIGHT)")
isClosed = !isClosed
self.enchorHeight!.constant = self.isClosed ? 0 : self.HEIGHT
UIView.animate(withDuration: 1, delay: 0, options: .curveEaseInOut, animations: {
self.superview?.layoutIfNeeded()
view.layoutIfNeeded()
}, completion: nil)
}
override func layoutIfNeeded() {
print("...")
super.layoutIfNeeded()
}
var enchorHeight: NSLayoutConstraint? = nil
}
class ViewController: UIViewController {
@IBOutlet weak var customLayout: CustomLayout!
@IBOutlet weak var slideDownLayout: SlideDownLayout!
override func viewDidLoad() {
super.viewDidLoad()
customLayout.translatesAutoresizingMaskIntoConstraints = false
customLayout.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
customLayout.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 0).isActive = true
customLayout.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 0).isActive = true
customLayout.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
}
override var prefersStatusBarHidden: Bool {
return true
}
@IBAction
func buttonListener(_ sender: Any) {
slideDownLayout.slideAnimation(view: self.view)
}
}