I am trying to set the origin of the frame programmatically.
Method1:
button.frame.origin.y = 100;
Method 2:
CGRect frame = button.frame;
frame.origin.y = 100;
I tried method 1 but it is not working(showing an error saying Expression is not assignable). Method 2 is working. Why is this so?
Need guidance on what I am doing right.
The reason you can't do method #1 is because a frame's individual properties are read-only. However, the entire frame itself is writable/assignable, thus you can do method #2.
You can even do tricks like this:
CGRect newFrame = button.frame;
newFrame.origin.y += 100; // add 100 to y's current value
button.frame = newFrame;
You know
button.frame.origin.y return a value.
if you are using this one so you will get this error...
Expression is not assignable.
button.frame.origin.y = 100;
So this is correct way
CGRect frame = button.frame;
frame.origin.y = 100;
otherwise you can do like this...
button.frame = CGRectMake(button.frame.origin.x, 100, button.frame.size.width, button.frame.size.height)
It's because if you were able to directly change a frame's origin or size, you would bypass the setter method of UIView's frame property. This would be bad for multiple reasons.
UIView would have no chance to be notified about changes to it's frame. But it has to know about these changes to be able to update it's subviews or redraw itself.
button.frame.origin.y = 100;
equals to the following call:
[button getFrame].origin.y = 100;
in which [button getFrame] gives you the copied CGRect.
You are trying to set a variable of a structure of a structure. There is no pointer from the UIView to the structure (as it is a basic C struct so can't be pointed). hence, copied instead.
So basically, you are copying the structure and setting it. But, that just doesn't work like that.
Related
Im new to IOS development , so when i change the width of a UITextFeild dynamically i want the button below to shift up .
i tried using the constrains but it doesn't seem to shift dynamically .
(IBAction)selectStatus:(id)sender {
CGRect frameRect = _textViewDevices.frame;
frameRect.size.height = 10;
self.textViewDevices.frame = frameRect;
any good example of how to achieve that ?
I want to achieve something like the Relative positioning in android .
current box before any action
Try calling layoutIfNeeded after the modifications:
- (IBAction)selectStatus:(id)sender {
CGRect frameRect = _textViewDevices.frame;
frameRect.size.height = 10;
self.textViewDevices.frame = frameRect;
[self.view layoutIfNeeded];
}
If you have a height constraint on the text view, try to set its constant instead of setting the frame height:
- (IBAction)selectStatus:(id)sender {
self.textViewHeightConstraint.constant = 10;
[self.view layoutIfNeeded];
}
Programmatically when the first violet field changes in height, to make all the below views stay next to it, you should update the frame.origin.y properly.
So, for example, the status label should be reframed like this
CGRect frame = statusLabel.frame;
frame.origin.y = firstField.origin.y + firstField.size.height + 5;
statusLabel.frame = frame;
And the same for all below views (I've supposed 5 pixels of space between views)
generally when I want to move a label to the right 20px, or increase just the width of a view, I go through one of the following avenues
label.frame = CGRectMake(label.frame.origin.x+20, label.frame.origin.y, label.frame.size.width, label.frame.size.height);
or
CGRect viewFrame = view.frame;
viewFrame.x += 20;
view.frame = viewFrame;
I don't particularly like the amount of code that goes into either variation and was hoping you guys knew a shortcut that I hadn't discovered
A better method of moving to the right is the CGRectOffset macro:
label.frame = CGRectOffset(label.frame, 20.0f, 0.0f);
I find that this a clearer expression of the intent of my code.
Just to add:
Here's an article with nice CGRect tricks (Shrinking, Expanding, Edge Insetting, Intersecting)
Whenever possible I use center to modify the origin:
myView.center = CGPointMake(150, 150);
Or even better:
myView.center = anotherView.center;
To modify the size frame or bounds are the only way to go. You can use the various CGRect functions in CGGeometry to express the transformation at a higher level.
I'm creating compatibility for iOS6 for an app made by someone else. I'm used to using making buttons/UI elements with autoresizing masks but I don't really know how they work when you're creating the button programatically.
For example:
- (UIButton*) createSampleButton {
UIButton* b = createSampleViewButton(CGRectMake(67, 270, 191, 45),
#"btn_shuffle",
#"btn_shuffle_active",
self,
#selector(sampleAction));
b.autoresizingMask = UIViewAutoresizingFlexibleTopMargin;
[self attachButton:b];
return b;
}
How can I change these buttons such that they'll be placed according to some scale/margin instead of arbitrarily choosing points until everything "looks right" ?
I was thinking of something like:
- (UIButton*) createSampleButton {
CGFloat height = self.bounds.size.height;
CGFloat bottomBound = 80;
UIButton* b = createSampleViewButton(CGRectMake(67, height-bottomBound, 191, 45),
#"btn_shuffle",
#"btn_shuffle_active",
self,
#selector(sampleAction));
[self attachButton:b];
return b;
}
This would guarantee me that the button is placed 80 points from the bottom of the screen every time right? Is there a more graceful or purposeful way of doing this?
The masks are the same as when created in IB or code. The thing you want to make sure to do in code though is make sure the frames are set properly proportioned once. In your case, yes you do want UIViewAutoResizingFlexibleTopMargin, and setting the correct y-value on the origin in terms of y = parentView.bounds.size.height - (x points as you described), is all you need to do.
EDIT:
According to your updated question, maybe this will help you. If the button has a constant size, set the frame to that size with CGPointZero as the origin when you create the button. If a UIView owns the button, then put this code in layoutSubviews. If a UIViewController owns the button, replace self.bounds with self.view.bounds and put this in view(Will/Did)LayoutSubviews (Assuming iOS5+).
// Aligning the button at it's current x value, current size, with its bottom border margin pizels from the bottom of the parent view.
CGFloat margin = 10;
CGRect buttonFrame = button.frame;
buttonFrame.origin.y = self.bounds.size.height - buttonFrame.size.height - margin;
button.frame = buttonFrame;
Also, define constant values at the top of the implementation file. Feel free to create convenience methods for readability (if you find this more readable and not doing too much on one line) such as
CGRect CGSetYInRect(CGFloat y, CGRect rect)
...
button.frame = CGSetYInRect(self.bounds.size.height - button.frame.size.height - margin, button.frame);
Use AutoResizing when appropriate to avoid explicit logic in layoutSubviews.
When you move to iOS 6 + only, use AutoLayout.
I'm playing around with UIbuttons, just to get a feel on what can really be done with them. I have only one problem so far:
How do I modify the position of a UIButton?
- (IBAction)buttonClicked:(id)sender
{
UIButton *senderB = sender;
CGPoint position = senderB.frame.origin;
CGSize size = senderB.frame.size;
senderB.frame = CGRectMake(position.x,position.y + 10,size.width,size.height);
}
The above works just fine, however, creating a new CGrect for every time I want to simply change one seems rather inefficient to me.
Is there any way for me to directly set the values of senderB.frame.origin.x, etc?
I usually do it like this:
CGRect buttonFrame = button.frame;
buttonFrame.origin.y += 10;
button.frame = buttonFrame;
Nope. Notice that 'someview.frame' returns a CGRect by value, not by reference or pointer or whatever. That's why you get the 'Lvalue required' error.
However, setting the frame like you're doing is plenty fast.
The frame property is read only. What you can do is copying the current frame with
CGRect btFrame = senderB.frame;
btFrame.origin.x += 10;
senderB.frame = btFrame;
Greetings all -
I am having an issue assigning a value to an existing UIScrollView. In response to an Orientation change, I am re-orienting and sizing the ScrollView and the UIImageViews I have contained within. I can set the UIScrollView's frame:
CGRect wideThumbFrame = CGRectMake(0.0, 530.0, 1024, 190.0);
thumbScrollView.frame = wideThumbFrame;
But I can't seem to adjust ONLY the bounds:
[thumbScrollView bounds].size.height = 190.0;
Compiler says "LValue required as left operand of assignment". Is not thumbScrollView my LValue?!?!? What am I missing here?
You can't do that, since bounds is a property, you have to assign it, to a local variable first, ie
CGRect rect = thumbScrollView.frame;
rect.size.height = 190.0;
thumbScrollView.frame = rect;
...bounds.size.height is part of a CGRect structure.
You should assign it just like you do with the .frame CGRect structure property.
You can adjust the size by assigning a CGRect to the bounds property.
thumbScrollView.bounds = CGRectMake(thumbScrollView.bounds.origin.x, thumbScrollView.bounds.origin.y, thumbScrollView.bounds.size.width, 190.0);