Search code examples
iosobjective-cios7

Resizing UIViews on click of a button using Autolayout


I am new to Auto layout constraints. I have 2 views(topView and paintView) on my main view, along with a button on the top right corner of the main view. On loading the view, the topView occupies the whole main view(excluding the button). On click of the button, I want the topView to occupy 70% of the main view and the paintView to occupy the rest(excluding the button). I have set up the the X, Y and top constraints for the topView using storyboard. The paintView and the corresponding constraints have been set up programmatically.

The code I have now is this:

-(void)setupPaintView
{
    UIView *pPaintView = [UIView new];
    [pPaintView setBackgroundColor:[UIColor yellowColor]];
    pPaintView.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:pPaintView];
    self.paintView = pPaintView;
    [self addConstraintsToView];
    //[self setTopViewFrame];

}

-(void)addConstraintsToView
{

    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.paintView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.topView attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0.0]];

    [self.view addConstraint:[NSLayoutConstraint
                              constraintWithItem:self.paintView
                              attribute:NSLayoutAttributeWidth
                              relatedBy:NSLayoutRelationEqual
                              toItem:self.topView
                              attribute:NSLayoutAttributeWidth
                              multiplier:1.0
                              constant:0.0]];

     [self.view addConstraint:[NSLayoutConstraint
                              constraintWithItem:self.topView
                              attribute:NSLayoutAttributeBottom
                              relatedBy:NSLayoutRelationEqual
                              toItem:self.paintView
                              attribute:NSLayoutAttributeTop
                              multiplier:1.0
                              constant:0.0]];


    NSLayoutConstraint *pHeightConstraintTopView = [NSLayoutConstraint
                                             constraintWithItem:self.topView
                                             attribute:NSLayoutAttributeHeight
                                             relatedBy:NSLayoutRelationEqual
                                             toItem:self.view
                                             attribute:NSLayoutAttributeHeight
                                             multiplier:1.0
                                             constant:0.0];

    self.heightconstraintTopView = pHeightConstraintTopView;

    [self.view addConstraint:pHeightConstraintTopView];


    NSLayoutConstraint *pHeightConstraintPaintView = [NSLayoutConstraint
                                                    constraintWithItem:self.paintView
                                                    attribute:NSLayoutAttributeHeight
                                                    relatedBy:NSLayoutRelationEqual
                                                    toItem:self.view
                                                    attribute:NSLayoutAttributeHeight
                                                      multiplier:0.0
                                                    constant:0.0];

    self.heightconstraintPaintView = pHeightConstraintPaintView;

    [self.view addConstraint:pHeightConstraintPaintView];

}

On button click the following method gets called:

-(IBAction)detailBtnClick:(id)sender
{
    if(self.heightconstraintPaintView.constant == 0)
    {

        self.heightconstraintTopView.constant = 0.7*self.view.frame.size.height;
        self.heightconstraintPaintView.constant = 0.3*self.view.frame.size.height;
        [self.view setNeedsUpdateConstraints];
    }
    else
    {
        self.heightconstraintTopView.constant = self.view.frame.size.height;
        self.heightconstraintPaintView.constant = 0;
        [self.view setNeedsUpdateConstraints];
    }

}

When the view loads, the topView acquires the main view's height, which is desired here. But when I click on the button, the topView remains at 100% i.e. it does not resize and neither does the paintView. I am modifying the constant property of the topView and the paintView constraints, but I am not sure that is the correct way to go about it. The constraint here is that the views have to be laid out using Autolayout constraints only. How can I get the views to resize at the click of the button? Any help is welcome.

Thanks to timothykc and others, I have successfully navigated the problem stated above. But I am facing another issue now.When I change the orientation of the simulator to landscape, the paintView remains almost hidden. Following is the code (toggle is a boolean value that decides whether to stretch/shrink the views):

-(IBAction)detailBtnClick:(id)sender
{


        if(self.toggle == FALSE)
        {
            self.topViewHeightConstraint.constant = 0.7*self.bounds.frame.size.height;
            self.heightconstraintPaintView.constant = 0.3*self.bounds.frame.size.height;

            //[self.view layoutIfNeeded];
        }
        else
        {
            self.topViewHeightConstraint.constant = self.view.bounds.size.height;
            self.heightconstraintPaintView.constant = 0;
            //[self.view layoutIfNeeded];

        }

    self.toggle = !self.toggle;


}

The topViewHeightConstraint has been added as a property as indicated by timothykc. This is working properly for the portrait orientation, but is not working properly for landscape, as the height of the topView does not change as desired(70%), meaning that the ratios are not getting handled properly.


Solution

  • I'm going to provide a storyboard driven solution that should help you with other autolayout problems down the road.

    My solution to your specific problem, you've got two views (1 and 2 in diagram below):

    For view 1, pin the view to the left, top, and right of the superview. Then set a height constant. (e.g. 568, the full height of an iphone 5s)

    For view 2, pin it to the left, bottom, and right of the superview. Then pin it to the bottom of view 1.

    Open up the assistant editor view, and here's the key trick--turn the height constraint on view 1 into a nslayoutconstraint property on your VC. You do this by locating the constraint, and then control-dragging onto the VC. (e.g.`


    @property (strong, nonatomic) IBOutlet NSLayoutConstraint *viewHeight;`


    Now you can manipulate this property with an action linked to your button, such as

    - (IBAction)scale:(id)sender {
        self.viewHeight.constant = 397.6; //%70 of 568....
    }
    

    In my example, I change the nslayoutconstraint.CONSTANT manually to an arbitrary value.

    To understand what's happening, you need to know that autolayout is a means for determining the (x coord,y coord,width, height) of any layout object. Warnings occur when xcode cannot ascertain all 4 values...

    In View 1, we give a constraint for Height. X,Y, and Width are extrapolated from the distance to the superview. (if something is 0 from the left and right, then the width fills the whole screen...; if 0 from top and left, then coords must be (0,0))

    In view 2, X must be 0 since distance from left is 0. width whole screen... Height and Y are extrapolated based on the height of View 1!

    So when we mess with height constraint in View 1, it effects the height and Y coord of View 2!

    constraint overview