Pergunta

Please see the following code:

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

The problem I'm having is H:|-[start(100)]-| won't work. What I want is a button with a width of 100 centered on the X-axis and attached to the bottom of the screen with a default margin. As soon as I remove the (100) this works, however the button stretches to the width of the screen minus the default margins. When I specify a custom width I reckon the Auto Layout system can't work out what the left and right margins should be. I get an Unable to simultaneously satisfy constraints. error. I guess this has something to do with the dashes in H:|-[start(100)]-|, which need to have a fluid width to attach the start element to the superview, instead of being the default margins.

Any thoughts on how I might solve this?

Update (thanks ghettopia):

This works (notice I'm using a UINavigationController in the app delegate and self.view.translatesAutoresizingMaskIntoConstraints = false in viewDidLoad of TestController is commented out):

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

Great. Now I get a blue screen with a button centered on the X-axis with a default margin to the bottom, just as I intended. However, from what I've read self.view.translatesAutoresizingMaskIntoConstraints = false is required to make Auto Layout work. To make that happen, this works as well (notice I'm not using a UINavigationController this time and self.view.translatesAutoresizingMaskIntoConstraints = false in viewDidLoad of TestController IS being used):

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

But that doesn't seem like a proper solution. I need a UINavigationController to create my app structure. The thing is when I don't use any of the above solutions I get a black screen with a button dead in the middle (on both axis). The views seems to be broken: Black screen

Thoughts? Should I just remove self.view.translatesAutoresizingMaskIntoConstraints = false and forget about it or is it indeed required? If it is, there must be something wrong with my code.

Update 2:

Interesting tutorial: Auto Layout in iOS 6: Adding constraints through code. The author doesn't use self.view.translatesAutoresizingMaskIntoConstraints = false in viewDidLoad, only on subviews.

Update 3:

I think I may have solved the black screen problem by moving self.view.translatesAutoresizingMaskIntoConstraints = false to the init method instead of viewDidLoad. Not sure why this works though, but the screen looks identical to the screenshot now, just as I intented in the first place. Here's the updated code:

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
Foi útil?

Solução

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 ] ] ;
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top