133
votes

I have a UIView inside a UIViewm 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?

15
The accepted answer is wrong and will crash. Hejazi's answer works great.Fattie

15 Answers

224
votes

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)
293
votes

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)
44
votes

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

enter image description here

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:

enter image description here

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:

enter image description here

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:

enter image description here

27
votes

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);
19
votes

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];
  1. If you are UIView+Autolayout or Purelayout:

    [view1 autoAlignAxis:ALAxisHorizontal toSameAxisOfView:view2];
    [view1 autoAlignAxis:ALAxisVertical toSameAxisOfView:view2];
    
  2. 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);
})];
13
votes

The easiest way:

child.center = parent.center
9
votes

enter image description here

Set this autoresizing mask to your inner view.

9
votes

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)
8
votes

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.

5
votes

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];
3
votes

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:

Center with PureLayout

2
votes

In c# or Xamarin.ios, we can use like this

imageView.Center = new CGPoint(tempView.Frame.Size.Width / 2, tempView.Frame.Size.Height / 2);

2
votes

This worked for me

childView.centerXAnchor.constraint(equalTo: parentView.centerXAnchor).isActive = true
childView.centerYAnchor.constraint(equalTo: parentView.centerYAnchor).isActive = true
1
votes

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!

0
votes
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