I am creating a category on UIView to make programmatically positioning and sizing my views easier. I want to create a method that will center a given view horizontally or vertically in its superview. So I can do something like the following:
Category
- (void)centerHorizontally {
self.center = CGPointMake(self.window.superview.center.x, self.center.y);
}
- (void)centerVertically {
self.center = CGPointMake(self.center.x, self.window.superview.center.y);
}
Use
UIView *v = [[UIView alloc] initWithFrame:CGRectMake(0,0,100,100)];
[v centerHorizontally];
However, this doesn't seem to be working. What is incorrect about my solution?
You need to add the view to a parent view before you can center it.
UIView *v = [[UIView alloc] initWithFrame:CGRectMake(0,0,100,100)];
[someOtherView addSubview:v];
[v centerHorizontally];
And your category is incorrect. Don't get the window involved. You need to base it on the superview's size:
- (void)centerHorizontally {
self.center = CGPointMake(self.superview.bounds.size.width / 2.0, self.center.y);
// or
self.center = CGPointMake(CGRectGetMidX(self.superview.bounds), self.center.y);
}
- (void)centerVertically {
self.center = CGPointMake(self.center.x, self.superview.bounds.size.height / 2.0);
// or
self.center = CGPointMake(self.center.x, CGRectGetMidY(self.superview.bounds));
}
Related
I need to calculate the visible CGRect of a UIView subview, in the coordinates of the original view. I've got it working if the scale is 1, but if one of the superviews or the view itself is scaled (pinch), the visible CGRect origin is offset slightly.
This works when the scale of the views is 1 or the view is a subview of the root view:
// return the part of the passed view that is visible
// TODO: figure out why result origin is wrong for scaled subviews
//
- (CGRect)getVisibleRect:(UIView *)view {
// get the root view controller (and it's view is vc.view)
UIViewController *vc = UIApplication.sharedApplication.keyWindow.rootViewController;
// get the view's frame in the root view's coordinate system
CGRect frame = [vc.view convertRect:view.frame fromView:view.superview];
// get the intersection of the root view bounds and the passed view frame
CGRect intersection = CGRectIntersection(vc.view.bounds, frame);
// adjust the intersection coordinates thru any nested views
UIView *loopView = view;
do {
intersection = [loopView convertRect:intersection fromView:loopView.superview];
loopView = loopView.superview;
} while (loopView != vc.view);
return intersection; // may be same as the original view frame
}
When a subview is scaled, the size of the resultant view is correct, but the origin is offset by a small amount. It appears that the convertRect does not calculate the origin properly for scaled subviews.
I tried adjusting the origin relative to the X/Y transform scale but I could not get the calculation correct. Perhaps someone can help?
To save time, here is a complete test ViewController.m, where a box with an X is drawn on the visible part of the views - just create a reset button in the Main.storyboard and connect it to the reset method:
//
// ViewController.m
// VisibleViewDemo
//
// Copyright © 2018 ByteSlinger. All rights reserved.
//
#import "ViewController.h"
CG_INLINE void drawLine(UIView *view,CGPoint point1,CGPoint point2, UIColor *color, NSString *layerName) {
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:point1];
[path addLineToPoint:point2];
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [path CGPath];
shapeLayer.strokeColor = color.CGColor;
shapeLayer.lineWidth = 2.0;
shapeLayer.fillColor = [UIColor clearColor].CGColor;
shapeLayer.name = layerName;
[view.layer addSublayer:shapeLayer];
}
CG_INLINE void removeShapeLayers(UIView *view,NSString *layerName) {
if (view.layer.sublayers.count > 0) {
for (CALayer *layer in [view.layer.sublayers copy]) {
if ([layer.name isEqualToString:layerName]) {
[layer removeFromSuperlayer];
}
}
}
}
CG_INLINE void drawXBox(UIView *view, CGRect rect,UIColor *color) {
NSString *layerName = #"xbox";
removeShapeLayers(view, layerName);
CGPoint topLeft = CGPointMake(rect.origin.x,rect.origin.y);
CGPoint topRight = CGPointMake(rect.origin.x + rect.size.width,rect.origin.y);
CGPoint bottomLeft = CGPointMake(rect.origin.x, rect.origin.y + rect.size.height);
CGPoint bottomRight = CGPointMake(rect.origin.x + rect.size.width, rect.origin.y + rect.size.height);
drawLine(view,topLeft,topRight,color,layerName);
drawLine(view,topRight,bottomRight,color,layerName);
drawLine(view,topLeft,bottomLeft,color,layerName);
drawLine(view,bottomLeft,bottomRight,color,layerName);
drawLine(view,topLeft,bottomRight,color,layerName);
drawLine(view,topRight,bottomLeft,color,layerName);
}
#interface ViewController ()
#end
#implementation ViewController
UIView *view1;
UIView *view2;
UIView *view3;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
CGFloat width = [UIScreen mainScreen].bounds.size.width / 2;
CGFloat height = [UIScreen mainScreen].bounds.size.height / 4;
view1 = [[UIView alloc] initWithFrame:CGRectMake(width / 2, height / 2, width, height)];
view1.backgroundColor = UIColor.yellowColor;
[self.view addSubview:view1];
[self addGestures:view1];
view2 = [[UIView alloc] initWithFrame:CGRectMake(width / 2, height / 2 + height + 16, width, height)];
view2.backgroundColor = UIColor.greenColor;
[self.view addSubview:view2];
[self addGestures:view2];
view3 = [[UIView alloc] initWithFrame:CGRectMake(10, 10, width / 2, height / 2)];
view3.backgroundColor = [UIColor.blueColor colorWithAlphaComponent:0.5];
[view1 addSubview:view3]; // this one will behave differently
[self addGestures:view3];
}
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
[self checkOnScreen:view1];
[self checkOnScreen:view2];
[self checkOnScreen:view3];
}
- (IBAction)reset:(id)sender {
view1.transform = CGAffineTransformIdentity;
view2.transform = CGAffineTransformIdentity;
view3.transform = CGAffineTransformIdentity;
[self.view setNeedsLayout];
}
- (void)addGestures:(UIView *)view {
UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc]
initWithTarget:self action:#selector(handlePan:)];
[view addGestureRecognizer:panGestureRecognizer];
UIPinchGestureRecognizer *pinchGestureRecognizer = [[UIPinchGestureRecognizer alloc]
initWithTarget:self action:#selector(handlePinch:)];
[view addGestureRecognizer:pinchGestureRecognizer];
}
// return the part of the passed view that is visible
- (CGRect)getVisibleRect:(UIView *)view {
// get the root view controller (and it's view is vc.view)
UIViewController *vc = UIApplication.sharedApplication.keyWindow.rootViewController;
// get the view's frame in the root view's coordinate system
CGRect frame = [vc.view convertRect:view.frame fromView:view.superview];
// get the intersection of the root view bounds and the passed view frame
CGRect intersection = CGRectIntersection(vc.view.bounds, frame);
// adjust the intersection coordinates thru any nested views
UIView *loopView = view;
do {
intersection = [loopView convertRect:intersection fromView:loopView.superview];
loopView = loopView.superview;
} while (loopView != vc.view);
return intersection; // may be same as the original view
}
- (void)checkOnScreen:(UIView *)view {
CGRect visibleRect = [self getVisibleRect:view];
if (CGRectEqualToRect(visibleRect, CGRectNull)) {
visibleRect = CGRectZero;
}
drawXBox(view,visibleRect,UIColor.blackColor);
}
//
// Pinch (resize) an image on the ViewController View
//
- (IBAction)handlePinch:(UIPinchGestureRecognizer *)recognizer {
static CGAffineTransform initialTransform;
if (recognizer.state == UIGestureRecognizerStateBegan) {
[self.view bringSubviewToFront:recognizer.view];
initialTransform = recognizer.view.transform;
} else if (recognizer.state == UIGestureRecognizerStateEnded) {
} else {
recognizer.view.transform = CGAffineTransformScale(initialTransform,recognizer.scale,recognizer.scale);
[self checkOnScreen:recognizer.view];
[self.view setNeedsLayout]; // update subviews
}
}
- (IBAction)handlePan:(UIPanGestureRecognizer *)recognizer {
static CGAffineTransform initialTransform;
if (recognizer.state == UIGestureRecognizerStateBegan) {
[self.view bringSubviewToFront:recognizer.view];
initialTransform = recognizer.view.transform;
} else if (recognizer.state == UIGestureRecognizerStateEnded) {
} else {
//get the translation amount in x,y
CGPoint translation = [recognizer translationInView:recognizer.view];
recognizer.view.transform = CGAffineTransformTranslate(initialTransform,translation.x,translation.y);
[self checkOnScreen:recognizer.view];
[self.view setNeedsLayout]; // update subviews
}
}
#end
So you need to know the real visible frame of a view that is somehow derived from bounds+center+transform and calculate everything else from that, instead of the ordinary frame value. This means you'll also have to recreate convertRect:fromView: to be based on that. I always sidestepped the problem by using transform only for short animations where such calculations are not necessary. Thinking about coding such a -getVisibleRect: method makes me want to run away screaming ;)
What is a frame?
The frame property is derived from center and bounds.
Example:
center is (60,50)
bounds is (0,0,100,100)
=> frame is (10,0,100,100)
Now you change the frame to (10,20,100,100). Because the size of the view did not change, this results only in a change to the center. The new center is now (60,70).
How about transform?
Say you now transform the view, by scaling it to 50%.
=> the view has now half the size than before, while still keeping the same center. It looks like the new frame is (35,45,50,50). However the real result is:
center is still (60,50): this is expected
bounds is still (0,0,100,100): this should be expected too
frame is still (10,20,100,100): this is somewhat counterintuitive
frame is a calculated property, and it doesn't care at all about the current transform. This means that the value of the frame is meaningless whenever transform is not the identity transform. This is even documented behaviour. Apple calls the value of frame to be "undefined" in this case.
Consequences
This has the additional consequences that methods such as convertRect:fromView: do not work properly when there are non-standard transforms involved. This is because all these methods rely on either frame or bounds of views, and they break as soon as there are transforms involved.
What can be done?
Say you have three views:
view1 (no transform)
view2 (scale transform 50%)
view3 (no transform)
and you want to know the coordinates of view3 from the point of view of view1.
From the point of view of view2, view3 has frame view3.frame. Easy.
From the point of view of view1, view2 has not frame view2.frame, but the visible frame is a rectangle with size view2.bounds/2 and center view2.center.
To get this right you need some basic linear algebra (with matrix multiplications). (And don't forget the anchorPoint..)
I hope it helps..
What can be done for real?
In your question you said that there is an offset. Maybe you can just calculate the error now? The error should be something like 0.5 * (1-scale) * (bounds.size) . If you can calculate the error, you can subtract it and call it a day :)
Thanks to #Michael for putting in so much effort in his answer. It didn't solve the problem but it made me think some more and try some other things.
And voila, I tried something that I'm certain I had done before, but this time I started with my latest code. It turns out a simple solution did the trick. The builtin UIView convertRect:fromView and convertRect:toView worked as expected when used together.
I apologize to anyone that has spent time on this. I'm humbled in my foolishness and how much time I have spent on this. I must have made a mistake somewhere when I tried this before because it didn't work. But this works very well now:
// return the part of the passed view that is visible
- (CGRect)getVisibleRect:(UIView *)view {
// get the root view controller (and it's view is vc.view)
UIViewController *vc = UIApplication.sharedApplication.keyWindow.rootViewController;
// get the view's frame in the root view's coordinate system
CGRect rootRect = [vc.view convertRect:view.frame fromView:view.superview];
// get the intersection of the root view bounds and the passed view frame
CGRect rootVisible = CGRectIntersection(vc.view.bounds, rootRect);
// convert the rect back to the initial view's coordinate system
CGRect visible = [view convertRect:rootVisible fromView:vc.view];
return visible; // may be same as the original view frame
}
If someone uses the Viewcontroller.m from my question, just replace the getVisibleRect method with this one and it will work very nicely.
NOTE: I tried rotating the view and the visible rect is rotated too because I displayed it on the view itself. I guess I could reverse whatever the view rotation is on the shape layers, but that's for another day!
I want 2 views to act as if they were "one view" - meaning if view 1 moves on the 'x' n pixels I want view 2 to move on the x axis the same amount of pixels (in any arbitrary direction) - without having to calculate all sorts of offsets and so on.
I thought using the new UIDynamicAnimator would be a great candidate so I tried this
UIView *v1 = [[UIView alloc] initWithFrame:CGRectMake(320-150, 150, 150, 100)];
v1.backgroundColor = [UIColor blackColor];
[self.view addSubview:v1];
self.v1 = v1;
UIView *v2 = [[UIView alloc] initWithFrame:CGRectMake(self.view.bounds.size.width,
0,
self.view.bounds.size.width,
self.view.bounds.size.height)];
v2.backgroundColor = [UIColor redColor];
[self.view addSubview:v2];
self.v2 = v2;
UIPanGestureRecognizer *p =
[[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(pan:)];
[v1 addGestureRecognizer:p];
self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
UIAttachmentBehavior *att =
[[UIAttachmentBehavior alloc] initWithItem:self.v1
offsetFromCenter:UIOffsetZero
attachedToItem:self.v2
offsetFromCenter:UIOffsetMake(0,
self.v1.center.y - self.v2.center.y)];
att.damping = 0;
[self.animator addBehavior:att];
self.att = att;
-(void)pan:(UIPanGestureRecognizer *)gesture {
if(gesture.state == UIGestureRecognizerStateChanged) {
CGPoint p = [gesture locationInView:self.view];
// move only on x axis but keep on same y point
self.v1.center = CGPointMake(p.x, self.v1.center.y);
[self.animator updateItemUsingCurrentState:self.v1];
}
}
But they are interacting with each other - the little view tilts and changes its rotation and y location.
I would have hoped - only on 1 axis and "hard" connected to each other - any way to do this?
Given that no further details about the context is provided, I assume that you want the two views' relative distance to each other to remain constant. If this is indeed the case, I am not sure why you consider UIDynamicAnimator. Instead, you could embed the two views in a containerview and then manipulate the origin of the container instead of the two views individually. By embracing this approach you don't have to worry about re-calculating the origin of one view when moving the other, and vice versa.
self.containerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 100)];
UIView *v1 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
UIView *v2 = [[UIView alloc] initWithFrame:CGRectMake(100 0, 100, 100)];
[self.containerView addSubview:v1];
[self.containerView addSubview:v2];
// now, changing the origin of containerView will move v1 and v2 simultaniously
- (void)pan:(UIPanGestureRecognizer *)gesture
{
if(gesture.state == UIGestureRecognizerStateChanged)
{
CGPoint p = [gesture locationInView:self.view];
// move only on x axis but keep on same y point
self.containerView.center = CGPointMake(p.x, self.containerView.center.y);
}
}
As an alternative, you could use autolayout and relate the two views in such way that your requirements are met. Then, when moving one of the views, the other will move accordingly. However, if you are actually using UIDynamics to manipulate views in that view hierarchy, autolayout is not the way to go since autolayout and UIDynamics tend to interfere with each other.
Set v1 origin 'X' to v2 origin 'X in panGesture.
-(void)pan:(UIPanGestureRecognizer *)gesture {
CGPoint point = [gesture locationInView:self.view];
CGRect boundsRect = CGRectMake(15, 40, 285, self.view.frame.size.height-60);
if (CGRectContainsPoint(boundsRect, point))
{
v1.center = point;
}
v2.frame = CGRectMake(v1.frame.origin.x, v2.frame.origin.y, v2.frame.size.width, v2.frame.size.height);
}
One easy way to solve this could be to add one of the views as a subview to the other or add both as subviews to a new view, which is only used to group the views. Depending on how you intend to use the views this might not be applicable to you though.
If you want to make one view a subview of the other but want the subview to be visible outside the bounds of the superview you can set clipToBounds to NO on the superview.
I am trying to rotate the rectangle around the circle. So far after putting together some code I found in various places (mainly here: https://stackoverflow.com/a/4657476/861181) , I am able to rotate rectangle around it's center axis.
How can I make it rotate around the circle?
Here is what I have:
OverlaySelectionView.h
#import <QuartzCore/QuartzCore.h>
#interface OverlaySelectionView : UIView {
#private
UIView* dragArea;
CGRect dragAreaBounds;
UIView* vectorArea;
UITouch *currentTouch;
CGPoint touchLocationpoint;
CGPoint PrevioustouchLocationpoint;
}
#property CGRect vectorBounds;
#end
OverlaySelectionView.m
#import "OverlaySelectionView.h"
#interface OverlaySelectionView()
#property (nonatomic, retain) UIView* vectorArea;
#end
#implementation OverlaySelectionView
#synthesize vectorArea, vectorBounds;
#synthesize delegate;
- (void) initialize {
self.userInteractionEnabled = YES;
self.multipleTouchEnabled = NO;
self.backgroundColor = [UIColor clearColor];
self.opaque = NO;
self.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(rotateVector:)];
panRecognizer.maximumNumberOfTouches = 1;
[self addGestureRecognizer:panRecognizer];
}
- (id) initWithCoder: (NSCoder*) coder {
self = [super initWithCoder: coder];
if (self != nil) {
[self initialize];
}
return self;
}
- (id) initWithFrame: (CGRect) frame {
self = [super initWithFrame: frame];
if (self != nil) {
[self initialize];
}
return self;
}
- (void)drawRect:(CGRect)rect {
if (vectorBounds.origin.x){
UIView* area = [[UIView alloc] initWithFrame: vectorBounds];
area.backgroundColor = [UIColor grayColor];
area.opaque = YES;
area.userInteractionEnabled = NO;
vectorArea = area;
[self addSubview: vectorArea];
}
}
- (void)rotateVector: (UIPanGestureRecognizer *)panRecognizer{
if (touchLocationpoint.x){
PrevioustouchLocationpoint = touchLocationpoint;
}
if ([panRecognizer numberOfTouches] >= 1){
touchLocationpoint = [panRecognizer locationOfTouch:0 inView:self];
}
CGPoint origin;
origin.x=240;
origin.y=160;
CGPoint previousDifference = [self vectorFromPoint:origin toPoint:PrevioustouchLocationpoint];
CGAffineTransform newTransform =CGAffineTransformScale(vectorArea.transform, 1, 1);
CGFloat previousRotation = atan2(previousDifference.y, previousDifference.x);
CGPoint currentDifference = [self vectorFromPoint:origin toPoint:touchLocationpoint];
CGFloat currentRotation = atan2(currentDifference.y, currentDifference.x);
CGFloat newAngle = currentRotation- previousRotation;
newTransform = CGAffineTransformRotate(newTransform, newAngle);
[self animateView:vectorArea toPosition:newTransform];
}
-(CGPoint)vectorFromPoint:(CGPoint)firstPoint toPoint:(CGPoint)secondPoint
{
CGPoint result;
CGFloat x = secondPoint.x-firstPoint.x;
CGFloat y = secondPoint.y-firstPoint.y;
result = CGPointMake(x, y);
return result;
}
-(void)animateView:(UIView *)theView toPosition:(CGAffineTransform) newTransform
{
[UIView setAnimationsEnabled:YES];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:0.0750];
vectorArea.transform = newTransform;
[UIView commitAnimations];
}
#end
here is attempt to clarify. I am creating the rectangle from a coordinates on a map. Here is the function that creates that rectangle in the main view. Essentially it is the middle of the screen:
overlay is the view created with the above code.
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
if (!circle){
circle = [MKCircle circleWithCenterCoordinate: userLocation.coordinate radius:100];
[mainMapView addOverlay:circle];
CGPoint centerPoint = [mapView convertCoordinate:userLocation.coordinate toPointToView:self.view];
CGPoint upPoint = CGPointMake(centerPoint.x, centerPoint.y - 100);
overlay = [[OverlaySelectionView alloc] initWithFrame: self.view.frame];
overlay.vectorBounds = CGRectMake(upPoint.x, upPoint.y, 30, 100);
[self.view addSubview: overlay];
}
}
Here is the sketch of what I am trying to achieve:
Introduction
A rotation is always done around (0,0).
What you already know:
To rotate around the center of the rectangle you translate the rect to origin, rotate and translate back.
Now for your question:
to rotate around a center point of a circle, simply move the center of the rectangle such that the circle is at (0,0) then rotate, and move back.
start positioning the rectangle at 12 o clock, with the center line at 12.
1) as explained you always rotate around 0,0, so move the center of the circle to 0,0
CGAffineTransform trans1 = CGAffineTransformTranslation(-circ.x, -circ.y);
2) rotate by angle
CGAffineTransform transRot = CGAffineTransformRotation(angle); // or -angle try out.
3) Move back
CGAffineTransform transBack = CGAffineTransformTranslation(circ.x, circ.y);
Concat these 3 rotation matrices to one combibed matrix, and apply it to the rectangle.
CGAffineTransformation tCombo = CGAffineTransformConcat(trans1, transRot);
tCombo = CGTransformationConcat(tCombo, transback);
Apply
rectangle.transform = tCombo;
You probably should also read the chapter about Transformation matrices in Quartz docu.
This code is written with a text editor only, so expect slighly different function names.
Im building a custom UIView similar to UIPopover view , simply I subclass the UIView class and build the stuff of controls and events inside .. to show this view I assign the superView through My sub Class datasource like this
if ([dataSource respondsToSelector:#selector(containerView)])
superView = [dataSource containerView];
and to show it I have a function doing that like this
- (void) showPopOverFromRect : (CGRect) rect
{
CGSize popSize = self.frame.size;
float yPoint;
if(ntPopOverDirection == NTPopOverArrowDirectionUP)
yPoint = rect.origin.y + 10;
else
yPoint = rect.origin.y - 10;
self.frame = CGRectMake(rect.origin.x - popSize.width, yPoint , popSize.width, popSize.height);
[superView addSubview:self];
}
so My Question .. how can i dismiss this view (remove it) if the user tap AnyWhere on the superView just like the UIPopOverController ?
I suggest that you create your custom UIView to fill the entire superview or the entire screen with a clear background or a radial gradient. Then inside of this you would put another UIView that has the look and feel of the popover.
This eliminates the issue of trying to capture taps and sending notifications from other views. It will be all self contained.
You can easily add a gesture recognizer inside your custom view to close the view when the user touches the clear area.
You could place a UIButton below your new UIView that is clear. When this new button is pressed, it dismisses your view and removes itself from superview.
Something like:
- (void) showPopOverFromRect : (CGRect) rect
{
CGSize popSize = self.frame.size;
float yPoint;
if(ntPopOverDirection == NTPopOverArrowDirectionUP)
yPoint = rect.origin.y + 10;
else
yPoint = rect.origin.y - 10;
self.frame = CGRectMake(rect.origin.x - popSize.width, yPoint , popSize.width, popSize.height);
UIButton *dismissButton = [UIButton buttonWithType:UIButtonTypeCustom];
dismissButton.backgroundColor = [UIColor clearColor];
dismissButton.frame = [[UIScreen mainScreen] bounds];
[dismissButton addTarget:self.delegate action:#selector(dismissPopover) forControlEvents:UIControlEventTouchUpInside];
[superview addSubview:dismissButton];
[superView addSubview:self];
}
You'd have to set up the view to set it's superview as a delegate that receives the message to dismiss the popover, though.
I want to add a sub view in current view, this sub view is 300x300. When I add subview using
[self.view addSubview:md.view];
the md.view will appear at position (0,0) is there any way to add subview in center?
Thanks
You can set view's center property:
md.view.center = self.view.center;
Or you can explicetly set frame for md.view so that it will be centered as you want.
Use
CGRect bounds = self.view.bounds;
md.view.center = CGPointMake(bounds.size.width / 2, bounds.size.height / 2);
before or after that -addSubview: line.
You can specify exactly where you want the sub view to be placed within the parent view by doing so in the viewDidLoad method as follows:
- (void)viewDidLoad {
[super viewDidLoad];
SubView1Controller *subView1Controller=[[[SubView1Controller alloc] initWithNibName:#"SubView1" bundle:nil] autorelease];
CGRect r = [subView1Controller.view frame];
r.origin.x = 50;
r.origin.y = 50;
[subView1Controller.view setFrame:r];
[self.view insertSubview:subView1Controller.view atIndex:0];
}