【问题标题】:How to center a subview of UIView如何使 UIView 的子视图居中
【发布时间】:2012-06-30 09:45:47
【问题描述】:

我在UIViewm 中有一个UIView,我希望内部UIView 始终位于外部UIView 的中心,而不必调整宽度和高度。

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

【问题讨论】:

  • 接受的答案是错误的,会崩溃。 Hejazi 的回答效果很好。

标签: iphone objective-c ios ipad


【解决方案1】:

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

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

对于 Swift:

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

【讨论】:

  • 之后别忘了,child.frame = CGRectIntegral(child.frame);
  • 一个:这仅在您没有更改父视图的中心/位置时才有效。 第二个:如果您使用这种方法,则无需转换点(它已经是正确的格式)只需使用child.center = parent.center。我会使用`child.center = CGPointMake(parent.bounds.height/2, parent.bounds.width/2)'。无论您的父视图中心设置为什么,这将始终使您的子视图居中。
  • 如果视图尚未添加到视图层次结构中(例如在初始化对象时),它也没有用
  • @Hejazi 也可以添加快速答案;)
  • @Soumen 不,有区别。 UIView.bounds 相对于 view 本身(因此bounds.origin 最初为零),而UIView.centersuperview 的坐标系中指定。跨度>
【解决方案2】:

目标-C

yourSubView.center = CGPointMake(yourView.frame.size.width  / 2, 
                                 yourView.frame.size.height / 2);

斯威夫特

yourSubView.center = CGPoint(x: yourView.frame.size.width  / 2,
                             y: yourView.frame.size.height / 2)

【讨论】:

  • 你应该使用bounds而不是frame,因为如果视图有transformframe是未定义的。
  • 在这种情况下实际上不会有什么不同,因为只使用了size
  • 没关系,如果视图有一个不是身份转换的transform,则整个frame 属性是未定义的;阅读documentation on the frame property of UIView
  • 不幸的是,这个答案实际上是错误的。只需使用 Heja 的正确答案即可。
  • @Fattie 这里到底出了什么问题?我用它来使 ImageView 在 View 中居中,它正在工作。
【解决方案3】:

在开始之前,让我们提醒一下,原点是视图的左上角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()
    }

}

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

现在让我们尝试将 subView 添加另一个 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)

结果如下:

因为这条线:

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

您希望紫色矩形的原点与其父矩形(黑色矩形)相同,但它位于其下方,这是为什么呢? 因为当您将视图添加到另一个视图时,子视图框架“世界”现在是它的父 BOUND RECTANGLE,如果您认为它在主屏幕上的原点在所有子视图的坐标 (15,15) 处,则左上角将是 (0,0)

这就是为什么你需要始终通过它的绑定矩形来引用父级,这是它的子视图的“世界”,让我们将这一行修复为:

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

看看神奇的是,subSubview 现在正好位于它的父原点:

所以,你喜欢“好吧,我只想以我父母的观点为中心,有什么大不了的?” 好吧,这没什么大不了的,您只需要将从框架中获取的父中心点“翻译”到父边界中心 通过这样做:

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

您实际上是在告诉他“获取父母视图中心,并将其转换为 subSubView 世界”。

你会得到这个结果:

【讨论】:

  • 到'subSubView.center = subView.convertPoint(subView.center, fromView: subSubView)'行的位置?
【解决方案4】:

我会使用:

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

【讨论】:

    【解决方案5】:

    1。如果您启用了自动布局:

    • 提示:要使用自动布局使视图居中在另一个视图上,您​​可以对共享至少一个父视图的任何两个视图使用相同的代码。

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

    UIView *view1, *view2;
    [childview setTranslatesAutoresizingMaskIntoConstraints:NO];
    
    1. 如果你是 UIView+Autolayout 或者Purelayout:

      [view1 autoAlignAxis:ALAxisHorizontal toSameAxisOfView:view2];
      [view1 autoAlignAxis:ALAxisVertical toSameAxisOfView:view2];
      
    2. 如果您只使用 UIKit 级别的自动布局方法:

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

    【讨论】:

    • 应该注意的是,与公认的答案不同,此解决方案将在像素边界上清晰对齐,并防止某些宽度的视图模糊。
    • 如果我没记错的话,child.frame = CGRectIntegral(child.frame); 是 BL 描述的问题的一种优雅的包罗万象 / 随处使用的解决方案.
    • @JoeBlow:感谢您的提醒。我曾经喜欢四舍五入,但使用块样式更优雅CGRectIntegral
    • 你能解释一下你用来设置框架的语法吗,我以前没见过。它总是分配给属性的“闭包”中的最后一个语句吗?在 Apple 文档中哪里可以找到它?
    • "如果您只使用 UIKit 级别的自动布局方法:" 会导致错误。
    【解决方案6】:

    最简单的方法:

    child.center = parent.center
    

    【讨论】:

    • 我的意思是你应该添加更多关于它是如何工作的解释/描述。
    • 搜索了很多这种类型的答案,这个简单的答案对我有用。谢谢。
    【解决方案7】:

    你可以使用

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

    在 Swift 3.0 中

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

    【讨论】:

    • 第二个代码示例在 swift 4 中完美运行。太棒了??!
    • 是的!谢谢你,终于。不知道 midX / midY 的事情。完美。
    【解决方案8】:

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

    【讨论】:

    • 使用自动布局,没有自动调整窗口大小。
    • @Allen 如果你想使用自动调整大小,你必须禁用自动布局。
    【解决方案9】:

    在 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 干扰。

    【讨论】:

      【解决方案10】:

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

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

      【讨论】:

      • 这将使子视图相对于视图的超级视图居中。在上述情况下,它正在工作,因为原点位于 (0, 0)。
      【解决方案11】:

      PureLayout 使用autoCenterInSuperview 的另一种解决方案。

      // ...
      UIView *innerView = [UIView newAutoLayoutView];
      innerView.backgroundColor = [UIColor greenColor];
      [innerView autoSetDimensionsToSize:CGSizeMake(100, 30)];
      
      [outerview addSubview:innerView];
      
      [innerView autoCenterInSuperview];
      

      这就是它的样子:

      【讨论】:

        【解决方案12】:

        在c#或Xamarin.ios中,我们可以这样使用

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

        【讨论】:

          【解决方案13】:

          这对我有用

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

          【讨论】:

            【解决方案14】:

            我会使用:

            child.center = CGPointMake(parent.bounds.height / 2, parent.bounds.width / 2)
            

            这很简单,简短而甜蜜。如果您在上面使用@Hejazi 的答案并且parent.center 设置为(0,0) 以外的任何内容,您的子视图将不会居中!

            【讨论】:

              【解决方案15】:
              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
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2019-03-07
                • 2015-07-06
                • 1970-01-01
                • 1970-01-01
                • 2014-02-06
                相关资源
                最近更新 更多