ChatGPT解决这个技术问题 Extra ChatGPT

How to center a subview of UIView

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?

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

H
Hejazi

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)

and don't forget afterwards, child.frame = CGRectIntegral(child.frame);
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.
It's also not useful if the view has not been added yet to the view hierarchy (such as when initting the object)
@Hejazi It would be nice to add swift answer too ;)
@Soumen 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.
C
Cœur

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)

You should use the bounds and not the frame, as the frame is undefined if the view has a transform.
It actually won't make a different in this case, as only size is being used.
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.
Unfortunately this answer is actually wrong. Simply use Heja's correct answer.
@Fattie what is exactly wrong here ? I used it for centering an ImageView within a View and it is working.
A
Alexander Abakumov

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


To where the line 'subSubView.center = subView.convertPoint(subView.center, fromView: subSubView)' be placed ?
t
theprojectabot

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

C
Cemal Eker

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);
})];

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.
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.
@JoeBlow: Thanks for the heads up. I used to love rounding but with block style it's more elegant to use CGRectIntegral
"If you are using only UIKit level autolayout methods:" results in errors.
j
juancazalla

The easiest way:

child.center = parent.center

What I mean is you should add more explanation/description of how this works.
Searched a lot of answers of this type, this simple one did the trick for me. Thanks.
S
Sayali Shinde

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)

The second code example work perfectly in swift 4. GREAT 👍🏻!
YES! Thank you, finally. Didn't know about that midX / midY thing. Perfecto.
M
Mayank Jain

https://i.stack.imgur.com/oJ3wL.png

Set this autoresizing mask to your inner view.


With autolayout, there's no autosizing window.
@Allen you have to disable autolayout if you want to use autoresizing.
F
Foobar

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.


c
codeFood

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

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).
H
H6.

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


A
Anisetti Nagendra

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

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


K
KamyFC

This worked for me

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

O
Old Name

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!


S
Sidd Redkar
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