Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSLayoutConstraint and setting a view X pixels from top in portrait and Y pixles from top in landscape

Want a table view to appear 300 pixels down from the top while in portrait and about 175 pixels from the top while in landscape.

i can't seem to figure out the VFL logic i need.

like image 202
Padin215 Avatar asked Jan 09 '13 22:01

Padin215


2 Answers

Like many autolayout problems, yes, you can do what you're asking, but it's far from obvious. If I really needed precisely 300pt or 175pt, I might, too, be tempted to adjust the top constraint on rotation.

But if you want to know how to do this without handling rotation events, you could:

  1. Set a required minimum top margin of 175;

  2. Set a lower priority preferred top margin of 300 (which won't be satisfied in landscape); and

  3. Less obviously, you also need a required minimum height too (so that in landscape, it will know not to satisfy the lower priority request to make the top margin 300).

You could, for example, use (obviously replace my bottom margin of 5 with whatever makes sense for you, but adjust the minimum height of the tableview accordingly):

@"V:|-(>=175)-[tableView(>=120)]-5-|"

combined with:

@"V:|-(300@500)-[tableView]"

(Obviously, you would have constraints for the horizontal axis, too, but I omit those for the sake of brevity.)

This is, admittedly, vaguely unappealing, to have to precisely specify the minimum table height, too, but I saw no other way to tell autolayout under what situations it should gracefully not satisfy the optional top space of 300pt.


You can also do this with using the the y = mx + b formula of constraintWithItem. Yes, I know you asked how to do this with Visual Format Language, but if you use constraintWithItem, you don't have to specify the minimum table height, but rather you can just set the top margin like so:

constraint = [NSLayoutConstraint constraintWithItem:self.tableView
                                          attribute:NSLayoutAttributeTop
                                          relatedBy:NSLayoutRelationEqual
                                             toItem:self.tableView.superview
                                          attribute:NSLayoutAttributeBottom
                                         multiplier:multiplier
                                           constant:constant];

Clearly, the trick is how to determine the multiplier and constant so that you get 300 pt in portrait and 175 pt in landscape. Doing a little algebra, you will see that you can calculate those values as follows:

CGFloat multiplier = (300.0 - 175.0) / (superviewPortraitHeight - superviewLandscapeHeight);
CGFloat constant = 175.0 - superviewLandscapeHeight * multiplier;

(And, again, I'll assume that you'll specify the other constraints so that the tableview is not ambiguously defined, e.g. set the left, right, and bottom constraints, which can be done in Visual Format Language.)

like image 73
Rob Avatar answered Nov 18 '22 14:11

Rob


I don't think there's anyway to set this up to do specific distances without changing it in code in a rotation callback method. If you make an IBOutlet to the constraint in IB (lets call it con1), and have that constraint with the initial value of 300, then in a rotation callback method you can just change that constant.

self.con1.constant = 175;

After Edit:

this works:

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {

    if (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft || toInterfaceOrientation == UIInterfaceOrientationLandscapeRight) {
        con1.constant = 175;
    }else{
        con1.constant = 300;
    }
}
like image 3
rdelmar Avatar answered Nov 18 '22 14:11

rdelmar