How to center a subview of UIView
Asked Answered
E

15

148

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?

Exult answered 28/6, 2012 at 20:0 Comment(2)
The accepted answer is wrong and will crash. Hejazi's answer works great.Peipus
This page is a testament to what a mess the tools Apple provided for making software on Apple platforms have been.Devoir
L
239

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)
Lavalley answered 28/6, 2012 at 22:3 Comment(7)
You should use the bounds and not the frame, as the frame is undefined if the view has a transform.Logistics
It actually won't make a different in this case, as only size is being used.Gallipot
That doesn't matter, the entire 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.Logistics
Unfortunately this answer is actually wrong. Simply use Heja's correct answer.Peipus
@Peipus what is exactly wrong here ? I used it for centering an ImageView within a View and it is working.Pantywaist
@Pantywaist it will eventually crash, as has been extensively explained in the commentsPeipus
you can replace frame.size.width / 2 with midX and the height equation with midYContrabass
S
309

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)
Seafaring answered 28/6, 2012 at 22:8 Comment(9)
and don't forget afterwards, child.frame = CGRectIntegral(child.frame);Peipus
@Seafaring Why not as simple as this child.center.x = parent.bounds.size.width/2 AND child.center.y = parent.bounds.size.height/2 ?Felicidad
@JoeBlow Check the comments on the accepted answer.Seafaring
One: This only works if you have not changed the center/location of your parent view. Second: If you're using this method there isn't any need to convert the point (it's already in the correct format) just use 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.Destruction
It's also not useful if the view has not been added yet to the view hierarchy (such as when initting the object)Bedight
One thing to add... if your view's view controller is embedded in a navigation controller, you should instead call the navigation controller's view instead of self.viewAlbuminate
@Seafaring It would be nice to add swift answer too ;)Witherspoon
I wonder why child.center = parent.center is not working sometimes while `child.center = CGPointMake(parent.bounds.height/2, parent.bounds.width/2)' works. Isn't parent.center does the same calculation?Ene
@Ene No, there is a difference. UIView.bounds is relative to the view itself (and therefore bounds.origin is initially zero), while UIView.center is specified in the coordinate system of the superview.Seafaring
L
239

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)
Lavalley answered 28/6, 2012 at 22:3 Comment(7)
You should use the bounds and not the frame, as the frame is undefined if the view has a transform.Logistics
It actually won't make a different in this case, as only size is being used.Gallipot
That doesn't matter, the entire 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.Logistics
Unfortunately this answer is actually wrong. Simply use Heja's correct answer.Peipus
@Peipus what is exactly wrong here ? I used it for centering an ImageView within a View and it is working.Pantywaist
@Pantywaist it will eventually crash, as has been extensively explained in the commentsPeipus
you can replace frame.size.width / 2 with midX and the height equation with midYContrabass
L
49

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

List answered 22/7, 2015 at 14:29 Comment(1)
To where the line 'subSubView.center = subView.convertPoint(subView.center, fromView: subSubView)' be placed ?Morry
L
28

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);
Leisure answered 18/1, 2015 at 19:41 Comment(0)
J
20

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);
})];
Jaw answered 28/6, 2012 at 21:22 Comment(4)
It should be noted that, unlike the accepted answer, this solution will align cleanly on pixel boundaries and prevent blurriness of the view for certain widths.Eternize
If I'm not mistaken, child.frame = CGRectIntegral(child.frame); is an elegant sort of catch-all / use anywhere solution to the problem BL describes.Peipus
@JoeBlow: Thanks for the heads up. I used to love rounding but with block style it's more elegant to use CGRectIntegralJaw
"If you are using only UIKit level autolayout methods:" results in errors.Hillinck
H
16

The easiest way:

child.center = parent.center
Heligoland answered 17/2, 2016 at 16:37 Comment(2)
What I mean is you should add more explanation/description of how this works.Berzelius
Searched a lot of answers of this type, this simple one did the trick for me. Thanks.Side
S
12

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)
Skyjack answered 15/9, 2017 at 8:52 Comment(2)
The second code example work perfectly in swift 4. GREAT 👍🏻!Bork
YES! Thank you, finally. Didn't know about that midX / midY thing. Perfecto.Cycling
R
9

enter image description here

Set this autoresizing mask to your inner view.

Ritchie answered 14/4, 2014 at 11:43 Comment(2)
With autolayout, there's no autosizing window.Catacaustic
@Catacaustic you have to disable autolayout if you want to use autoresizing.Ritchie
B
9

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.

Basswood answered 24/6, 2016 at 1:17 Comment(0)
S
5

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];
Sada answered 17/7, 2013 at 22:38 Comment(1)
This will center the sub view with respect to the super view of view. In the above case, it is working because the origin is at (0, 0).Depredate
P
3

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

Procyon answered 15/5, 2015 at 17:1 Comment(0)
S
3

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

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

Stockjobber answered 7/6, 2019 at 4:19 Comment(0)
D
3

This worked for me

childView.centerXAnchor.constraint(equalTo: parentView.centerXAnchor).isActive = true
childView.centerYAnchor.constraint(equalTo: parentView.centerYAnchor).isActive = true
Draff answered 19/2, 2021 at 6:17 Comment(0)
C
2
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
Chairmanship answered 23/8, 2019 at 16:48 Comment(0)
D
1

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!

Destruction answered 23/7, 2014 at 23:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.