0

I have an app that requires me to have image views and labels to laid out differently depending on portrait or landscape orientation.

For example, in portrait mode, I have 2 UIImageViews on top and bottom that share the screen evenly. In landscape mode, the 2 UIImageViews are side by side. How can this be done using storyboard in Xcode 6?

Things I have tried:

  1. Settings constraints on the views in storyboard with size classes. I set the base values for my 2 imageviews in w:Any h:Any, then moved to w:Compact h:Regular and set constraints for portrait view.Then I moved to w:Any h:Compact, moved the 2 imageviews side by side and set constraints for landscape view. Then I get conflicts in w:Compact h:Compact because of the constraints I have applied for and landscape and portrait orientation. I think it's because I moved the image views around for landscape orientation before settings the constraints that caused this problem.
  2. Using 2 separate view controllers and have portrait view controller switch to landscape view controller when orientation changes using NSNotificationCenter and performSegueWithIdentifier to push the landscape view controller on top of my portrait view controller. This problem is that there's lots of data to be passed(lot of imageviews and labels).

Is the a way to use only one view controller and a way to rearrange the imageviews/labels and apply new constraints on them when the orientation changes? Is -(void)viewDidLayoutSubviews{} where I put the code to rearrange the image views? Can someone point me in the right directions? Thanks!

Hima
  • 1,249
  • 1
  • 14
  • 18
iamarnold
  • 229
  • 3
  • 12

1 Answers1

-1

For this case I recommend to make layout programmatically via code. Here is example: https://dl.dropboxusercontent.com/u/48223929/Test.zip

- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    [self layoutImageViewsForViewSize:self.view.frame.size];
}

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
    [self layoutImageViewsForViewSize:size];
}

- (void)layoutImageViewsForViewSize:(CGSize)size
{
    // Portrait mode
    if (size.height > size.width) {
        self.imageView1.frame = CGRectMake(0, 0, size.width, size.height / 2);
        self.imageView2.frame = CGRectMake(0, size.height / 2, size.width, size.height / 2);
        // Landscape mode
    } else {
        self.imageView1.frame = CGRectMake(0, 0, size.width / 2, size.height);
        self.imageView2.frame = CGRectMake(size.width / 2, 0, size.width / 2, size.height);
    }
}

For autolayout:

- (void)layoutImageViewsForViewSize:(CGSize)size
{
    // Portrait mode
    [self.view removeConstraints:self.view.constraints];
    if (size.height > size.width) {
        NSString *heightLayoutFormatString = [NSString stringWithFormat:@"V:|[_imageView1(%.0f)][_imageView2(%.0f)]|", size.height / 2, size.height / 2];
        [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:heightLayoutFormatString options:0 metrics:nil views:NSDictionaryOfVariableBindings(_imageView1, _imageView2)]];
        [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"H:|[_imageView1(%.0f)]|", size.width] options:0 metrics:nil views:NSDictionaryOfVariableBindings(_imageView1)]];
        [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"H:|[_imageView2(%.0f)]|", size.width] options:0 metrics:nil views:NSDictionaryOfVariableBindings(_imageView2)]];

    // Landscape mode
    } else {
        NSString *widthLayoutFormatString = [NSString stringWithFormat:@"H:|[_imageView1(%.0f)][_imageView2(%.0f)]|", size.width / 2, size.width / 2];
        [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:widthLayoutFormatString options:0 metrics:nil views:NSDictionaryOfVariableBindings(_imageView1, _imageView2)]];
        [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"V:|[_imageView1(%.0f)]|", size.height] options:0 metrics:nil views:NSDictionaryOfVariableBindings(_imageView1)]];
        [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"V:|[_imageView2(%.0f)]|", size.height] options:0 metrics:nil views:NSDictionaryOfVariableBindings(_imageView2)]];
    }
    [self.view setNeedsUpdateConstraints];
}

Another solution for autolayout - make your custom subclass of UIView, which contains 2 image views, and layout it programmly without constraints - just setFrame. And then add this custom UIView to your storyboard

Vitalii Gozhenko
  • 9,220
  • 2
  • 48
  • 66
  • Is it possible to use storyboard with the above code instead of xib? – iamarnold Dec 06 '14 at 20:08
  • Yes, but there will be problem: you need disable autolayout. And it will be disabled for whole storyboard. Another solution - use storyboard and autolayout, but not change frame directly, only change constraints – Vitalii Gozhenko Dec 06 '14 at 20:12
  • If I use storyboard and autolayout, do I have to change the constraints programmatically? I tried moving the moving the imageviews in the view controller on storyboard(for side to side and top & bottom) and applying constraints on different size classes before and ended up with lots of conflicts. Is it possible to programmatically apply a set of constraints for landscape and portrait separately? – iamarnold Dec 06 '14 at 20:33
  • Updated answer for autolayout – Vitalii Gozhenko Dec 06 '14 at 20:38
  • I access my imageviews with self.imageView1 and self.imageView2 and got the error: *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unable to parse constraint format: self is not a key in the views dictionary. V:|[self.imageView1(334)][self.imageView2(334)]| – iamarnold Dec 06 '14 at 20:52
  • I got it working, but when I try to add button in the center of imageView1, I get an error saying unable to simultaneously satisfy constraints. – iamarnold Dec 08 '14 at 05:02
  • [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"H:|-(%.0f)-[Button(75)]|", (size.width/2 - self.Button.frame.size.width/2)] options:0 metrics:nil views:views]]; [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"V:|-(%.0f)-[Button(75)]|", (size.height/4 - self.Button.frame.size.height/2)] options:0 metrics:nil views:views]]; – iamarnold Dec 08 '14 at 05:10
  • your problem is that you need to make correct bind view variable to visual format. Here is simple example: constraintsWithVisualFormat:@"V:|_button|": options:0 metrics:nil views:NSDictionaryOfVariableBindings(_button)] – Vitalii Gozhenko Dec 08 '14 at 07:00
  • due to your crash report, I assume you have something like: constraintsWithVisualFormat:@"V:|self.button|": options:0 metrics:nil views:NSDictionaryOfVariableBindings(self.button)] – Vitalii Gozhenko Dec 08 '14 at 07:01