I am developing an iOS app and ran into a weird problem. I am doing a log of resizing of views and so on view did load, I have an ivar that holds the initial size of the view that I sized in the Interface Builder. The Initial CGFrame rect is: (x = 0, y = 63, width = 284, height = 705). The code I use to hold the initial value is:
filesFrame = self.fileView.frame;
and the only places i touch self.fileView.frame is:
self.fileView.frame = filesFrame;
self.fileView.frame = fullFilesFrame;
These are in two separate spots not right after each other
fullFilesFrame is defined as:
fullFilesFrame = CGRectMake(self.view.frame.origin.x,self.view.frame.origin.y+63,
self.view.frame.size.height,self.view.frame.size.width+63);
When I check my values after I resize back to the initial frame, The frame rect is now origin CGPoint (x=0, y=63)
CGSize (width=28, height=961)
how can this be?
This is the first time I'm dealing with resizing of views, and Im fairly new to iOS as well.
I was going to put this in a comment, but it's too long, so:
One trick I like in these situations is to override setFrame: in the class of the view I'm having trouble with, and set a break point in that overridden method. If you do that then you can see when the frame changes and take a look at the call stack.
It's not always totally straight forward, overriding setFrame:. The frame property can be set directly but it can also be derived from the view's bounds and center, so you might need to look for things setting the view's bounds or the view's center instead of the frame.
Also if the view has a non-identity transform, that will make the frame property behave very strangely. If you are setting non-identity transforms on your view you should just avoid the frame property altogether.
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 have an app with certain number of UIViews. I now need to swap their positions horizontally. For example, there is a UIView called X at the left end and one called Y at the right end. At a button click, I want Y to reside where X resided and X to come to UIView Y's initial position. I figure, I must be able to do this by swapping the NSLayoutConstraints of them both(just a guess). But I can't get this to work. Is this idea possible? What will be the objective-C code for this?
These are the results I got after trying out the first code(almost there, but not completely). I have only applied it to the views KWI and DXB. What I want is a blind swap between KWI and DXB
If the views are of the same size, then it is not much of a problem. Assume your two views X and Y are called xView and yView. You could do something like this:
CGRect xViewFrame = xView.frame;
UIViewAutoresizing xViewResizingConstraints = xView.autoresizingMask;
xView.frame = yView.frame;
xView.autoresizingMask = yView.autoresizingMask;
yView.frame = xViewFrame;
yView.autoresizingMask = xViewResizingConstraints;
If you want this animated, you can put it inside a [UIView animateWithDuration: animations:^{}] block, and it should work. (I haven't tested it out though)
You could also change the CGRect xViewFrame to use CGPoint xViewCenter and swap the centers for same-sized views.
The property autoresizingMask tells the program what to do in the case of a screen resize - whether by a change in orientation, or a result of device screen size or any other reason.
If the views are NOT of the same size, you would have to deal with the proper margins of your views, and ensure that they do not get clipped outside the screen.
Hope this helps.
EDIT
It seems that you are using UILabels either as your view, or a subview of the two views. If this is the case, make sure you also swap the NSTextAlignment of the UILabels. Something like this:
NSTextAlignment xTextAlignment = xView.titleLabel.textAlignment;
xView.titleLabel.textAlignment = yView.titleLabel.textAlignment;
yView.titleLabel.textAlignment = xTextAlignment;
I have created a view using storyboard and i want to move it 20pixels when it is ios 6(guess why:D).
-(void)awakeFromNib
{
if( SYSTEM_VERSION_LESS_THAN(#"7.0") )
{
self.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height );
}
}
This code doesn't work at here but if I put it in a function that is called later it does for the first time but then resets itself to default height.
Why this frame change and how can I make sure it stays as it is?
Any help is welcome...
The reason why your view reverts to its default height is most likely due to auto layout. If you change frames directly with auto layout turned on, then when anything causes the view to redraw itself, the objects will revert to the frames determined by their constraints. So, you should change the size or position of a view using their constraints rather than setting frames (or turn off auto layout).
The reason the code you posted doesn't work in awakeFromNib is because of what I said above. The view hasn't been loaded or drawn yet at that point, so it reverts to its constraint defined frames before you even see it.
I've ran into a weird issue when executing the code below for a UIView with rotation transform applied. What I'm trying to do is remove the view from superview, then insert it under a specific view and restore its frame:
UIView* movedView= [self.views objectAtIndex:newIndex];
center = movedView.center;
CGRect oldFrame = movedView.frame;
//find the layer on top and insert the moved view under that
UIView* coveringView = [self.views objectAtIndex:newIndex-1];
[movedView removeFromSuperview];
[self.view insertSubview:movedView belowSubview:coveringView];
movedView.frame = oldFrame;
I expect that the view would appear in the same place after the operation, but it shifts around, based on how much rotation was applied via CGAffineTransformMakeRotation().
I got the desired behavior by replacing calls that assign frame to calls that assign center property. This got me thinking - how can I understand what's happening to a UIView's frame when it is rotated? Is there a good tutorial or something that can help me conceptually understand how transforms affect UIView's frame?
The -[UIView frame] documentation says this:
Warning: If the transform property is not the identity transform, the value of this property is undefined and therefore should be ignored.
and this:
Changes to this property can be animated. However, if the transform property contains a non-identity transform, the value of the frame property is undefined and should not be modified. In that case, you can reposition the view using the center property and adjust the size using the bounds property instead.
So you might want to avoid thinking about the frame property at all, since your transform is not identity.
After a CGAffineTransform, the property frame of a UIView is simply no longer defined. The docs say "Warning: If the transform property is not the identity transform, the value of this property is undefined and therefore should be ignored."
In my opinion the frame is calculated by the center, the transform and the bounds
just like the formula: frame = f(center,transform,bounds). But I do not know the internal of the f(x)