I thoght that it's frame's oringin decides the position of the view. But when I change the center property like so
myView.center = CGPointMake(myView.center.x - 20, myView.center.y);
my view will move 20 units to left. I want to change the center point to make some rotations relative to that point.
If you want to change the rotation point, set the anchorPoint instead. The anchorPoint is on the layer in the view, but the rotation applied to the view still uses the anchor point.
From the Apple API for UIView:
The center is specified within the
coordinate system of its superview.
Setting this property changes the
values of the frame properties
accordingly.
Changing the frame rectangle
automatically redisplay the receiver
without invoking the drawRect: method.
If you want the drawRect: method
invoked when the frame rectangle
changes, set the contentMode property
to UIViewContentModeRedraw.
So essentially, changing either center, frame, or bounds will reposition and resize the view appropriately, changing the other two properties accordingly.
Related
Observe the following screenshot:
How do I anchor UIView a few pixel off the middle point using Autoresizing Mask so that it is always 20px to the left of the middle point?
I have tried setting the autoresizingMask property to UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin and it's not really doing it.
I did manage to do it if I wrap the view in another bigger view that fills the entire screen and doesn't resize at all. But is there a way to do it without an additional view?
Autoresizing masks don't handle this case very well, as you've already discovered. They work great if you want to keep something a fixed distance from its superview or proportionally resizing/repositioning somewhere in the middle. You can do a surprising amount with just those options, but off-center anchoring is not something you can do easily
If you want do this with autoresizing masks, you'll need to put your box inside another empty UIView, one that is in a more convenient position for autoresizing masks. It will look like this.
Here's what you've got right now:
center
|
|---------------------------------------------------| <-- The main parent view
|-----| <-- your view
What you want is this:
center
|
|---------------------------------------------------| <-- The main parent view
|--------------------| <-- The new view, centered in the parent
|-----| <-- your view
The new view should be completely transparent, have a fixed width, and a flexible distance from both sides of the parent view. It should be wide enough to fully contain the off-center box, and no wider. If it is positioned exactly in the center of the main parent view, it will stay centered no matter what happens to the size of the parent view.
Then add your box as a subview of the new view, with a fixed width and fixed distance from the left edge of the parent. Now, using only autoresizing masks, your view will stay where you want it.
A simpler option might be to override -layoutSubviews on your view, or -viewDidLayoutSubviews on your controller (available iOS 5.0 and later) and just manually position the view. But you asked how to do it with autoresizing masks, so that's what you got. Without adding an extra view, there's no way to use autoresizing masks to get the positioning behavior you want.
I guess the best solution is to set center property to:
myview.center = CGPointMake(self.view.frame.size.width/2-20, myview.center.y);
And set up it in willRotate method.
Not exactly an answer, more of an avenue for exploration. You can try playing with the layer-level property anchorPoint. Setting it to (1.0, 0.5) means the layer's position will be defined by its right edge. In that case centered would mean the right edge is centered. Set flexible left margin and flexible right margin and it might stay left of the center.
To get it exactly 20p left of the center, just set the anchorPoint to 20p right of the center of the view. (But anchorPoint units are a fraction of the size of the layer, so do some math to find the right value.)
I'm not sure if it will work. I'm not sure what the effects are of mixing layer-level positioning with autoresizing.
I have created a subclass of UIView and am trying to scale and move the view from within its m file but am running into some problems. When I used the command:
self.frame = CGRectMake(self.frame.origin.x-10,self.frame.origin.y-10,self.frame.size.width/2,self.frame.size.height/2); the object moves location but does not resize (the view only contains a few UIImageViews). In the xib file of the sub class I have the options checked to Clip Subviews and to Autoresize Subviews but neither appears to happen. Any ideas as to why the view will not resize with this command and how I could get it to resize.
Resizing your view is not the same as scaling it. Think of your view as a picture frame. What you're doing above is moving the frame, and also moving the lower right corner (you're shortening the frame's wood bars) - but that does not automatically shrink the picture.
There are four ways of resizing a view with subviews:
Let the superview clips its subviews (by setting view.clipsToBounds = YES): Subviews do not resize or relayout, but only show in the area that is inside the frame.
Let the superview not clip its subviews (by setting view.clipsToBounds = NO): Changing superview size does not have any visual effect on subviews, they also show outside of the frame.
Give the subviews autoresizingMasks: The subviews do not change size, but they relayout according to their autoresizing mask (for instance, a subview may always stay 10 px off the lower right corner of the frame, or may always span exactly the width of the frame.) Note that this does not necessarily automatically scale subview content. Set subview.contentMode accordingly.
Scale the superview: By setting superview.transform = CGAffineTransformScale(superview.transform, 0.5, 0.5), you shrink the superview and all its subviews (you essentially zoom out). Note that this makes superview.frame undefined, which means you shouldn't use that anymore. It can also make things a bit blurry.
You could also "manually" change all the subviews, but that kind of defeats the purpose of having a nice view hierarchy.
As MishieMoo said, temporarily set the backgroundColor of your superview to something visible. This will very likely show you that your view is indeed changing.
So i have a View and a scroll view inside that view. I call a
[View setFrame:CGRectMake(55,70,260,420)];
i put a
NSLog(#"%f %f",scrollview.frame.origin.x, scrollview.frame.origin.y);
before and after the setFrame and it reads 6,112 and then 6,172. 112 is correct, i have no idea where the 60 comes from. i searched 60 in my implementation file, and there is nothing that could affect the y at all. is there some rule with doing a setframe when there is a view inside that view?
Thanks
If you take a look at the UIView reference, the frame property states
frame
The frame rectangle, which describes the view’s location and size in
its superview’s coordinate system.
#property(nonatomic) CGRect frame
Discussion
This rectangle defines the size and position of the view in its
superview’s coordinate system. You use this rectangle during layout
operations to size and position the view. Setting this property
changes the point specified by the center property and the size in the
bounds rectangle accordingly. The coordinates of the frame rectangle
are always specified in points.
So i guess when you NSLog the frame for scrollview it is displayed based on the coordinates of the superview. The second NSLog shows different because the superview's coordinate system has changed.
I fixed this by making the scrollview in my code instead of doing it through the XIB. the scrollview is created after the setFrame and addSubView of the parent View
I created a class in my project and this class is a subclass of another class; I want place this subview in the principal view, I reduced x and y to make it smaller, but it always appears at the top left, how can I set it in other position?
Would be easier to answer if you posted some code. Most likely, you need to modify the frame property of your view. frame is a rectangle (CGRect) that determines the position and size of your view in the coordinate system of its superview. The bounds property is similar but expresses origin and size in the coord system of itself (e.g. origin is 0,0).
For other layout tips, look at the autoresizingMask and contentMode properties of views. In fact, read up on views in general. The Apple docs are good and lots of stuff here about them.
Is there a way to a bounding box for a view so that its subviews cannot leave the view?
I currently have UIImageViews which I move around, scale, rotate etc and they are able to leave the view area.
How does one set the superview to bound/hold the subviews within it?
How else can this be done. I currently detect the origin of the image this works to the point that the image moves until it reaches this origin, when it does, the image is stuck.
I use gestureRecognizers and this origin technique only works for panning/moving an image.
Any suggestions?
If you want to stop a view's subviews from being drawn outside its borders, you need to set its clipsToBounds property to YES. (See the UIView class reference for details.)
If you want to stop your views from being in certain positions, don't move them there! It's your code that's putting them where you don't want them to be. If you're using a gesture recogniser, presumably you have a method that responds to gestures by adjusting the frame of a view - put some conditions on this movement that prevent it from happening when you don't want it.
When you write these conditions, bear in mind that a view's origin is relative to its superview. For example, say you have a view controller with a view that takes up the whole screen of the device, and inside that a box that starts at 0, 100, and inside that some squares and circles and squiggly shapes that the user can move around. If you examine containerBox.bounds.origin, you'll find that it's 0, 100, but if you want to put a square in the top left corner of the box, you need to get its frame and set the origin to 0, 0. Something to look out for.
I didn't follow your explanation of the 'origin technique'. If you paste your code, I might be able to help.