I have a rectangular UIView whose edges are constrained to its superview. I need to rotate this view by 90 degrees, but then update its constraints so it stays correctly constrained to the superview. If I do
self.overlayView.transform = CGAffineTransformMakeRotation(M_PI * 0.5);
The view rotates, but the width and height stay fixed the wrong way round. Do I need to break the constraints and set them again so that the top is constrained to the superview's left, the left is constrained to the superview's bottom and so on?
Autolayout plays with the frame to do its thing. As per the docs, the frame is undefined when the transform is set to something other than the identity.
Based on this, it would appear that this is fixed in iOS8 (and indeed they reference the above docs, noting that as of iOS8 setFrame method gets called on the transformed view).
Related
I have a UIView buttonView and gave it an equal heights constraint to the super UIView with a 0.4 multiplier. The frame is adjusted correctly but the subviews of buttonView are not visible. However, when I click on the position where the buttons are supposed to be then the actions triggers.
This does not happen when I change the buttonViews constraint to be a fixed height.
I can get more into details if you want but has anyone run into something similar?
EDIT
There should be two buttons where the white space underneath the label is. When I click on the white space the timer runs but the button is not visible.
I took a look at the project and the issue I saw in a couple places was that auto layout and manual frame transformations are both used, which can be tricky. A couple specific things I saw that you will probably need to modify in order for the view to adapt and render correctly at different sizes / orientations:
1) The CustomAudioLearn view loads a view from a xib and adds it as a subview. However, it does not set constraints on this subview to make sure that the subview always hugs the edges of the parent view. So changing the size of the CustomAudioLearn view through auto layout in the storyboard results in the the xib-based subview always staying the same size. You should either add constraints to the subview or override layoutSubviews() in CustomAudioLearn and include self.customView.frame = self.bounds and self.customViw.layoutIfNeeded() in there. Also, I would suggest removing the line self.customView.translatesAutoresizingMaskIntoConstraints = false
2) Similarly, the RecordButtonView sets its corner radius on awakeFromNib(), but after layout happens, that's no longer the right radius. So you should again consider overriding layoutSubviews() or similar location to adjust the radius every time the layout is updated.
3) Lastly, the superview of the RecordButtonView in the storyboard is set to a height constraint of 70 with a priority of 1000. If you want the RecordButtonView to expand for the space available, you should reduce the priority of that height constraint so that the proportional width of the RecrodButtonView and the 1:1 aspect ratio take priority in determining the height of the superview. Otherwise, it will always be 70 points, or there will be conflicting constraints.
The problem was that I set the rounded corners to half of my frame's width. The radius got so big that it completely hide the view. I changed it so that after the bounds are set I change the corner radius. Sorry for confusion but thanks for any help!
In the .gif below, I have a view that is the same size as the device screen (with the beige background). That view has a subview (with the purple background), which I've positioned using Auto Layout. It's been set to be the same width as its superview, with a constant value of -18, and its CenterX value set to be the same as its superview, so it's centered with 9pts of space on each side.
Inside of that view, is a UILabel, also positioned using Auto Layout. It's been set to be the same width as its superview, with a constant value of -20, and its CenterX the same as its superview, so it's centered with 10pts of space on each side.
When the user taps on the purple view, I want to perform a multi-step animation, where the first step involves the purple view expanding to be the same width as its superview.
I'm doing this using the following code:
[UIView animateWithDuration:3.0 animations:^{
[constraint setConstant:0.0];
[view.superview layoutIfNeeded];
}];
The problem (as seen in the first .gif), is that the UILabel immediately shifts right, and then gradually comes back to center as the animation plays out.
Incorrect animation:
In this next .gif, however, the animation performs correctly. I'm using the same code to perform the animation, but instead of making the UILLabel be the same width as its superview (minus the 20pts), I hard-code the width to be a static value, using 0 as the constraint multiplier, and 357 as the constant value.
Correct animation:
This accomplishes the effect that I'm looking to achieve, but I'd rather not hard-code the width of the UILabel (plus I'm very curious why it's acting this way).
Any ideas?
Working on a project in iOS 8 using storyboard and auto layout:
In storyboard, specified constraints for this view and its subviews
In code, in response to touch events, I'm going to change this view's size by setting its frame
To make both 1 and 2 warning free, I'm doing the following when first changing its size with code:
[theView removeConstraints:theView.constraints];
theView.translatesAutoresizingMaskIntoConstraints = YES;
theView.frame = CGRectMake(0,0,width,height);
If not doing the first line, Xcode will complain a whole bunch about constraint conflicts, however adding this line will remove all its subview's constraints as well. So my question is: is there way to just remove this uiview's constraints but not its subview, say a button on it still wants to center its self relative to this view's size and position?
First, you don't need to resize the view by setting frame otherwise what is the point of keeping the constraint at first place. You could have position that by simply having a correct initial frame.
Secondly, you have a mis-conception about "TO-WHOM" a constraint has been applied to.
say a button on it still wants to center its self relative to this view's size and position?
When you apply a position related constraint to a view you normally apply it to it's superview. Means if you want to position a subview in the horizontal centre of a view then the constraint is added on view not on the subview. That's why when you called a removeContraints: message on view that position constraint was removed and now your subview isn't bound to any constraint. However the width and height constraints are applied to subviews itself.
To solve this you need to make IBOutlets for constraint that you need to modify, which in your case should be width, height, horizontal x and top constraint; and then change the constant values for them respectively.
theView.widthConstraint.constant = newValue;
My app is built on a UIScrollview with a UIImageView subview and various other subviews. When I rotate to landscape, I change the contentSize of the scroll view and resize the image view proportionally to take advantage of the increased horizontal width. The means the height increases as well to maintain the proportions.
My question is, in the case of the blue subview shown, what do I need to do to reposition it such that it maintains it relative position after rotation, given that it's superview is no longer the same size? I have experimented with convertRect:toView: and converPoint:toView:, but I can't seem to get it quite right.
Are you using auto layout? If so, in many cases, the judicious use of constraints can keep that subview in the right place and right size, even as you go from landscape to portrait. But you'd have to share more details about what else is on this view for us to be more specific.
If not using auto layout, you generally can set the view's autosizing mask so it moves to the correct location for you. But in the case of a scroll view subview, you might have your view controller can respond to viewWillLayoutSubviews, updating the contentSize of the scroll view and the frame of the subview to move, accordingly:
- (void)viewWillLayoutSubviews
{
// update the contentSize of the scroll view for the width of the root view, but I'm assuming the
// height won't change
self.scrollView.contentSize = CGSizeMake(self.view.bounds.size.width, self.scrollView.contentSize.height);
// adjust the frame of the subview you want to move so that it is a certain offset from the bottom
// left corner of the scroll view's `contentSize` (in this case, 10 points from bottom, 10 points from right)
self.subviewToMove.frame = CGRectMake(self.scrollView.contentSize.width - self.subviewToMove.frame.size.width - 10,
self.scrollView.contentSize.height - self.subviewToMove.frame.size.height - 10,
self.subviewToMove.frame.size.width, self.subviewToMove.frame.size.height);
}
The specifics vary based upon details of (a) whether you're using autolayout or not; (b) whether you're creating this subview programmatically or not; and (c) what other content you have in your view and whether the change from portrait to landscape and back results in any change in the vertical height of the scroll view.
To reposition a view, you update its frame. The frame property is of type CGRect, which is a combination of size (CGSize) and origin (CGPoint). If size of your blue view doesn't change, then only origin should be updated.
iOS coordinate system starts from top left corner:
For your blue view you calculate it's origin from the bottom right corner, that is
origin = contentSize - blueViewSize - padding
Do this separately for x and y coordinate, make CGRect with updated origin, and update blue view's frame.
UP: This is how you do it manually, but you can (and better should) let UIKit reposition subviews for you automatically -- learn about autoresizing and autolayout in Xcode's Interface Builder, and Developer manuals
Say I have two UIViews. One is a UIImageView of a frame, and one is a UIImageView of a picture. I want the picture to stay inside the frame regardless of screen size using autolayout. The picture is NOT a subview of the frame - they're just two imageviews that I want to remain superimposed in the right proportions.
I can't pin the heights, because I want them to change when rotating (for arguments sake say I pinned the frames bottom to the bottom of the main view). I can't make the heights equal, because they're not, the picture should be smaller. I can pin the horizontal spacing, but that will just make sure the picture's x,y are right, but not height and width.
I want it so that if for whatever reason I change the frames size (via transform, for example), the picture will follow.
Can I do this in autolayout, or is coding required?
You can make constraints pinning the centerX and centerY of the two views to be the same. Then you can make constraints to specify the width and the height. It depends on how big your frame is. You might try
picture.width = frame.width - 20
or
picture.width = 0.8 * frame.width
(and do something similar for the height).
If you want them both to rotate, you need to either set the rotation transform on both views (not recommended) or put them both in the same superview and set the rotation transform on that superview (recommended). Remember, if a view has a transform set then you can't make a constraint that goes from within that view to something outside that view. They are like separate worlds.