ios frame and bounds - CGRectMake is offscreen - ios

On iPad following is offscreen when in portrait, why this even when starting up in portrait?
- (void)viewDidLoad
{
[super viewDidLoad];
UIView* imageView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
blue.backgroundColor = [UIColor blueColor];
[[self view] addSubview:imageView];
I have been told that the root view's frame is always the same in portrait and landscape:
- portrait frame orign(x i representing the orign of an UIView)
x0
00
00
Landscape frame orign:
000
x00
But why is CGRectMake(0,0 .. not up in the right corner in portrait?
Thanks in advance

The bounds and the frame can change when you rotate the device. Let's take a Single View Application template as an example, add orientation support and run it on the iPhone. In portrait:
bounds = (0, 0, 320, 460) // 460 compensates for 20p status bar
frame = (0, 20, 320, 460) // status bar adjustment
x0
00
00
In landscape:
bounds = (0, 0, 480, 300) // now 20p is taken from "height"
frame = (20, 0, 300, 480) // status bar adjustment
x00
000
Origin is always top-left corner, regardless of orientation.

Related

How big in points is an imag in a UITextfield

I have a UITextfield like so:
UITextfield *name = [[UITextField alloc] initWithFrame:CGRectMake(30, 210, 100, 34)];
name.borderStyle = UITextBorderStyleRoundedRect;
name.backgroundColor = [UIColor whiteColor];
name.font = [UIFont systemFontOfSize:12];
name.leftView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"icon.png"]];
If I have the following UITextfield setup, how many points is the UIImage suppossed to be? Is it 34 by 34 or a little smaller? I know, if it's 34 points by 34 points I will have to make .pngs 34x34, 68x68 and 92x92 for x, 2x, and 3x pixel displays.
From the documentation:
The left overlay view is placed in the rectangle returned by the
leftViewRectForBounds: method of the receiver. The image associated
with this property should fit the given rectangle. If it does not fit,
it is scaled to fit. If you specify a control for your view, the
control tracks and sends actions as usual.
It means that you can change size of leftView.
On iOS 8.3 "leftViewRectForBounds:" value is based on the size of the leftView. If I use the leftView with size: 300x300 then the frame will be (0, -125, 300, 300). If I use the view with size 30x30, then the frame will be (0, 10, 30, 30).
A frame of my textField is (0.0, 0.0, 300.0, 50.0).
[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"icon.png"]];
It's frame will be x=0, y=0, width = width of the image, height = height of the image
You can set any image of any resolution according to your requirement. Please also add the following line before the last line of your code for the image to be visible.
[name setLeftViewMode:UITextFieldViewModeAlways];

Set a UIView in a fixed proportional position from the Right Edge of screen iOS

Say, I have a UIImageView or any object and I set it in a UIView as subView with CGRectMake like this:
UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 30)];
UIImageView *imgView = [[UIImageView alloc]initWithFrame:CGRectMake(266, 0, 30, 30)];
[imgView setImage:[UIImage imageNamed:[self.imageDicKey objectAtIndex:section]]];
[headerView addSubview:imgView];
Here I set the position of my imgView like CGRectMake(266, 0, 30, 30)]; and it counts it's position form the left x position (which is 266). What If I want to set my imgView's position from right side of the screen? So that,in different width of iPhone screen it shows in a same ratio position. But which will be counted it's position from right edge.
Thanks a lot in advanced.
I would recommend not hard coding the exact positions and instead calculating the x and y. That way it will help for different sized screens so it's not an exact position and rather it's based upon the views' size.
UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 30)];
CGFloat padding = 20; // amount for padding
CGSize size = CGSizeMake(30, 30); // size of imageView
CGPoint startPos = CGPointMake(headerView.frame.size.width - padding - size.width, 0); // starting position for imageView
UIImageView *imgView = [[UIImageView alloc]initWithFrame:CGRectMake(startPos.x, startPos.y, size.width, size.height)]; [imgView setImage:[UIImage imageNamed:[self.imageDicKey objectAtIndex:section]]]; [headerView addSubview:imgView];
Well, since the ImageView's width is 30 and the x coordinate is 266 from the left side, it makes the x coordinate from the right side 296.

Adding subviews programmatically positions them weirdly

I have a view in which I want to add multiple subviews, however when I add them, they get positioned in positions where I didn't set the frame. The x coordinate is correct, but the y is quite off.
Using the Interface Builder it went quite smooth, just drag them in and send the correct frame and origin. However I don't appear to be able to set the origin; I get expression is not assignable when I try view.frame.origin = CGPointMake(x, y), and setting the x and y coordinates directly gives me the same error.
Does this happens because subviews cannot overlap programmatically without setting a special attribute (that I'm missing)?
Edit: The views are being set in the initWithStyle method of a UITableViewCell.
Edit 2: Added code within initWithStyle method.
// Initialize images
self.imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"image"]];
self.anImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"anImage"]];
self.anotherImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"anotherImage"]];
// Set imageview locations
self.imageView.frame = CGRectMake(0, 0, 300, 54);
self.anImageView.frame = CGRectMake(20, 53, 16, 52);
self.anotherImageView.frame = CGRectMake(179, 43, 111, 53);
To avoid expression is not assignable, you have to set the entire frame at once, either using
view.frame = CGRectMake(x, y, width, height)
or
CGRect frame = self.view.frame;
frame.origin.x = newX;
self.view.frame = frame;
Most likely you are setting the frames in the viewDidLoad method. The problem here is that you are setting the frame before the viewControllers frame has been resized based on the constraints of the app.
Try moving your frame setting into the method viewWillAppear and see if that fixes your problem.
Edit: Because you are doing this in a cell, and not in a viewController you would do something like the following:
In initWithStyle:reuseIdentifier
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
self.customView = [[UIView alloc] initWithFrame:CGRectZero];
}
return self;
}
Then override layoutSubviews to actually set the views frame
- (void)layoutSubviews
{
[super layoutSubviews];
self.customView.frame = CGRectMake(x, y, width, height);
}
As far as the "expression is not assignable" warning, this is because you cannot just set a views origin without setting the height and width. Use:
view.frame = CGRectMake(x, y, width, height);
If you want to keep the same width and height without having to hard code it do something like
view.frame = CGRectMake(x, y, view.frame.size.width, view.frame.size.height);

View Frame differs IOS 4.3 vs IOS 5.1 -- Why?

In laying out CALayer objects in the main view of a viewController I am seeing a discrepancy between IOS 43. and 5.1
I am running in landscape mode. I want a CALayer object 40 pts wide, showing at the top left -- butted up against the nav bar and the full height of the screen (less the nav bar). Status bar is disabled. I calculate the height of the layer as the height of the view less the height of the nav bar.
In viewDidLoad of my viewController I have the following code....
[[UIApplication sharedApplication] setStatusBarHidden:YES];
CGRect viewFrame = self.view.frame;
float navBarHeight = self.navigationController.navigationBar.frame.size.height;
CGRect f = CGRectMake( 0, navBarHeight, 40, viewFrame.size.height - navBarHeight);
leftLayer = [[CALayer alloc] init];
leftLayer.frame = f;
leftLayer.backgroundColor = [UIColor greenColor].CGColor; // for debug
[self.view.layer addSublayer:leftLayer];
When I run this on 5.1 viewFrame = (0, 0, 480, 288) and navBarHeight = 32. When I run this on 4.3 viewFrame = (0, 0, 480, 320) and navBarHeight = 32. I've tried the same comparison in portrait mode and there is no discrepancy between OS versions.
navBarHeight also seems wrong -- because my green CALayer object has about 12 pts of white space between it and the nav bar. What am I doing wrong?
I have better luck with using the viewWillAppear method to adjust frames because the view has been sized for the orientation by then. Do you have the same issue in that method?

When would a UIView's bounds.origin not be (0, 0)?

When would an UIView's bounds.origin not be (0, 0)?
This paragraph was helpful to me:
IMPORTANT!! Bounds X and Y, the origin, are for moving inside the
View. For eample X+5, moving 5pix to the left of the frame's origin
meaning draw all content within this View to the left 5pix of frame's
origin. It doesn't do anything to itself, it is what being drew on it
that get affected.
But it describes only the case when I had set the value of bounds.origin myself.
In what other cases the value of bounds.origin != (0, 0)?
View's frame determines its location in superview. View's bounds determines its subviews locations. That means, if you change view's bounds, its location won't be changed, but all of its subviews location will be changed.
Positive width and height is like you draw a view from upper-left to bottom-right, while negative value is from bottom-right to upper-left. So
frame1 = CGRectMake(100, 100, -50, -50)
is totally identical with
frame2 = CGRectMake(50, 50, 50, 50).
And in fact, if you init a view with frame1, it will AUTOMATICALLY CHANGED to frame2.
But the bounds.origin of the views are not identical. Bounds.origin indicates the point that you "draw" the view, so all subviews frames will originate at this point.
For example, in Landscape iPhone 6, we have:
UIView *leftView = [[UIView alloc] initWithFrame:CGRectMake(50, 50, 275, 275)];
leftView.backgroundColor = [UIColor greenColor];
[self.view addSubview:leftView];
UIView *rightView = [[UIView alloc] initWithFrame:CGRectMake(667-50, 375-50, -275, -275)];
rightView.backgroundColor = [UIColor blueColor];
[self.view addSubview:rightView];
And we got:
We will find that rightView's frame is automatically changed to positive value, which is (342, 50, 275, 275), but its bounts.origin = (-275,-275).
And we add subviews:
UIView *leftSubview = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 30, 30)];
leftSubview.backgroundColor = [UIColor grayColor];
[leftView addSubview:leftSubview];
UIView *rightSubview= [[UIView alloc] initWithFrame:CGRectMake(0, 0, 30, 30)];
rightSubview.backgroundColor = [UIColor grayColor];
[rightView addSubview:rightSubview];
So the bounds makes rightView's subview follows the origin which we init rightView.
If we change the bounds of rightView equals to leftView:
rightView.bounds = leftView.bounds;
Then the two subViews location is the same, we lost the information that rightView's width and height are negative.
And we change the bounds of leftView instead of rightView:
CGRect bounds = leftView.bounds;
bounds.origin = CGPointMake(50, 50);
leftView.bounds = bounds;
We can see, its subview's frame.origin is offset by bounds.origin(using minus, not plus).
To conclude:
view.bounds determines all its subview's location(offset by bounds.origin), while bounds will not affect its own location in its superview.
If you init a view with negative width and height, it will automatically changed to positive(which won't change the location), but its bounds.origin indicates the point that you start to "draw" the view.
A UIScrollView's bounds.origin will not be (0, 0) when its contentOffset is not (0, 0).
The bounds.origin will be negative if you initialize a view with negative width/height.
For example, if you did
UIView* v = [[UIView alloc] initWithFrame:CGRectMake(5, 5, -10, -20)];
the frame would be:
origin = {
x = -5,
y = -15
},
size = {
width = 10,
height = 20
}
bounds:
origin = {
x = -10,
y = -20
},
size = {
width = 10,
height = 20
}
center:
x = 0,
y = -5
try it for yourself!
(edited again because I can’t delete my original answer after it was accepted—credit for this goes to ian, who posted a more thorough answer below:)
In most cases this won’t happen. If you initialize your view with a negative width and/or height, you’ll get an origin with a negative X of the width and/or negative Y of the height.

Resources