I have a set of views that represent cards, that should all fit into it's superview:
I want the container view to be aligned near the center of the screen, so I added these constraints for it:
- Leading space with it's container;
- Top space with the layout guide (the view controller is inside a navigation controller);
- Center horizontally in the container;
- Center vertically in the container.
This way the view that contains all the other small views is somehow pinned, and in landscape mode it gets more tiny so that it's subviews should shrink a lot vertically.
I added on all the subviews inside the view these constraints:
- Same width;
- Same height;
- Leading, trailing, top and bottom space with any neighbor view.
To make it clearer this last step I'll also add this picture:
Now the first problem is that when the iphone simulator gets rotated to landscape, all the views are too much shrunk:
And I understand why: the top and vertical space from neighbors has a standard value, which maybe in landscape mode is too high relatively to the available vertical space, so they're too short. But how do I specify a constraint that takes a space in percentage (e.g.: vertical separation: 5% of the view's width)? The best to do in my case is to resize the subviews in the same way as if they were scaled to fit inside the new subview's bounds. How do I do that?
Another problem is that the app crashes if I rotate it to landscape and then to portait upside down:
2014-03-17 23:40:04.736 Matchismo[10284:60b] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
(
"<NSLayoutConstraint:0x109226d90 V:|-(NSSpace(20))-[PlayingCardView:0x109224330] (Names: '|':UIView:0x109226610 )>",
"<NSLayoutConstraint:0x109226e80 V:[PlayingCardView:0x109224330]-(NSSpace(8))-[PlayingCardView:0x109225080]>",
"<NSLayoutConstraint:0x109227150 V:[PlayingCardView:0x109225080]-(NSSpace(8))-[PlayingCardView:0x109225700]>",
"<NSLayoutConstraint:0x1092277e0 V:[PlayingCardView:0x109225d80]-(NSSpace(20))-| (Names: '|':UIView:0x109226610 )>",
"<NSLayoutConstraint:0x109227830 PlayingCardView:0x109225d80.height == PlayingCardView:0x109225700.height>",
"<NSLayoutConstraint:0x109227970 PlayingCardView:0x109225d80.height == PlayingCardView:0x109224330.height>",
"<NSLayoutConstraint:0x109227ba0 PlayingCardView:0x109225d80.height == PlayingCardView:0x109225080.height>",
"<NSLayoutConstraint:0x109227ce0 V:[PlayingCardView:0x109225700]-(NSSpace(8))-[PlayingCardView:0x109225d80]>",
"<NSLayoutConstraint:0x10922a0e0 UIView:0x109228f40.centerY == UIView:0x109226610.centerY + 32>",
"<NSLayoutConstraint:0x10922a130 V:[_UILayoutGuide:0x109229020]-(14)-[UIView:0x109226610]>",
"<_UILayoutSupportConstraint:0x109224980 V:[_UILayoutGuide:0x109229020(64)]>",
"<_UILayoutSupportConstraint:0x109221ff0 V:|-(0)-[_UILayoutGuide:0x109229020] (Names: '|':UIView:0x109228f40 )>",
"<NSAutoresizingMaskLayoutConstraint:0x10923eef0 h=--& v=--& V:[UIView:0x109228f40(271)]>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x109227ce0 V:[PlayingCardView:0x109225700]-(NSSpace(8))-[PlayingCardView:0x109225d80]>
Break on objc_exception_throw to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
(lldb)
But I can't see any conflicting constraints.
Solution
Exploiting ReedD's answer, I decided to use a collection view. This is the solution I came around with (in my case I need to use 16 cards in a 4x4 collection view, but the code can be rearranged to work in a generic way):
- (NSInteger) collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return 4;
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 4;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell* cell= [collectionView dequeueReusableCellWithReuseIdentifier:@"reuseIdentifier" forIndexPath:indexPath];
<Initialize the card view and add it to the cell>
return cell;
}
- (CGSize) collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return CGSizeMake(collectionView.contentSize.width/4.0 -5.0,collectionView.contentSize.height/4.0 -5.0);
}
- (UIEdgeInsets) collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
return UIEdgeInsetsMake(5, 5, 5, 5);
}