如何将UIView的子视图居中

148

我有一个UIView嵌套在另一个UIView中,我希望内部的UIView始终居中于外部的UIView中,而无需调整宽度和高度。

我已经设置了支撑和弹簧效果,使其位于顶部/左侧/右侧/底部,但没有设置大小调整。但它仍然没有居中。有什么想法吗?


2
被接受的答案是错误的并且会崩溃。Hejazi 的答案非常好。 - Fattie
该页面证明了苹果为在其平台上开发软件提供的工具有多么混乱。 - 01GOD
15个回答

309

你可以这样做,并且它总是有效的:

child.center = [parent convertPoint:parent.center fromView:parent.superview];

对于 Swift:

child.center = parent.convert(parent.center, from:parent.superview)

1
不要忘记,child.frame = CGRectIntegral(child.frame); - Fattie
12
一: 只有在您未更改父视图的中心/位置时才有效。
二: 如果您使用此方法,则无需转换点(它已经处于正确的格式),只需使用 child.center = parent.center。我会使用 child.center = CGPointMake(parent.bounds.height/2, parent.bounds.width/2)。这将始终使您的子视图居中,而不管您的父视图中心设置为何。
- Old Name
1
如果视图尚未添加到视图层次结构中(例如在初始化对象时),这也是没有用的。 - Victor Jalencas
1
@Hejazi 如果能添加Swift的答案就更好了 ;) - Milad Faridnia
1
@Soumen 不,这两者是有区别的。UIView.bounds 是相对于 视图本身 的(因此 bounds.origin 最初为零),而 UIView.center 则是在 父视图 的坐标系中指定的。 - Hejazi
显示剩余4条评论

238

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)

59
如果视图使用了transform,就应该使用bounds而不是frame,因为如果使用frame会得到未定义的结果。 - omz
1
在这种情况下实际上不会有任何区别,因为只有size被使用。 - Peter DeWeese
1
不要紧,如果视图具有非标识变换,则整个“frame”属性未定义;请阅读UIView的框架属性文档。 - omz
8
很遗憾,此回答实际上是错误的。请使用Heja的正确答案。 - Fattie
1
@Fattie 这里到底有什么问题?我用它来将 ImageView 居中于 View 中,它是有效的。 - jreft56
显示剩余2条评论

49
在我们开始之前,让我们提醒一下,原点是视图左上角的 CGPoint。 了解视图和其父视图之间的重要关系。
让我们来看一下这段简单的代码,一个视图控制器向其视图添加一个黑色正方形:
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()
    }

}

这将创建此视图: 黑色矩形的原点和中心与其父视图的坐标相同

在这里输入图片描述

现在让我们尝试添加另一个SubSubView子视图,并将subSubview的原点设置为subView,但将subSubView设置为subView的子视图.

我们将添加以下代码:

var subSubView = UIView();
subSubView.frame.origin = subView.frame.origin;
subSubView.frame.size = CGSizeMake(20, 20);
subSubView.backgroundColor = UIColor.purpleColor()
subView.addSubview(subSubView)

这是结果:

enter image description here

由于这行代码:

subSubView.frame.origin = subView.frame.origin;

你希望紫色矩形的起点与它的父视图(黑色矩形)相同,但实际上它却在其下方。为什么会这样呢? 因为当将一个视图添加到另一个视图中时,子视图的框架“世界”现在是其父视图的BOUND RECTANGLE(边界矩形),如果你有一个视图,在主屏幕上的原点坐标为(15,15),那么对于它的所有子视图而言,左上角将是(0,0)。

这就是为什么你需要始终使用其父视图的BOUND RECTANGLE来引用它,这是它的子视图的“世界”,让我们将这一行修正为:

subSubView.frame.origin = subView.bounds.origin;

注意看,子视图现在恰好位于其父视图的原点位置:

enter image description here

所以,你可能会认为:“好吧,我只是想让我的视图相对于父视图居中,有什么大不了的?” 事实上,这并不复杂,你只需要将父视图中心点从它的frame转换为parent's bounds center即可,示例代码如下:

subSubView.center = subView.convertPoint(subView.center, fromView: subSubView);

你实际上是在告诉他:“将父视图中心转换为subSubView世界”。

然后你会得到这个结果:

输入图像描述


在哪里放置代码行'subSubView.center = subView.convertPoint(subView.center, fromView: subSubView)'? - Thamarai T

28

我会使用:

self.childView.center = CGPointMake(CGRectGetMidX(self.parentView.bounds),
                                    CGRectGetMidY(self.parentView.bounds));

我喜欢使用CGRect选项...

SWIFT 3:

self.childView.center = CGPoint(x: self.parentView.bounds.midX,
                                        y: self.parentView.bounds.midY);

20

1. 如果你启用了自动布局:

  • 提示:在使用自动布局的情况下,如果要将一个视图居中于另一个视图,可以使用相同的代码来处理任何共享至少一个父视图的两个视图。

首先禁用子视图的自动调整大小。

UIView *view1, *view2;
[childview setTranslatesAutoresizingMaskIntoConstraints:NO];
  1. 如果您正在使用UIView+Autolayout或Purelayout

    [view1 autoAlignAxis:ALAxisHorizontal toSameAxisOfView:view2];
    [view1 autoAlignAxis:ALAxisVertical toSameAxisOfView:view2];
    
    如果你仅使用UIKit级别的自动布局方法:
  2. [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. 没有使用自动布局:

我更喜欢:

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

6
需要注意的是,与被接受的答案不同,这个解决方案将在像素边界上干净地对齐,并防止某些宽度下视图模糊。 - Brad Larson
1
如果我没记错的话,child.frame = CGRectIntegral(child.frame); 是一个优雅的捕获 / 无处不在的解决方案来解决BL所描述的问题。 - Fattie
1
@JoeBlow:谢谢你提醒我。我曾经喜欢四舍五入,但是用块样式的话,使用 CGRectIntegral 更加优雅。 - Cemal Eker
如果您仅使用UIKit级别的自动布局方法,则会出现错误。 - Jonny

15

最简单的方法:

child.center = parent.center

我的意思是你应该添加更多关于这个如何工作的解释/描述。 - Tushar
我搜索了很多类似的答案,但最简单的一个对我起了作用。谢谢。 - gbossa

12

您可以使用

yourView.center = CGPointMake(CGRectGetMidX(superview.bounds), CGRectGetMidY(superview.bounds))

在Swift 3.0中

yourView.center = CGPoint(x: superview.bounds.midX, y: superview.bounds.midY)

1
第二个代码示例在Swift 4中完美运行。太棒了! - iGhost
是的!谢谢,终于找到了。之前不知道 midX / midY 这个东西。太完美了。 - Dave Y

9

这里输入图片描述

将此自动调整大小掩码设置为您的内部视图。


1
使用自动布局,就没有自动调整大小的窗口了。 - Allen
@Allen,如果您想使用自动调整大小功能,您需要禁用自动布局。 - Mayank Jain

8

在IOS9中,您可以使用布局锚点API。

代码如下:

childview.centerXAnchor.constraintEqualToAnchor(parentView.centerXAnchor).active = true
childview.centerYAnchor.constraintEqualToAnchor(parentView.centerYAnchor).active = true

这种方法优于使用CGPointMakeCGRect的方法,因为使用这些方法会将视图的中心设置为一个常量,但使用这种技术可以在两个视图之间建立一个永久保持的关系,无论parentview如何更改。
在执行此操作之前,请确保执行以下操作:
        self.view.addSubview(parentView)
        self.view.addSubView(chidview)

还要为每个视图设置translatesAutoresizingMaskIntoConstraints为false。

这将防止崩溃和AutoLayout干扰。


5

在视图和子视图中使用相同的中心是最简单的方法。你可以像这样做:

UIView *innerView = ....;
innerView.view.center = self.view.center;
[self.view addSubView:innerView];

这将使子视图相对于视图的超级视图居中。在上述情况下,它能够正常工作是因为原点位于(0,0)。 - Abdurrahman Mubeen Ali

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接