How to programmatically increase the height of UIView with Swift
Asked Answered
R

7

35

Inside IB I have a viewController with a segmentedControl and 2 containerViews. In each containerView I have a tableView. From each tableView I push on a detailView. My auto layout is in IB.

Once I pick a segment, I see the corresponding tableView, I pick a cell and the correct detailView gets pushed on the scene.

The issue is once the detailView gets pushed on the segmentedControl is still visible. I decided to hide the segmentedControl which works but there is a big empty space there. I tried to programmatically increase the size of detailView's view but it's not expanding. From what I read it's because I made the initial constraints in storyboards.

How to I programmatically get the detailView's view to expand?

code:

DetailViewController: UIViewController{

override func viewDidLoad() {
        super.viewDidLoad()

 //this isn't increasing the view's size
 self.view.frame.size.height += 20.0

 //doesn't work. I get an error on the last argument
 self.view.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height += 20.0)

 //doesn't work. I get an error on the last argument
 self.view.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.size.height += 20.0)
 }

}

Errors:

//Error for the last argument- height: *self.view.frame.height += 20.0*
self.view.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height += 20.0)

Left side of mutating operator isn't mutable: 'height' is a get-only property

//Error for the last argument- *self.view.frame.size.height += 20.0*:
self.view.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.size.height += 20.0)

Cannot invoke initializer for type 'CGRect' with an argument list of type '(x: Int, y: Int, width: CGFloat, height: ())'

Rabaul answered 24/3, 2017 at 22:31 Comment(0)
N
54

You need to create an outlet for the height constraint of the detail view, and then you can adjust the height programmatically like this myHeightConstraint.constant += extraHeight where extraHeight is a number indicating how much taller you want the detail view to be. You also may need to call self.view.layoutIfNeeded() afterwards.

To create an outlet from a constraint, control drag from the constraint in the storyboard editor (just like you would for an outlet of a UIView) into your code.

You are right - because you are using auto layout and constraints, the adjustments need to be made with constraints too. Setting the raw frames can lead to unexpected behavior. Let me know if you have any other questions or difficulties.

Nasty answered 24/3, 2017 at 22:47 Comment(1)
most important part is dont forget to call -> self.view.layoutIfNeeded(). Works perfectly for me. ThanksCards
A
18

Inside the CGRect initializer you should not be using +=, just +.

Change:

self.view.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height += 20.0)

to:

self.view.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height + 20.0)

You should not be trying to change the value of self.view.frame.height inside the initializer.

Alliterate answered 24/3, 2017 at 22:33 Comment(5)
thanks for the help. The error went away but the view didn't increase.Rabaul
Is your view setup with constraints?Alliterate
yes they it is. But the constraints are set in storyboard. I'm going to edit the questioning include the 3D shots of the layout with the segmentedControl hidden and you'll see the big empty space I want to increase the view overRabaul
Your question is about the error that is now resolved. You should create a new question to deal with your new issue if needed (after you do lots of research first). But your constraints are going to cause issues trying to change the frame I believe.Alliterate
i see your point, the error is resolved but the height didn't increase. I upvoted your answer anyway because it corrected the error. Thanks anyway though :)Rabaul
D
11

For me, a programmatic solution wouldn't require me to create an outlet for every height constraint I might want to modify. Here's a code-only solution that works nicely for me. It should work whether the original constraint was created on the storyboard or programmatically. It also provides an option to animate the change if desired -- although I'm not sure if this would work if the view is nested in a complex hierarchy.

extension UIView {
    func setHeight(_ h:CGFloat, animateTime:TimeInterval?=nil) {

        if let c = self.constraints.first(where: { $0.firstAttribute == .height && $0.relation == .equal }) {
            c.constant = CGFloat(h)

            if let animateTime = animateTime {
                UIView.animate(withDuration: animateTime, animations:{
                    self.superview?.layoutIfNeeded()
                })
            }
            else {
                self.superview?.layoutIfNeeded()
            }
        }
    }
}
Dimitris answered 23/1, 2020 at 20:39 Comment(1)
this got the job done. thanksSudiesudnor
T
9

Swift 4.2

I create an example for you programmatically:

    var flowHeightConstraint: NSLayoutConstraint?

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white

        view.addSubview(button)
        button.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        button.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        button.widthAnchor.constraint(equalToConstant: 100).isActive = true
        flowHeightConstraint = button.heightAnchor.constraint(equalToConstant: 30)
        flowHeightConstraint?.isActive = true
    }

    @objc func animateButtonTapped() {
        UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: .curveEaseOut, animations: {
            self.flowHeightConstraint?.constant = 100
            self.view.layoutIfNeeded()
        }, completion: nil)
    }

    lazy var button: UIButton = {
       let button = UIButton()
        button.translatesAutoresizingMaskIntoConstraints = false
        button.backgroundColor = .green
        button.addTarget(self, action: #selector(animateButtonTapped), for: .touchUpInside)
        return button
    }()

this line of code create a button an on tapped change height of button with animation.

hope this help :)

Towhead answered 26/2, 2019 at 5:51 Comment(1)
I must say you have solved a very interesting problem that I was having. But now I understand why. Once you set a constraint active on an object you cannot just set it again because it just makes another constraint and the two will conflict. However, assigning a constraint to a variable and then changing it is something that you can do. Thank you again You are my SaviourBabs
N
0

Remove the constraints first. I had constraints in the interface builder, and repositioning worked, and I didn't understand why size changes won't apply. So avoid constraints when manually change the size of a view.

Numismatics answered 9/6, 2023 at 17:41 Comment(0)
I
-2

Use self.view.frame.size.height = 80

Imperium answered 31/1, 2019 at 12:0 Comment(4)
this actually doesn't work because size.height is a get-only property.Bowling
let me know if this line doesn't work. This will change you height as your want itImperium
It's work with bounds e.g., myview.bounds.size.height = 100....!!!Wintery
@EmreA frame.height is a get-only property, size.height is not, not sure why this answer downvoted as it does work.Catt
I
-2

Use of size classes in this case because effective way to handle the size of the screen in the different layout , and good for the command for ios

Ignorance answered 17/8, 2023 at 6:42 Comment(2)
Can you add a code example? Without one, this answer isn't very helpful for someone who isn't already familiar with size classes.Allseed
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Sherrylsherurd

© 2022 - 2024 — McMap. All rights reserved.