I'm trying to adjust the origin.y value of a UIView's frame. The problem that I'm running into is that the elements aren't moving with the frame with negative offsets. When I give the origin.y a positive value, it works perfectly: the view drops down, leaving black above, and the elements shift down as well. With a negative value, on the other hand, the view moves correctly, leaving black below, but the elements don't change position. I feel like the problem might be with autolayout, and the elements remaining trapped by the top of the screen, not the top of the UIView.
Any ideas on how to fix this?
Related
I am trying to retrieve rect value of a class in ViewDidAppear. The button is in UITableViewCell. All values return correct except frame.origin.y. It returns -1.5. I am wondering what might cause that.
CGRect customRect = CGRectMake(self.favoriteButton.frame.origin.x, self.favoriteButton.frame.origin.y, self.favoriteButton.frame.size.height, self.favoriteButton.frame.size.width) ;
Origin.y is defined in an unintuitive.
First, moving down is positive and up is negative (aka larger numbers means the view will appear lower on the screen).
Second, the origin is relative to the top left corner of the immediate parent view (in your case the cell). If origin.y really is -1.5 then the top of your button is just one and a half points above the top of your table view cell, (which sounds likely). If your origin.y really should be 400-ish points it means for it to appear in your UITableViewCell your tableViewCell would have to be over 400 points tall.
This could be the case but I'm wondering if what you're looking for is not origin.y, but how far bellow the top of the root view (self.view in your view controller) the top of your button is. If so try:
CGPoint originInRootview = [self.view convertPoint:CGPointZero fromView:self.favoriteButton];
CGFloat theNumberIThinkYouWant = originInRootview.y
There are two things
1-) You said that it is in TableViewCell so it returns correct. Because you put button inside a view(TableViewVell container view), button gets it coordinates from container view not from superview.
2-) If TableViewCell is big enough and starts from y=0 and you are sure it is wrong and must be something like 400. Try to get the rect value at viewDidLayoutSubviews
All values return correct except frame.origin.y. It returns -1.5. I am wondering what might cause that.
Applying a transform to the view can cause it's frame property to be invalid. From the documentation for UIView's frame property:
Warning
When the value of this property is anything other than the identity
transform, the value in the frame property is undefined and should be
ignored.
So, if you're not seeing what you expect, compare your view's transform to CGAffineTransformIdentity.
I want to create a vertical UISlider and exactly fit it into an existing container view that is sized and placed from a .xib file using autoLayout. But I simply cannot get it to work and I have Googled my fingers bloody.
The closest I have gotten creates a slider that is too long and extends off the screen.
Am I putting the code in the wrong place?
I am putting my code in "layOutSubviews"
Some Points of interest:
1.Per Apple's docs, the view's "frame" is not valid after the transformation and should not be set.
2.The frame of the slider is set to the future parent's dimensions before the transformation (with x and y swapped).
3.The transformed view appears to maintain its bounds in the pre-transformation coordinate frame. i.e. After the 90 degree transformation, the width and height of the transformed view's bounds appear to be swapped.
This code doesn't work. The slider looks right except that it extends off the bottom of the screen. The slider bounds and even the frame (which Apple says is not valid) seem to match the bounds and frame of the container view. The slider doesn't even stay within its own bounds.
[super layoutSubviews];
CGRect trigLevelSliderFrame=self.trigLevelSliderContainer.bounds;
trigLevelSliderFrame.size.height=self.trigLevelSliderContainer.bounds.size.width;
trigLevelSliderFrame.size.width=self.trigLevelSliderContainer.bounds.size.height;
UISlider *mySlider=[[UISlider alloc] initWithFrame:trigLevelSliderFrame];
self.trigSlider=mySlider;
[mySlider release];
self.trigSlider.transform=CGAffineTransformMakeRotation(-M_PI_2);
CGPoint center=CGPointMake(self.trigLevelSliderContainer.bounds.size.width/2,self.trigLevelSliderContainer.bounds.size.height/2);
self.trigSlider.center=center;
[self.trigLevelSliderContainer addSubview:self.trigSlider];
There is no problem with this code to add and rotate the slider. The problem is that the the code must be put into the "layoutSubviews" method of the slider's parent view; instead I had it in the "layoutSubviews" of the parent view of the parent view of the slider. When my original code executed the slider's parent view had not yet been laid out and did not yet have the correct dimensions.
During "layoutSubviews" of a view, the subviews have not yet been laid out and so their bounds are not yet valid. I needed to wait until later in the layout process to get the bounds of the parent view and transform the slider to fit.
In the end, I put the code to add the slider and transform the slider in the "viewDidAppear" of the top level view controller. This was the same code as in the original question - just in a different place.
I'm trying to zoom in and out an UIView, and rearrange it content to look similar for both states: zoomed and normal.
This picture shows the default state (the view that I'm going to zoom has orange color and has 5 UIImageViews) :
When I press "Zoom in" button I change orange view frame:
_page.frame = self.view.bounds;
And I'm getting the following result:
But the goal that I want to achieve is something similar to this (same result if I would scale the view):
It means that I must change frames for each subview, but it could be complicated when view would have many objects on it.
What I'm asking for are some hints or methods how can I get desired result without accessing subviews.
There are be hacks to do this, but the proper way would be to use auto layout. You don't have to access any subviews and will be able to do it in the storyboard/IB.
If you use auto layout, you can actually create constraints which will pin the following attributes of the subviews:
Pin the top subview's top space and leading space to the container
Pin the all but the last subviews' vertical distance to its nearest neighbour and leading space to container
Pin the last subview's top vertical space to its nearest neighbour and bottom space to container and leading space to container
Set constraints for height and width but set the priority to low
In addition to setting the frame (which just changes the size of the view) you want to change the transform (scale the view) Try something like:
_page.transform = CGAffineTransformMakeScale(2.0, 2.0)
You'll probably want to calculate the scale factor based on the old view size and the new size.
I understand the difference between frames and bounds I think, bounds are to the view's local coordinate system, while frames are to the superviews.
With scrollviews however, I'm a little confused.
When I have a UIImageView in a UIScrollView and pinch to zoom it larger, it seems the frame grows larger (width and height) increases the width and height of the corresponding UIImage as well.
However, it seems like the bounds of the UIImageView don't change at all.
Why is this? How do scroll views work in regards to all of this? I've read multiple questions and checked the documentation but this explanation is eluding me.
How does zooming in a UIScrollView affect its contents? Does it just change the frame of the zooming view but somehow not the bounds?
See the explanation in my book:
The scroll view zooms by applying a scaling transform to the scalable view; therefore the frame of the scalable view is scaled as well. Moreover, the scroll view is concerned to make scrolling continue to work correctly: the limits as the user scrolls should continue to match the limits of the content, and commands like scrollRectToVisible:animated: should continue to work the same way for the same values. Therefore, the scroll view automatically scales its own contentSize to match the current zoomScale. (You can actually detect this happening by overriding setContentSize in a UIScrollView subclass: you can see the scroll view adjusting its own content size as you zoom.)
Basically (though that is not quite clear from the above quotation) we have no business concerning ourselves with the frame of the scalable view - or any view - that has a non-identity transform applied to it, which is exactly the case here. That fact is made very clear by the Apple documentation on UIView. Thus you should not be looking at the frame - only the transform. The frame value that your are reading changes purely as a side-effect of the transform change.
As for the bounds of the scalable view - obviously the bounds do not change; that is the whole point of how a transform works. It maintains a constant center and bounds, so that subviews and drawing continue to operate correctly within the frame-of-reference coordinates despite the transform. My book talks you through an understanding of this as well.
On the other hand, the scroll view's own bounds can certainly change their origin, not least because that is exactly and identically what it means for a scroll view to scroll. Scrolling is a change of bounds origin, plain and simple. And this would not be surprising during zooming, because, as I just said, the content size has changed, so the content may be repositioned in order to keep displaying it coherently as you zoom.
I have a UITextview with a small UIViewController on top of it, whose view is a UITextView (It's red in the screenshots).The small red textView is the subView of the bigger textView under it.
Heres what it looks like. The small textView is red and is in the shape small square (let's say 50 x 50). It is purposely cut of the edge of the screen. That's how it's positioned.
This is in portrait. When the device is rotated to landscape, I'd like the small textView to move to the left so it's no longer on top of the bigger textView, but it's still a subview. So I make a new CGRect that's the same size as the small textView's frame, and then change the x coordinate of the origin. Then reassign the small textViews frame to the altered one. Here's how:
-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
if (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft || toInterfaceOrientation ==UIInterfaceOrientationLandscapeRight) {
CGRect smallFrame = self.smallTextView.view.frame;
smallFrame.origin.x -=20.0;
self.smallTextView.view.frame = smallFrame;
}
}
Heres the result:
Obviously this is incorrect. I don't even touch the textView's frame size, but those attributes are changed! What's stranger is that if I NSLog the size dimensions, they are the same as they were before the rotation, 50 x 50.
A few observations:
This only happens when the small red textView is a textView. I could replace that view with a UIImageView and this problem does no occur.
I'm fairly certain this is happening because it's a subview of another UITextView. Why? How? No clue.
I'm starting to think the problem lies in how the big superview UITextView is rotating, and somehow the subview small red textView is being effected some way. Even though "Autoresize Subviews" in interface builder is not checked for either textViews. The large superview textView is constrained to a specific width and height in IB with constraints. So the size doesn't really change there.
I'd really appreciate some help with this. I've been looking at it for a few days and just can't pinpoint a cause or solution.
Solved this a while ago. Assigning the textView's center property instead of its frame solves the problem.
CGPoint center = self.smallTextView.view.center;
center.x -=20.0;
self.smallTextView.center = center;
Even still, assigning the textView's frame with a different origin still causes the bug, even in iOS 7. But assigning the center works just fine.