I have a UIView
inside a UIView
m and I want the inner UIView
to be always centered inside the outer one, without it having to resize the width and height.
I've set the struts and springs so that it's on top/left/right/bottom without setting the resize. But it still doesn't center. Any idea?
You can do this and it will always work:
child.center = [parent convertPoint:parent.center fromView:parent.superview];
And for Swift:
child.center = parent.convert(parent.center, from:parent.superview)
Objective-C
yourSubView.center = CGPointMake(yourView.frame.size.width / 2,
yourView.frame.size.height / 2);
Swift
yourSubView.center = CGPoint(x: yourView.frame.size.width / 2,
y: yourView.frame.size.height / 2)
bounds
and not the frame
, as the frame
is undefined if the view has a transform
.
size
is being used.
frame
property is undefined if the view has a transform
that is not the identity transform; read the documentation on the frame property of UIView.
Before we'll begin, let's just remind that origin point is the Upper Left corner CGPoint
of a view. An important thing to understand about views and parents.
Lets take a look at this simple code, a view controller that adds to it's view a black square:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
createDummyView()
super.view.backgroundColor = UIColor.cyanColor();
}
func createDummyView(){
var subView = UIView(frame: CGRect(x: 15, y: 50, width: 50 , height: 50));
super.view.addSubview(subView);
view.backgroundColor = UIColor.blackColor()
}
}
This will create this view: the black rectangle origin and center does fit the same coordinates as it's parent
https://i.stack.imgur.com/kNM0f.png
Now let's try to add subView another SubSubView, and giving subSubview same origin as subView, but make subSubView a child view of subView
We'll add this code:
var subSubView = UIView();
subSubView.frame.origin = subView.frame.origin;
subSubView.frame.size = CGSizeMake(20, 20);
subSubView.backgroundColor = UIColor.purpleColor()
subView.addSubview(subSubView)
And this is the result:
https://i.stack.imgur.com/viHzv.png
Because of this line:
subSubView.frame.origin = subView.frame.origin;
You expect for the purple rectangle's origin to be same as it's parent (the black rectangle) but it goes under it, and why is that? Because when you add a view to another view, the subView frame "world" is now it's parent BOUND RECTANGLE, if you have a view that it's origin on the main screen is at coords (15,15) for all it's sub views, the upper left corner will be (0,0)
This is why you need to always refer to a parent by it's bound rectangle, which is the "world" of it's subViews, lets fix this line to:
subSubView.frame.origin = subView.bounds.origin;
And see the magic, the subSubview is now located exactly in it's parent origin:
https://i.stack.imgur.com/fpudG.png
So, you like "ok I only wanted to center my view by my parents view, what's the big deal?" well, it isn't big deal, you just need to "translate" the parent Center point which is taken from it's frame to parent's bounds center by doing this:
subSubView.center = subView.convertPoint(subView.center, fromView: subSubView);
You're actually telling him "take parents view center, and convert it into subSubView world".
And you'll get this result:
https://i.stack.imgur.com/XDbSd.png
I would use:
self.childView.center = CGPointMake(CGRectGetMidX(self.parentView.bounds),
CGRectGetMidY(self.parentView.bounds));
I like to use the CGRect
options...
SWIFT 3:
self.childView.center = CGPoint(x: self.parentView.bounds.midX,
y: self.parentView.bounds.midY);
1. If you have autolayout enabled:
Hint: For centering a view on another view with autolayout you can use same code for any two views sharing at least one parent view.
First of all disable child views autoresizing
UIView *view1, *view2;
[childview setTranslatesAutoresizingMaskIntoConstraints:NO];
If you are UIView+Autolayout or Purelayout: [view1 autoAlignAxis:ALAxisHorizontal toSameAxisOfView:view2]; [view1 autoAlignAxis:ALAxisVertical toSameAxisOfView:view2]; If you are using only UIKit level autolayout methods: [view1 addConstraints:({ @[ [NSLayoutConstraint constraintWithItem:view1 attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:view2 attribute:NSLayoutAttributeCenterX multiplier:1.f constant:0.f], [NSLayoutConstraint constraintWithItem:view1 attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:view2 attribute:NSLayoutAttributeCenterY multiplier:1.f constant:0.f] ]; })];
2. Without autolayout:
I prefer:
UIView *parentView, *childView;
[childView setFrame:({
CGRect frame = childView.frame;
frame.origin.x = (parentView.frame.size.width - frame.size.width) / 2.0;
frame.origin.y = (parentView.frame.size.height - frame.size.height) / 2.0;
CGRectIntegral(frame);
})];
CGRectIntegral
The easiest way:
child.center = parent.center
You can use
yourView.center = CGPointMake(CGRectGetMidX(superview.bounds), CGRectGetMidY(superview.bounds))
And In Swift 3.0
yourView.center = CGPoint(x: superview.bounds.midX, y: superview.bounds.midY)
https://i.stack.imgur.com/oJ3wL.png
Set this autoresizing mask to your inner view.
With IOS9 you can use the layout anchor API.
The code would look like this:
childview.centerXAnchor.constraintEqualToAnchor(parentView.centerXAnchor).active = true
childview.centerYAnchor.constraintEqualToAnchor(parentView.centerYAnchor).active = true
The advantage of this over CGPointMake
or CGRect
is that with those methods you are setting the center of the view to a constant but with this technique you are setting a relationship between the two views that will hold forever, no matter how the parentview
changes.
Just be sure before you do this to do:
self.view.addSubview(parentView)
self.view.addSubView(chidview)
and to set the translatesAutoresizingMaskIntoConstraints
for each view to false.
This will prevent crashing and AutoLayout from interfering.
Using the same center in the view and subview is the simplest way of doing it. You can do something like this,
UIView *innerView = ....;
innerView.view.center = self.view.center;
[self.view addSubView:innerView];
Another solution with PureLayout using autoCenterInSuperview
.
// ...
UIView *innerView = [UIView newAutoLayoutView];
innerView.backgroundColor = [UIColor greenColor];
[innerView autoSetDimensionsToSize:CGSizeMake(100, 30)];
[outerview addSubview:innerView];
[innerView autoCenterInSuperview];
This is it how it looks like:
https://i.stack.imgur.com/M7dIN.png
In c# or Xamarin.ios, we can use like this
imageView.Center = new CGPoint(tempView.Frame.Size.Width / 2, tempView.Frame.Size.Height / 2);
This worked for me
childView.centerXAnchor.constraint(equalTo: parentView.centerXAnchor).isActive = true
childView.centerYAnchor.constraint(equalTo: parentView.centerYAnchor).isActive = true
I would use:
child.center = CGPointMake(parent.bounds.height / 2, parent.bounds.width / 2)
This is simple, short, and sweet. If you use @Hejazi's answer above and parent.center
is set to anything other than (0,0)
your subview will not be centered!
func callAlertView() {
UIView.animate(withDuration: 0, animations: {
let H = self.view.frame.height * 0.4
let W = self.view.frame.width * 0.9
let X = self.view.bounds.midX - (W/2)
let Y = self.view.bounds.midY - (H/2)
self.alertView.frame = CGRect(x:X, y: Y, width: W, height: H)
self.alertView.layer.borderWidth = 1
self.alertView.layer.borderColor = UIColor.red.cgColor
self.alertView.layer.cornerRadius = 16
self.alertView.layer.masksToBounds = true
self.view.addSubview(self.alertView)
})
}// calculation works adjust H and W according to your requirement
Success story sharing
child.center = parent.center
. I would use `child.center = CGPointMake(parent.bounds.height/2, parent.bounds.width/2)'. This will alway have your subview centered regardless of what your parent view center is set to.UIView.bounds
is relative to the view itself (and thereforebounds.origin
is initially zero), whileUIView.center
is specified in the coordinate system of the superview.