Como adicionar restrições programaticamente usando Swift


448

Estou tentando descobrir isso desde a semana passada sem dar um passo adiante. Ok, então eu preciso aplicar algumas restrições programaticamente no Swift a um UIViewusando este código:

var new_view:UIView! = UIView(frame: CGRectMake(0, 0, 100, 100));
new_view.backgroundColor = UIColor.redColor();
view.addSubview(new_view);

var constX:NSLayoutConstraint = NSLayoutConstraint(item: new_view, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.CenterX, multiplier: 1, constant: 0);
self.view.addConstraint(constX);

var constY:NSLayoutConstraint = NSLayoutConstraint(item: new_view, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.CenterY, multiplier: 1, constant: 0);
self.view.addConstraint(constY);

var constW:NSLayoutConstraint = NSLayoutConstraint(item: new_view, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: new_view, attribute: NSLayoutAttribute.Width, multiplier: 1, constant: 0);
self.view.addConstraint(constW);

var constH:NSLayoutConstraint = NSLayoutConstraint(item: new_view, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: new_view, attribute: NSLayoutAttribute.Height, multiplier: 1, constant: 0);
self.view.addConstraint(constH);

Mas o Xcode retorna esta saída estranha:

2014-10-03 09:48:12.657 Test[35088:2454916] Unable to simultaneously satisfy constraints.  Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
"<NSLayoutConstraint:0x7fa4ea446830 UIView:0x7fa4ea429290.centerX == UIView:0x7fa4ea4470f0.centerX>",
"<NSAutoresizingMaskLayoutConstraint:0x7fa4ea4516c0 h=--& v=--& UIView:0x7fa4ea429290.midX == + 50>",
"<NSLayoutConstraint:0x7fa4ea452830 'UIView-Encapsulated-Layout-Width' H:[UIView:0x7fa4ea4470f0(375)]>",
"<NSAutoresizingMaskLayoutConstraint:0x7fa4ea446db0 h=-&- v=-&- 'UIView-Encapsulated-Layout-Left' H:|-(0)-[UIView:0x7fa4ea4470f0]   (Names: '|':UIWindow:0x7fa4ea444b20 )>"
)

Will attempt to recover by breaking constraint <NSLayoutConstraint:0x7fa4ea446830 UIView:0x7fa4ea429290.centerX == UIView:0x7fa4ea4470f0.centerX>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in
<UIKit/UIView.h> may also be helpful.

2014-10-03 09:48:12.658 Test[35088:2454916] Unable to simultaneously satisfy constraints.  Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
(
"<NSLayoutConstraint:0x7fa4ea44d160 UIView:0x7fa4ea429290.centerY == UIView:0x7fa4ea4470f0.centerY>",
"<NSAutoresizingMaskLayoutConstraint:0x7fa4ea451b30 h=--& v=--& UIView:0x7fa4ea429290.midY == + 50>",
"<NSLayoutConstraint:0x7fa4ea44cf00 'UIView-Encapsulated-Layout-Height' V:[UIView:0x7fa4ea4470f0(667)]>",
"<NSAutoresizingMaskLayoutConstraint:0x7fa4ea452700 h=-&- v=-&- 'UIView-Encapsulated-Layout-Top' V:|-(0)-[UIView:0x7fa4ea4470f0]  (Names: '|':UIWindow:0x7fa4ea444b20 )>"
)

Will attempt to recover by breaking constraint <NSLayoutConstraint:0x7fa4ea44d160 UIView:0x7fa4ea429290.centerY == UIView:0x7fa4ea4470f0.centerY>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.

Pode me ajudar? Muito obrigado


1
Cole as mensagens de erro como blocos de código, não como texto entre aspas. Isso significa que você precisa colocar quatro espaços no início de cada linha, não a >. Eu consertei isso para você neste momento.
rob mayoff

8
está faltando "translateAutoresizingMaskIntoConstraints = false"
Christian 'fuzi' Orgler

1
Você pode usar esta biblioteca incrível para restrições dinâmicas e simples. github.com/SnapKit/SnapKit
Aashish

Verifique no iOS as diferenças entre margens, inserções de borda, inserções de conteúdo, rects de alinhamento, margens de layout e âncoras . Vai melhorar a sua tomada de decisão entre as margens, âncoras, layoutguides ...
Mel

Aqui está o post que explica como adicionar restrições através do código: slicode.com/…
Shankar BS

Respostas:


1056

Você planeja ter um quadrado UIViewde largura: 100 e Altura: 100 centrado dentro UIViewde um UIViewController? Nesse caso, você pode tentar um dos 6 seguintes estilos de Layout automático (Swift 5 / iOS 12.2):


1. Usando o NSLayoutConstraintinicializador

override func viewDidLoad() {
    let newView = UIView()
    newView.backgroundColor = UIColor.red
    view.addSubview(newView)

    newView.translatesAutoresizingMaskIntoConstraints = false
    let horizontalConstraint = NSLayoutConstraint(item: newView, attribute: NSLayoutConstraint.Attribute.centerX, relatedBy: NSLayoutConstraint.Relation.equal, toItem: view, attribute: NSLayoutConstraint.Attribute.centerX, multiplier: 1, constant: 0)
    let verticalConstraint = NSLayoutConstraint(item: newView, attribute: NSLayoutConstraint.Attribute.centerY, relatedBy: NSLayoutConstraint.Relation.equal, toItem: view, attribute: NSLayoutConstraint.Attribute.centerY, multiplier: 1, constant: 0)
    let widthConstraint = NSLayoutConstraint(item: newView, attribute: NSLayoutConstraint.Attribute.width, relatedBy: NSLayoutConstraint.Relation.equal, toItem: nil, attribute: NSLayoutConstraint.Attribute.notAnAttribute, multiplier: 1, constant: 100)
    let heightConstraint = NSLayoutConstraint(item: newView, attribute: NSLayoutConstraint.Attribute.height, relatedBy: NSLayoutConstraint.Relation.equal, toItem: nil, attribute: NSLayoutConstraint.Attribute.notAnAttribute, multiplier: 1, constant: 100)
    view.addConstraints([horizontalConstraint, verticalConstraint, widthConstraint, heightConstraint])
}
override func viewDidLoad() {
    let newView = UIView()
    newView.backgroundColor = UIColor.red
    view.addSubview(newView)

    newView.translatesAutoresizingMaskIntoConstraints = false
    let horizontalConstraint = NSLayoutConstraint(item: newView, attribute: NSLayoutConstraint.Attribute.centerX, relatedBy: NSLayoutConstraint.Relation.equal, toItem: view, attribute: NSLayoutConstraint.Attribute.centerX, multiplier: 1, constant: 0)
    let verticalConstraint = NSLayoutConstraint(item: newView, attribute: NSLayoutConstraint.Attribute.centerY, relatedBy: NSLayoutConstraint.Relation.equal, toItem: view, attribute: NSLayoutConstraint.Attribute.centerY, multiplier: 1, constant: 0)
    let widthConstraint = NSLayoutConstraint(item: newView, attribute: NSLayoutConstraint.Attribute.width, relatedBy: NSLayoutConstraint.Relation.equal, toItem: nil, attribute: NSLayoutConstraint.Attribute.notAnAttribute, multiplier: 1, constant: 100)
    let heightConstraint = NSLayoutConstraint(item: newView, attribute: NSLayoutConstraint.Attribute.height, relatedBy: NSLayoutConstraint.Relation.equal, toItem: nil, attribute: NSLayoutConstraint.Attribute.notAnAttribute, multiplier: 1, constant: 100)
    NSLayoutConstraint.activate([horizontalConstraint, verticalConstraint, widthConstraint, heightConstraint])
}
override func viewDidLoad() {
    let newView = UIView()
    newView.backgroundColor = UIColor.red
    view.addSubview(newView)

    newView.translatesAutoresizingMaskIntoConstraints = false
    NSLayoutConstraint(item: newView, attribute: NSLayoutConstraint.Attribute.centerX, relatedBy: NSLayoutConstraint.Relation.equal, toItem: view, attribute: NSLayoutConstraint.Attribute.centerX, multiplier: 1, constant: 0).isActive = true
    NSLayoutConstraint(item: newView, attribute: NSLayoutConstraint.Attribute.centerY, relatedBy: NSLayoutConstraint.Relation.equal, toItem: view, attribute: NSLayoutConstraint.Attribute.centerY, multiplier: 1, constant: 0).isActive = true
    NSLayoutConstraint(item: newView, attribute: NSLayoutConstraint.Attribute.width, relatedBy: NSLayoutConstraint.Relation.equal, toItem: nil, attribute: NSLayoutConstraint.Attribute.notAnAttribute, multiplier: 1, constant: 100).isActive = true
    NSLayoutConstraint(item: newView, attribute: NSLayoutConstraint.Attribute.height, relatedBy: NSLayoutConstraint.Relation.equal, toItem: nil, attribute: NSLayoutConstraint.Attribute.notAnAttribute, multiplier: 1, constant: 100).isActive = true
}

2. Usando a linguagem de formato visual

override func viewDidLoad() {
    let newView = UIView()
    newView.backgroundColor = UIColor.red
    view.addSubview(newView)

    newView.translatesAutoresizingMaskIntoConstraints = false
    let views = ["view": view!, "newView": newView]
    let horizontalConstraints = NSLayoutConstraint.constraints(withVisualFormat: "H:[view]-(<=0)-[newView(100)]", options: NSLayoutConstraint.FormatOptions.alignAllCenterY, metrics: nil, views: views)
    let verticalConstraints = NSLayoutConstraint.constraints(withVisualFormat: "V:[view]-(<=0)-[newView(100)]", options: NSLayoutConstraint.FormatOptions.alignAllCenterX, metrics: nil, views: views)
    view.addConstraints(horizontalConstraints)
    view.addConstraints(verticalConstraints)
}
override func viewDidLoad() {
    let newView = UIView()
    newView.backgroundColor = UIColor.red
    view.addSubview(newView)

    newView.translatesAutoresizingMaskIntoConstraints = false
    let views = ["view": view!, "newView": newView]
    let horizontalConstraints = NSLayoutConstraint.constraints(withVisualFormat: "H:[view]-(<=0)-[newView(100)]", options: NSLayoutConstraint.FormatOptions.alignAllCenterY, metrics: nil, views: views)
    let verticalConstraints = NSLayoutConstraint.constraints(withVisualFormat: "V:[view]-(<=0)-[newView(100)]", options: NSLayoutConstraint.FormatOptions.alignAllCenterX, metrics: nil, views: views)
    NSLayoutConstraint.activate(horizontalConstraints)
    NSLayoutConstraint.activate(verticalConstraints)
}

3. Usando uma mistura de NSLayoutConstraintinicializador e Visual Format Language

override func viewDidLoad() {
    let newView = UIView()
    newView.backgroundColor = UIColor.red
    view.addSubview(newView)

    newView.translatesAutoresizingMaskIntoConstraints = false
    let views = ["newView": newView]
    let widthConstraints = NSLayoutConstraint.constraints(withVisualFormat: "H:[newView(100)]", options: NSLayoutConstraint.FormatOptions(rawValue: 0), metrics: nil, views: views)
    let heightConstraints = NSLayoutConstraint.constraints(withVisualFormat: "V:[newView(100)]", options: NSLayoutConstraint.FormatOptions(rawValue: 0), metrics: nil, views: views)
    let horizontalConstraint = NSLayoutConstraint(item: newView, attribute: NSLayoutConstraint.Attribute.centerX, relatedBy: NSLayoutConstraint.Relation.equal, toItem: view, attribute: NSLayoutConstraint.Attribute.centerX, multiplier: 1, constant: 0)
    let verticalConstraint = NSLayoutConstraint(item: newView, attribute: NSLayoutConstraint.Attribute.centerY, relatedBy: NSLayoutConstraint.Relation.equal, toItem: view, attribute: NSLayoutConstraint.Attribute.centerY, multiplier: 1, constant: 0)
    view.addConstraints(widthConstraints)
    view.addConstraints(heightConstraints)
    view.addConstraints([horizontalConstraint, verticalConstraint])
}
override func viewDidLoad() {
    let newView = UIView()
    newView.backgroundColor = UIColor.red
    view.addSubview(newView)

    newView.translatesAutoresizingMaskIntoConstraints = false
    let views = ["newView": newView]
    let widthConstraints = NSLayoutConstraint.constraints(withVisualFormat: "H:[newView(100)]", options: NSLayoutConstraint.FormatOptions(rawValue: 0), metrics: nil, views: views)
    let heightConstraints = NSLayoutConstraint.constraints(withVisualFormat: "V:[newView(100)]", options: NSLayoutConstraint.FormatOptions(rawValue: 0), metrics: nil, views: views)
    let horizontalConstraint = NSLayoutConstraint(item: newView, attribute: NSLayoutConstraint.Attribute.centerX, relatedBy: NSLayoutConstraint.Relation.equal, toItem: view, attribute: NSLayoutConstraint.Attribute.centerX, multiplier: 1, constant: 0)
    let verticalConstraint = NSLayoutConstraint(item: newView, attribute: NSLayoutConstraint.Attribute.centerY, relatedBy: NSLayoutConstraint.Relation.equal, toItem: view, attribute: NSLayoutConstraint.Attribute.centerY, multiplier: 1, constant: 0)
    NSLayoutConstraint.activate(widthConstraints)
    NSLayoutConstraint.activate(heightConstraints)
    NSLayoutConstraint.activate([horizontalConstraint, verticalConstraint])
}
override func viewDidLoad() {
    let newView = UIView()
    newView.backgroundColor = UIColor.red
    view.addSubview(newView)

    newView.translatesAutoresizingMaskIntoConstraints = false
    let views = ["newView": newView]
    let widthConstraints = NSLayoutConstraint.constraints(withVisualFormat: "H:[newView(100)]", options: NSLayoutConstraint.FormatOptions(rawValue: 0), metrics: nil, views: views)
    let heightConstraints = NSLayoutConstraint.constraints(withVisualFormat: "V:[newView(100)]", options: NSLayoutConstraint.FormatOptions(rawValue: 0), metrics: nil, views: views)
    NSLayoutConstraint.activate(widthConstraints)
    NSLayoutConstraint.activate(heightConstraints)
    NSLayoutConstraint(item: newView, attribute: NSLayoutConstraint.Attribute.centerX, relatedBy: NSLayoutConstraint.Relation.equal, toItem: view, attribute: NSLayoutConstraint.Attribute.centerX, multiplier: 1, constant: 0).isActive = true
    NSLayoutConstraint(item: newView, attribute: NSLayoutConstraint.Attribute.centerY, relatedBy: NSLayoutConstraint.Relation.equal, toItem: view, attribute: NSLayoutConstraint.Attribute.centerY, multiplier: 1, constant: 0).isActive = true
}

4. Usando UIView.AutoresizingMask

Nota: Molas e suportes serão convertidos em restrições de layout automático correspondentes em tempo de execução.

override func viewDidLoad() {
    let newView = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
    newView.backgroundColor = UIColor.red
    view.addSubview(newView)

    newView.translatesAutoresizingMaskIntoConstraints = true
    newView.center = CGPoint(x: view.bounds.midX, y: view.bounds.midY)
    newView.autoresizingMask = [UIView.AutoresizingMask.flexibleLeftMargin, UIView.AutoresizingMask.flexibleRightMargin, UIView.AutoresizingMask.flexibleTopMargin, UIView.AutoresizingMask.flexibleBottomMargin]
}

5. Usando NSLayoutAnchor

override func viewDidLoad() {
    let newView = UIView()
    newView.backgroundColor = UIColor.red
    view.addSubview(newView)

    newView.translatesAutoresizingMaskIntoConstraints = false
    let horizontalConstraint = newView.centerXAnchor.constraint(equalTo: view.centerXAnchor)
    let verticalConstraint = newView.centerYAnchor.constraint(equalTo: view.centerYAnchor)
    let widthConstraint = newView.widthAnchor.constraint(equalToConstant: 100)
    let heightConstraint = newView.heightAnchor.constraint(equalToConstant: 100)
    view.addConstraints([horizontalConstraint, verticalConstraint, widthConstraint, heightConstraint])
}
override func viewDidLoad() {
    let newView = UIView()
    newView.backgroundColor = UIColor.red
    view.addSubview(newView)

    newView.translatesAutoresizingMaskIntoConstraints = false
    let horizontalConstraint = newView.centerXAnchor.constraint(equalTo: view.centerXAnchor)
    let verticalConstraint = newView.centerYAnchor.constraint(equalTo: view.centerYAnchor)
    let widthConstraint = newView.widthAnchor.constraint(equalToConstant: 100)
    let heightConstraint = newView.heightAnchor.constraint(equalToConstant: 100)
    NSLayoutConstraint.activate([horizontalConstraint, verticalConstraint, widthConstraint, heightConstraint])
}
override func viewDidLoad() {
    let newView = UIView()
    newView.backgroundColor = UIColor.red
    view.addSubview(newView)

    newView.translatesAutoresizingMaskIntoConstraints = false
    newView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
    newView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
    newView.widthAnchor.constraint(equalToConstant: 100).isActive = true
    newView.heightAnchor.constraint(equalToConstant: 100).isActive = true
}

6. Usando intrinsicContentSizeeNSLayoutAnchor

import UIKit

class CustomView: UIView {

    override var intrinsicContentSize: CGSize {
        return CGSize(width: 100, height: 100)
    }

}

class ViewController: UIViewController {

    override func viewDidLoad() {
        let newView = CustomView()
        newView.backgroundColor = UIColor.red
        view.addSubview(newView)

        newView.translatesAutoresizingMaskIntoConstraints = false
        let horizontalConstraint = newView.centerXAnchor.constraint(equalTo: view.centerXAnchor)
        let verticalConstraint = newView.centerYAnchor.constraint(equalTo: view.centerYAnchor)
        NSLayoutConstraint.activate([horizontalConstraint, verticalConstraint])
    }

}

Resultado:

insira a descrição da imagem aqui


3
Existe uma maneira de animar as restrições de estilo de âncora?
Lionx31 26/09/15

5
Eu não sabia sobre a opção 5 / estilo âncora, eu realmente gosto porque ela se encaixa melhor com o modelo do que estou tentando fazer. Mas como eu não costumo atualizar as restrições depois que elas foram adicionadas, eu uso uma abreviação que as ativa ao mesmo tempo em que as cria: por exemplonewView.centerXAnchor.constraintEqualToAnchor(view.centerXAnchor).active = true
MathewS 1/15/15

se você deseja compensações, use isso, por exemplo, let h = newView.centerXAnchor.constraintEqualToAnchor (view.centerXAnchor, constant: 80) ou deixe w = updatesAvailablePopover.centerYAnchor.constraintEqualToAnchor (view.topAnchor, constant: 100)
DogCoffee

1
@JoeHuang não, a mão curta não funciona se você quiser alterar a restrição no futuro porque a taquigrafia está criando uma nova restrição. Você vai precisar usar os usos estilo âncora Imanou na resposta se você quiser uma referência para atualizar uma restrição no futuro :)
Mathews

1
Não esqueça a newView.translatesAutoresizingMaskIntoConstraints = falseparte! Demorei um pouco para ver.
huwr

247

Isso me ajuda a aprender visualmente, então essa é uma resposta suplementar.

Código padrão

override func viewDidLoad() {
    super.viewDidLoad()

    let myView = UIView()
    myView.backgroundColor = UIColor.blue
    myView.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(myView)

    // Add constraints code here
    // ...
}

Cada um dos exemplos a seguir é independente dos outros.

Fixar borda esquerda

myView.leading = leadingMargin + 20

insira a descrição da imagem aqui

Método 1: Estilo Anchor

let margins = view.layoutMarginsGuide
myView.leadingAnchor.constraint(equalTo: margins.leadingAnchor, constant: 20).isActive = true
  • Além leadingAnchor, há também trailingAnchor, topAnchore bottomAnchor.

Método 2: estilo NSLayoutConstraint

NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.leading, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.leadingMargin, multiplier: 1.0, constant: 20.0).isActive = true
  • Além .leadinghá também .trailing, .tope .bottom.
  • Além .leadingMarginhá também .trailingMargin, .topMargine .bottomMargin.

Definir largura e altura

width = 200
height = 100

insira a descrição da imagem aqui

Método 1: Estilo Anchor

myView.widthAnchor.constraint(equalToConstant: 200).isActive = true
myView.heightAnchor.constraint(equalToConstant: 100).isActive = true

Método 2: estilo NSLayoutConstraint

NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 200).isActive = true
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 100).isActive = true

Centro no recipiente

myView.centerX = centerX
myView.centerY = centerY

insira a descrição da imagem aqui

Método 1: Estilo Anchor

myView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
myView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true

Método 2: estilo NSLayoutConstraint

NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.centerX, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.centerX, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.centerY, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.centerY, multiplier: 1, constant: 0).isActive = true

Notas

  • O estilo âncora é o método preferido em relação ao NSLayoutConstraintestilo; no entanto, ele só está disponível no iOS 9; portanto, se você suporta o iOS 8, ainda deve usar o NSLayoutConstraintestilo.
  • Os exemplos acima mostraram apenas as uma ou duas restrições que estavam sendo focadas. No entanto, para colocar corretamente myViewno meu projeto de teste, eu precisava ter quatro restrições.

Leitura adicional


2
Muito agradável! Uma pequena nota: apenas uma das restrições leadingvs. centerXdeve ser especificada.
CyberDude

1
@ CyberDude, sim, você está correto. Eu pretendia que todos os exemplos acima fossem independentes um do outro, não adicionando todas as restrições à mesma exibição. Isso não é tão claro quanto eu gostaria.
Suragch 06/07

Você deixou de fora a necessária addConstraint()sobre viewa fim de fazer as layoutconstraints registo.
Martin

@Suragch Awesome;)
Amir Khan

34

Se você deseja preencher sua super visão, sugiro a maneira mais rápida:

    view.translatesAutoresizingMaskIntoConstraints = false
    let attributes: [NSLayoutAttribute] = [.top, .bottom, .right, .left]
    NSLayoutConstraint.activate(attributes.map {
        NSLayoutConstraint(item: view, attribute: $0, relatedBy: .equal, toItem: view.superview, attribute: $0, multiplier: 1, constant: 0)
    })

Caso contrário, se você precisar de restrições não iguais, confira o NSLayoutAnchor a partir do iOS 9. Geralmente, é muito mais fácil ler isso usando o NSLayoutConstraint diretamente:

    view.translatesAutoresizingMaskIntoConstraints = false
    view.topAnchor.constraint(equalTo: view.superview!.topAnchor).isActive = true
    view.bottomAnchor.constraint(equalTo: view.superview!.bottomAnchor).isActive = true
    view.leadingAnchor.constraint(equalTo: view.superview!.leadingAnchor, constant: 10).isActive = true
    view.trailingAnchor.constraint(equalTo: view.superview!.trailingAnchor, constant: 10).isActive = true

3
Baseado neste momento do vídeo da WWDC . Geralmente, não é eficiente ativar as restrições uma a uma, ou seja, fazer isActive = truenem sempre é uma boa ideia. É melhor e mais eficiente agrupar as restrições relacionadas em uma e ativá-las todas de uma vez NSLayoutConstraint.activate.
Honey

21

Restrições para várias visualizações no playground.

rápido 3+

  var yellowView: UIView!
    var redView: UIView!

    override func loadView() {

        // UI

        let view = UIView()
        view.backgroundColor = .white

        yellowView = UIView()
        yellowView.backgroundColor = .yellow
        view.addSubview(yellowView)

        redView = UIView()
        redView.backgroundColor = .red
        view.addSubview(redView)

        // Layout
        redView.translatesAutoresizingMaskIntoConstraints = false
        yellowView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            yellowView.topAnchor.constraint(equalTo: view.topAnchor, constant: 20),
            yellowView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
            yellowView.widthAnchor.constraint(equalToConstant: 80),
            yellowView.heightAnchor.constraint(equalToConstant: 80),

            redView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -20),
            redView.trailingAnchor.constraint(equalTo: view.trailingAnchor,constant: -20),
            redView.widthAnchor.constraint(equalToConstant: 80),
            redView.heightAnchor.constraint(equalToConstant: 80)
            ])

        self.view = view
    }

Na minha opinião, o xcode playground é o melhor lugar para aprender a adicionar restrições programaticamente.

Imagem de parque infantil


12

O problema, como sugere a mensagem de erro, é que você tem restrições do tipo NSAutoresizingMaskLayoutConstraintsque entram em conflito com as restrições explícitas, porque new_view.translatesAutoresizingMaskIntoConstraintsestão definidas como true.

Essa é a configuração padrão para as visualizações criadas no código. Você pode desativá-lo assim:

var new_view:UIView! = UIView(frame: CGRectMake(0, 0, 100, 100))
new_view.translatesAutoresizingMaskIntoConstraints = false

Além disso, suas restrições de largura e altura são estranhas. Se você deseja que a vista tenha uma largura constante, esta é a maneira correta:

new_view.addConstraint(NSLayoutConstraint(
    item:new_view, attribute:NSLayoutAttribute.Width,
    relatedBy:NSLayoutRelation.Equal,
    toItem:nil, attribute:NSLayoutAttribute.NotAnAttribute,
    multiplier:0, constant:100))

(Substitua 100 pela largura que deseja).

Se o seu destino de implantação for o iOS 9.0 ou posterior, você poderá usar este código mais curto:

new_view.widthAnchor.constraintEqualToConstant(100).active = true

De qualquer forma, para um layout como este (tamanho fixo e centralizado na visualização pai), seria mais simples usar a máscara de redimensionamento automático e permitir que o sistema traduza a máscara em restrições:

var new_view:UIView! = UIView(frame: CGRectMake(0, 0, 100, 100))
new_view.backgroundColor = UIColor.redColor();
view.addSubview(new_view);

// This is the default setting but be explicit anyway...
new_view.translatesAutoresizingMaskIntoConstraints = true

new_view.autoresizingMask = [ .FlexibleTopMargin, .FlexibleBottomMargin,
    .FlexibleLeftMargin, .FlexibleRightMargin ]

new_view.center = CGPointMake(view.bounds.midX, view.bounds.midY)

Observe que o uso do redimensionamento automático é perfeitamente legítimo, mesmo quando você também está usando o autolayout. (O UIKit ainda usa o dimensionamento automático em vários locais internamente.) O problema é que é difícil aplicar restrições adicionais a uma exibição que está usando o dimensionamento automático.


se o UIKit usar o redimensionamento automático internamente, isso poderia explicar o mau comportamento de restrições ancoradas no centro? Quando eu organizo uma coleção de UIButtons como uma subclasse de UIview, as restrições de âncora parecem funcionar, mas elas não funcionam quando eu as organizo como funções em um controlador de exibição. Se você pode poupar o tempo que você pode ter um olhar para este post [ stackoverflow.com/questions/40650951/... ler-nós-cant-realmente-add-qualquer-new-cercas-Devido]
Greg

Não, isso não explica o mau comportamento do seu código.
amigos estão dizendo sobre rob mayoff

12

Basicamente, envolveu 3 etapas

fileprivate func setupName() { 

    lblName.text = "Hello world"

    // Step 1
    lblName.translatesAutoresizingMaskIntoConstraints = false

    //Step 2
    self.view.addSubview(lblName)

    //Step 3
    NSLayoutConstraint.activate([
        lblName.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
        lblName.centerYAnchor.constraint(equalTo: self.view.centerYAnchor)
    ])
}

Isso coloca o rótulo "olá mundo" no centro da tela.

Consulte o link Restrições de reprodução automática programaticamente


9

Atualizado para o Swift 3

import UIKit

class ViewController: UIViewController {

let redView: UIView = {

    let view = UIView()
    view.translatesAutoresizingMaskIntoConstraints = false
    view.backgroundColor = .red
    return view
}()

override func viewDidLoad() {
    super.viewDidLoad()

    setupViews()
    setupAutoLayout()
}

func setupViews() {

    view.backgroundColor = .white
    view.addSubview(redView)
}

func setupAutoLayout() {

    // Available from iOS 9 commonly known as Anchoring System for AutoLayout...
    redView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20).isActive = true
    redView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -20).isActive = true

    redView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
    redView.heightAnchor.constraint(equalToConstant: 300).isActive = true

    // You can also modified above last two lines as follows by commenting above & uncommenting below lines...
    // redView.topAnchor.constraint(equalTo: view.topAnchor, constant: 20).isActive = true
    // redView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
 }
}

insira a descrição da imagem aqui

Tipo de restrições

 /*
// regular use
1.leftAnchor
2.rightAnchor
3.topAnchor
// intermediate use
4.widthAnchor
5.heightAnchor
6.bottomAnchor
7.centerXAnchor
8.centerYAnchor
// rare use
9.leadingAnchor
10.trailingAnchor
etc. (note: very project to project)
*/

Não se esqueça de adicionar youViewName.translatesAutoresizingMaskIntoConstraints = false
iAj

6

O layout automático é realizado aplicando restrições nas imagens. Use NSLayoutConstraint. É possível implementar um design ideal e bonito em todos os dispositivos. Por favor, tente o código abaixo.

import UIKit

class ViewController: UIViewController {

override func viewDidLoad() {
super.viewDidLoad()

let myImageView:UIImageView = UIImageView()
myImageView.backgroundColor = UIColor.red
myImageView.image = UIImage(named:"sample_dog")!
myImageView.translatesAutoresizingMaskIntoConstraints = false
myImageView.layer.borderColor = UIColor.red.cgColor
myImageView.layer.borderWidth = 10
self.view.addSubview(myImageView)

view.removeConstraints(view.constraints)


view.addConstraint(NSLayoutConstraint(
item: myImageView,
attribute: .top,
relatedBy: .equal,
toItem: view,
attribute: .top,
multiplier: 1,
constant:100)

)

view.addConstraint(NSLayoutConstraint(
item: myImageView,
attribute: .centerX,
relatedBy: .equal,
toItem: view,
attribute: .centerX,
multiplier: 1,
constant:0)
)

view.addConstraint(NSLayoutConstraint(
item: myImageView,
attribute: .height,
relatedBy: .equal,
toItem: view,
attribute: .width,
multiplier: 0.5,
constant:40))

view.addConstraint(NSLayoutConstraint(
item: myImageView,
attribute: .width,
relatedBy: .equal,
toItem: view,
attribute: .width,
multiplier: 0.5,
constant:40))

}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
}
}

insira a descrição da imagem aqui insira a descrição da imagem aqui


4

é um pouco diferente no xcode 7.3.1. é isso que eu proponho

   // creating the view
        let newView = UIView()
        newView.backgroundColor = UIColor.redColor()
        newView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(newView)

        // creating the constraint 

        // attribute and relation cannot be set directyl you need to create a cariable of them
        let layout11 = NSLayoutAttribute.CenterX
        let layout21 = NSLayoutRelation.Equal
        let layout31 = NSLayoutAttribute.CenterY
        let layout41 = NSLayoutAttribute.Width
        let layout51 = NSLayoutAttribute.Height
        let layout61 = NSLayoutAttribute.NotAnAttribute

        // defining all the constraint
        let horizontalConstraint = NSLayoutConstraint(item: newView, attribute: layout11, relatedBy: layout21, toItem: view, attribute: layout11, multiplier: 1, constant: 0)
        let verticalConstraint = NSLayoutConstraint(item: newView, attribute: layout31, relatedBy: layout21, toItem: view, attribute: layout31, multiplier: 1, constant: 0)
        let widthConstraint = NSLayoutConstraint(item: newView, attribute: layout41, relatedBy: layout21, toItem: nil, attribute: layout61, multiplier: 1, constant: 100)
        let heightConstraint = NSLayoutConstraint(item: newView, attribute: layout51, relatedBy: layout21, toItem: nil, attribute: layout61, multiplier: 1, constant: 100)

        // adding all the constraint
        NSLayoutConstraint.activateConstraints([horizontalConstraint,verticalConstraint,widthConstraint,heightConstraint])

translatesAutoresizingMaskIntoConstraints = false :))
Marin

4

Gostaria de acrescentar algum conceito teórico à resposta de Imanou Petit, para que se possa entender como o layout automático funciona.

Para entender o layout automático, considere sua visão como o objeto de borracha que é reduzido inicialmente.

Para colocar um objeto na tela, precisamos de 4 itens obrigatórios:

  • Coordenada X do objeto (posição horizontal).

  • Coordenada Y do objeto (posição vertical)

  • Largura do objeto

  • Altura do objeto.

1 Coordenada X: existem várias maneiras de atribuir coordenadas x a uma exibição.

Como restrição principal, restrição à direita, centro horizontal etc.

2 Coordenada Y: existem várias maneiras de fornecer coordenadas y a uma exibição:

Como restrição superior, restrição inferior, centro vertical etc.

3 Largura do objeto: Existem duas maneiras de restringir a largura a uma vista:

uma. Adicione restrição de largura fixa (considere essa restrição como barra de ferro de largura fixa e você prendeu o objeto de borracha horizontalmente a ele para que o objeto não encolha ou expanda)

b. Não adicione nenhuma restrição de largura, mas adicione a restrição de coordenadas x ao final da visão, à direita e à esquerda; essas duas restrições expandirão / encolherão o objeto de borracha, puxando / empurrando-o da extremidade, da frente e do final.

4 Altura do objeto: Semelhante à largura, também existem duas maneiras de restringir a altura de uma vista:

uma. Adicione restrição de altura fixa (considere essas restrições como uma barra de ferro de altura fixa e você prendeu o objeto de borracha verticalmente a ele para que o objeto não encolha ou expanda)

b. Não adicione nenhuma restrição de altura, mas adicione a restrição de coordenadas x nas extremidades superior e inferior da visão, essas duas restrições expandirão / reduzirão o objeto de borracha, puxando / empurrando-o das extremidades, superior e inferior.


3
    var xCenterConstraint : NSLayoutConstraint!
    var yCenterConstraint: NSLayoutConstraint!

 xCenterConstraint = NSLayoutConstraint(item: self.view, attribute: .CenterX, relatedBy: .Equal, toItem: (Your view NAme), attribute: .CenterX, multiplier: 1, constant: 0)
            self.view.addConstraint(xCenterConstraint)

 yCenterConstraint = NSLayoutConstraint(item: self.view, attribute: .CenterY, relatedBy: .Equal, toItem: (Your view Name), attribute: .CenterY, multiplier: 1, constant: 0)
            self.view.addConstraint(yCenterConstraint)

7
Por favor, explique o código e como ele responde à pergunta.
Ben Rhys-Lewis

3

Essa é uma maneira de adicionar restrições programaticamente

override func viewDidLoad() {
            super.viewDidLoad()


let myLabel = UILabel()
        myLabel.labelFrameUpdate(label: myLabel, text: "Welcome User", font: UIFont(name: "times new roman", size: 40)!, textColor: UIColor.red, textAlignment: .center, numberOfLines: 0, borderWidth: 2.0, BorderColor: UIColor.red.cgColor)
        self.view.addSubview(myLabel)


         let myLabelhorizontalConstraint = NSLayoutConstraint(item: myLabel, attribute: NSLayoutAttribute.centerX, relatedBy: NSLayoutRelation.equal, toItem: self.view, attribute: NSLayoutAttribute.centerX, multiplier: 1, constant: 0)
        let myLabelverticalConstraint = NSLayoutConstraint(item: myLabel, attribute: NSLayoutAttribute.centerY, relatedBy: NSLayoutRelation.equal, toItem: self.view, attribute: NSLayoutAttribute.centerY, multiplier: 1, constant: 0)
        let mylabelLeading = NSLayoutConstraint(item: myLabel, attribute: NSLayoutAttribute.leading, relatedBy: NSLayoutRelation.equal, toItem: self.view, attribute: NSLayoutAttribute.leading, multiplier: 1, constant: 10)
        let mylabelTrailing = NSLayoutConstraint(item: myLabel, attribute: NSLayoutAttribute.trailing, relatedBy: NSLayoutRelation.equal, toItem: self.view, attribute: NSLayoutAttribute.trailing, multiplier: 1, constant: -10)
        let myLabelheightConstraint = NSLayoutConstraint(item: myLabel, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 50)
        NSLayoutConstraint.activate(\[myLabelhorizontalConstraint, myLabelverticalConstraint, myLabelheightConstraint,mylabelLeading,mylabelTrailing\])
}

extension UILabel
{
    func labelFrameUpdate(label:UILabel,text:String = "This is sample Label",font:UIFont = UIFont(name: "times new roman", size: 20)!,textColor:UIColor = UIColor.red,textAlignment:NSTextAlignment = .center,numberOfLines:Int = 0,borderWidth:CGFloat = 2.0,BorderColor:CGColor = UIColor.red.cgColor){
        label.translatesAutoresizingMaskIntoConstraints = false
        label.text = text
        label.font = font
        label.textColor = textColor
        label.textAlignment = textAlignment
        label.numberOfLines = numberOfLines
        label.layer.borderWidth = borderWidth
        label.layer.borderColor = UIColor.red.cgColor
    }
}

insira a descrição da imagem aqui


2

Você está adicionando todas as restrições definidas às self.viewquais está incorreta, pois as restrições de largura e altura devem ser adicionadas à sua newView.

Além disso, como eu entendo, você deseja definir largura e altura constantes 100: 100. Nesse caso, você deve alterar seu código para:

var constW = NSLayoutConstraint(item: newView, 
    attribute: .Width, 
    relatedBy: .Equal, 
    toItem: nil, 
    attribute: .NotAnAttribute, 
    multiplier: 1, 
    constant: 100)
newView.addConstraint(constW)

var constH = NSLayoutConstraint(item: newView, 
    attribute: .Height, 
    relatedBy: .Equal, 
    toItem: nil, 
    attribute: .NotAnAttribute, 
    multiplier: 1, 
    constant: 100)
newView.addConstraint(constH)

2

Se você achar que o acima é feio. Você deve considerar o uso de uma DSL para restrições. Como o SnapKit, torna a API de restrição muito mais amigável

view.snp.makeConstraints { make in
    make.edges.equalToSuperview()
}

1

Podemos fazer isso facilmente com o rápido 5.1

configuração 1

  • subview alinhar para visualizar o centro
  • subview largura altura definida usando float

    view.addSubview(myView1)
    myView1.translatesAutoresizingMaskIntoConstraints = false
    NSLayoutConstraint.activate([
        myView1.centerXAnchor.constraint(equalTo: view.centerXAnchor),
        myView1.centerYAnchor.constraint(equalTo: view.centerYAnchor),
        myView1.widthAnchor.constraint(equalToConstant: 100),
        myView1.heightAnchor.constraint(equalToConstant: 100),
    ])

configuração 2

  • subview alinhar para visualizar a âncora principal e superior
  • largura da subvisualização definida usando a altura da largura da visualização

        view.addSubview(myView2)
        myView2.translatesAutoresizingMaskIntoConstraints = false
    
        NSLayoutConstraint.activate([
            myView2.leadingAnchor.constraint(equalTo: view.leadingAnchor,constant: 16),
            myView2.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor,constant: 16),
            myView2.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.3),
            myView2.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.3)
        ])

Resultado


0

Experimente esta elegante UIViewextensão de restrições. Você pode fazer restrições facilmente como:


 - firstView.coverWholeSuperview()
 - firstView.constraints(size: CGSize(width: 44, height: 44), centerX: view.centerXAnchor, centerY: view.centerXAnchor)
 - firstView.constraints(top: view.topAnchor, 
                         leading: secondView.leadingAnchor, 
                         bottom: view.bottomAnchor, 
                         trailing: secondView.trailingAnchor, 
                         padding: UIEdgeInsets(top: 12, left: 12, bottom: 12, right: 12))

Aqui está a extensão, basta copiá-la para o seu projeto.

extension UIView {
    /// Attaches all sides of the receiver to its parent view
    func coverWholeSuperview(margin: CGFloat = 0.0) {
        let view = superview
        layoutAttachTop(to: view, margin: margin)
        layoutAttachBottom(to: view, margin: margin)
        layoutAttachLeading(to: view, margin: margin)
        layoutAttachTrailing(to: view, margin: margin)

    }

    /// Attaches the top of the current view to the given view's top if it's a superview of the current view
    /// or to it's bottom if it's not (assuming this is then a sibling view).
    @discardableResult
    func layoutAttachTop(to: UIView? = nil, margin: CGFloat = 0.0) -> NSLayoutConstraint {

        let view: UIView? = to ?? superview
        let isSuperview = view == superview
        let constraint = NSLayoutConstraint(item: self, attribute: .top, relatedBy: .equal,
                                            toItem: view, attribute: isSuperview ? .top : .bottom, multiplier: 1.0,
                                            constant: margin)
        superview?.addConstraint(constraint)

        return constraint
    }

    /// Attaches the bottom of the current view to the given view
    @discardableResult
    func layoutAttachBottom(to: UIView? = nil, margin: CGFloat = 0.0, priority: UILayoutPriority? = nil) -> NSLayoutConstraint {

        let view: UIView? = to ?? superview
        let isSuperview = (view == superview) || false
        let constraint = NSLayoutConstraint(item: self, attribute: .bottom, relatedBy: .equal,
                                            toItem: view, attribute: isSuperview ? .bottom : .top, multiplier: 1.0,
                                            constant: -margin)
        if let priority = priority {
            constraint.priority = priority
        }
        superview?.addConstraint(constraint)

        return constraint
    }

    /// Attaches the leading edge of the current view to the given view
    @discardableResult
    func layoutAttachLeading(to: UIView? = nil, margin: CGFloat = 0.0) -> NSLayoutConstraint {

        let view: UIView? = to ?? superview
        let isSuperview = (view == superview) || false
        let constraint = NSLayoutConstraint(item: self, attribute: .leading, relatedBy: .equal,
                                            toItem: view, attribute: isSuperview ? .leading : .trailing, multiplier: 1.0,
                                            constant: margin)
        superview?.addConstraint(constraint)

        return constraint
    }

    /// Attaches the trailing edge of the current view to the given view
    @discardableResult
    func layoutAttachTrailing(to: UIView? = nil, margin: CGFloat = 0.0, priority: UILayoutPriority? = nil) -> NSLayoutConstraint {

        let view: UIView? = to ?? superview
        let isSuperview = (view == superview) || false
        let constraint = NSLayoutConstraint(item: self, attribute: .trailing, relatedBy: .equal,
                                            toItem: view, attribute: isSuperview ? .trailing : .leading, multiplier: 1.0,
                                            constant: -margin)
        if let priority = priority {
            constraint.priority = priority
        }
        superview?.addConstraint(constraint)

        return constraint
    }

    // For anchoring View
    struct AnchoredConstraints {
        var top, leading, bottom, trailing, width, height, centerX, centerY: NSLayoutConstraint?
    }

    @discardableResult
    func constraints(top: NSLayoutYAxisAnchor? = nil, leading: NSLayoutXAxisAnchor? = nil, bottom: NSLayoutYAxisAnchor? = nil,
                trailing: NSLayoutXAxisAnchor? = nil, padding: UIEdgeInsets = .zero, size: CGSize = .zero,
                centerX: NSLayoutXAxisAnchor? = nil, centerY: NSLayoutYAxisAnchor? = nil,
                centerXOffset: CGFloat = 0, centerYOffset: CGFloat = 0) -> AnchoredConstraints {

        translatesAutoresizingMaskIntoConstraints = false
        var anchoredConstraints = AnchoredConstraints()

        if let top = top {
            anchoredConstraints.top = topAnchor.constraint(equalTo: top, constant: padding.top)
        }

        if let leading = leading {
            anchoredConstraints.leading = leadingAnchor.constraint(equalTo: leading, constant: padding.left)
        }

        if let bottom = bottom {
            anchoredConstraints.bottom = bottomAnchor.constraint(equalTo: bottom, constant: -padding.bottom)
        }

        if let trailing = trailing {
            anchoredConstraints.trailing = trailingAnchor.constraint(equalTo: trailing, constant: -padding.right)
        }

        if size.width != 0 {
            anchoredConstraints.width = widthAnchor.constraint(equalToConstant: size.width)
        }

        if size.height != 0 {
            anchoredConstraints.height = heightAnchor.constraint(equalToConstant: size.height)
        }

        if let centerX = centerX {
            anchoredConstraints.centerX = centerXAnchor.constraint(equalTo: centerX, constant: centerXOffset)
        }

        if let centerY = centerY {
            anchoredConstraints.centerY = centerYAnchor.constraint(equalTo: centerY, constant: centerYOffset)
        }

        [anchoredConstraints.top, anchoredConstraints.leading, anchoredConstraints.bottom,
         anchoredConstraints.trailing, anchoredConstraints.width,
         anchoredConstraints.height, anchoredConstraints.centerX,
         anchoredConstraints.centerY].forEach { $0?.isActive = true }

        return anchoredConstraints
    }
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.