如何使用自动布局约束使自定义宽度的按钮居中?

时间:2012-12-04 12:05:49

标签: ios6 autolayout rubymotion nslayoutconstraint visual-format-language

请参阅以下代码:

def viewDidLoad
    super
    self.view.translatesAutoresizingMaskIntoConstraints = false
    self.view.backgroundColor = UIColor.whiteColor

    @start = UIButton.buttonWithType(UIButtonTypeRoundedRect).tap do |el|
      el.translatesAutoresizingMaskIntoConstraints = false          
      el.setTitle('Start', forState:UIControlStateNormal)
      el.addTarget(self, action:'toStartController', forControlEvents:UIControlEventTouchUpInside)
      self.view.addSubview(el)
    end

    self.layout_subviews
  end

def layout_subviews
    metrics = { 'space' => 8 }

    views_dict = { 
      'superview' => self.view, 
      'start' => @start
    }

    self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat('H:|-[start(100)]-|', 
                                                                    options: NSLayoutFormatAlignAllCenterX, 
                                                                    metrics: metrics, 
                                                                      views: views_dict))

    self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat('V:[start]-|', 
                                                                    options: NSLayoutFormatAlignAllBottom, 
                                                                    metrics: metrics, 
                                                                      views: views_dict))
  end

我遇到的问题是H:|-[start(100)]-|无效。我想要的是一个宽度为100的按钮,以X轴为中心,并以默认边距连接到屏幕底部。一旦我删除(100)这个工作,但按钮会拉伸到屏幕的宽度减去默认边距。当我指定自定义宽度时,我认为自动布局系统无法确定左边距和右边距应该是什么。我收到Unable to simultaneously satisfy constraints.错误。我想这与H:|-[start(100)]-|中的破折号有关,它需要有一个流畅的宽度来将start元素附加到superview,而不是默认的边距。

关于如何解决这个问题的任何想法?

更新(感谢ghettopia):

这有效(请注意,我在应用委托中使用了UINavigationController,而self.view.translatesAutoresizingMaskIntoConstraints = false viewDidLoad中的TestController已被注释掉了:

class AppDelegate
  def application(application, didFinishLaunchingWithOptions:launchOptions)
    @window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds).tap do |win|
      controller = TestController.alloc.initWithNibName(nil, bundle:nil)
      win.rootViewController = UINavigationController.alloc.initWithRootViewController(controller).tap do |root|
        root.navigationBarHidden = true
        root.wantsFullScreenLayout = true
      end
      win.makeKeyAndVisible
    end
    true
  end
end

class TestController < UIViewController

  def viewDidLoad
    super
    # self.view.translatesAutoresizingMaskIntoConstraints = false
    self.view.backgroundColor = UIColor.blueColor

    @button = UIButton.buttonWithType(UIButtonTypeRoundedRect)
    @button.translatesAutoresizingMaskIntoConstraints = false
    self.view.addSubview(@button)

    views = { 
      'view' => self.view, 
      'button' => @button
    }

    self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat('H:[button(100)]', options: 0, metrics: nil, views: views))
    self.view.addConstraint(NSLayoutConstraint.constraintWithItem(@button, attribute: NSLayoutAttributeCenterX, relatedBy: NSLayoutRelationEqual, toItem: self.view, attribute: NSLayoutAttributeCenterX, multiplier: 1, constant: 0))
    self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat('V:[button]-|', options: 0, metrics: nil, views: views))
  end
end

Correct screen

大。现在我得到一个蓝色的屏幕,其中一个按钮位于X轴的中心,底部有一个默认的边距,就像我想要的那样。但是,根据我的阅读self.view.translatesAutoresizingMaskIntoConstraints = false,需要使自动布局工作。为了实现这一点,这也适用(注意我这次没有使用UINavigationControllerself.view.translatesAutoresizingMaskIntoConstraints = false viewDidLoad正在使用TestController

class AppDelegate
  def application(application, didFinishLaunchingWithOptions:launchOptions)
    @window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds).tap do |win|
      win.rootViewController = TestController.alloc.initWithNibName(nil, bundle:nil)
      win.makeKeyAndVisible
    end
    true
  end
end

class TestController < UIViewController

  def viewDidLoad
    super
    self.view.translatesAutoresizingMaskIntoConstraints = false
    self.view.backgroundColor = UIColor.blueColor

    @button = UIButton.buttonWithType(UIButtonTypeRoundedRect)
    @button.translatesAutoresizingMaskIntoConstraints = false
    self.view.addSubview(@button)

    views = { 
      'view' => self.view, 
      'button' => @button
    }

    self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat('H:[button(100)]', options: 0, metrics: nil, views: views))
    self.view.addConstraint(NSLayoutConstraint.constraintWithItem(@button, attribute: NSLayoutAttributeCenterX, relatedBy: NSLayoutRelationEqual, toItem: self.view, attribute: NSLayoutAttributeCenterX, multiplier: 1, constant: 0))
    self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat('V:[button]-|', options: 0, metrics: nil, views: views))
  end
end

但这似乎不是一个合适的解决方案。我需要一个UINavigationController来创建我的应用结构。问题是,当我不使用上述任何解决方案时,我得到一个黑色屏幕,中间有一个按钮(两个轴上)。这些观点似乎被打破了: Black screen

思考?我应该删除self.view.translatesAutoresizingMaskIntoConstraints = false并忘掉它,还是确实需要?如果是,我的代码肯定有问题。

更新2:

有趣的教程:Auto Layout in iOS 6: Adding constraints through code。作者不在self.view.translatesAutoresizingMaskIntoConstraints = false中使用viewDidLoad,仅在子视图中使用。

更新3:

我想我可能通过将self.view.translatesAutoresizingMaskIntoConstraints = false移到init方法而不是viewDidLoad来解决黑屏问题。不知道为什么会这样,但屏幕看起来与截图相同,就像我最初的意图一样。这是更新后的代码:

class AppDelegate
  def application(application, didFinishLaunchingWithOptions:launchOptions)
    @window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds).tap do |win|
      controller = TestController.alloc.initWithNibName(nil, bundle:nil)
      win.rootViewController = UINavigationController.alloc.initWithRootViewController(controller).tap do |root|
        root.navigationBarHidden = true
        root.wantsFullScreenLayout = true
      end
      win.makeKeyAndVisible
    end
    true
  end
end    

class TestController < UIViewController

  def init
    self.view.translatesAutoresizingMaskIntoConstraints = false
  end

  def viewDidLoad
    super
    self.view.backgroundColor = UIColor.blueColor

    @button = UIButton.buttonWithType(UIButtonTypeRoundedRect)
    @button.translatesAutoresizingMaskIntoConstraints = false
    self.view.addSubview(@button)

    views = { 
      'view' => self.view, 
      'button' => @button
    }

    self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat('H:[button(100)]', options: 0, metrics: nil, views: views))
    self.view.addConstraint(NSLayoutConstraint.constraintWithItem(@button, attribute: NSLayoutAttributeCenterX, relatedBy: NSLayoutRelationEqual, toItem: self.view, attribute: NSLayoutAttributeCenterX, multiplier: 1, constant: 0))
    self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat('V:[button]-|', options: 0, metrics: nil, views: views))
  end
end

1 个答案:

答案 0 :(得分:6)

UIButton* button = [UIButton buttonWithType:UIButtonTypeRoundedRect] ;
button.translatesAutoresizingMaskIntoConstraints = NO ;
[self.view addSubview:button] ;

NSDictionary* views = @{ @"view" : self.view  ,  @"button" : button } ;
// Make button's width 100.
[self.view addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:@"H:[button(100)]"  options:0   metrics:nil  views:views ] ] ;
// Make button's CenterX the same as self.view's CenterX.
[self.view addConstraint: [NSLayoutConstraint constraintWithItem:button  attribute:NSLayoutAttributeCenterX  relatedBy:NSLayoutRelationEqual  toItem:self.view  attribute:NSLayoutAttributeCenterX  multiplier:1  constant:0 ] ] ;
// Make button's NSLayoutAttributeBottom the default space away from self.view's NSLayoutAttributeBottom.
[self.view addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:@"V:[button]-|"  options:0   metrics:nil  views:views ] ] ;