Как программно добавить ограничения с помощью Swift

311

Я пытаюсь понять это с прошлой недели, не продвинувшись дальше. Итак, мне нужно применить некоторые ограничения программно в Swift к UIView с помощью этого кода:

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

Но Xcode возвращает этот странный вывод:

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.

Вы можете мне помочь? Большое спасибо

  • 1
    Пожалуйста, вставляйте сообщения об ошибках как блоки кода, а не как текст в кавычках. Это означает, что вам нужно поставить четыре пробела в начале каждой строки, а не > . Я исправил это для тебя на этот раз.
  • 6
    вам не хватает "translateAutoresizingMaskIntoConstraints = false"
Показать ещё 2 комментария
Теги:
xcode
autolayout
nslayoutconstraint
uiview

15 ответов

816

Планируете ли вы иметь квадрат UIView ширины: 100 и Height: 100 в центре UIView UIViewController? Если это так, вы можете попробовать один из 6 следующих стилей Auto Layout (Swift 4.2/iOS 12):


1. Использование инициализатора NSLayoutConstraint

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. Использование языка Visual Format

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. Использование сочетания инициализатора NSLayoutConstraint и языка Visual Format

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. Использование UIView.AutoresizingMask

Примечание. Спрингс и Struts будут переведены на соответствующие ограничения макета во время выполнения.

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. Использование 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. Использование intrinsicContentSize и NSLayoutAnchor

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

}

Результат:

Изображение 1668

  • 3
    Есть ли способ анимировать ограничения стиля привязки?
  • 5
    Я не знал о варианте 5 / якорный стиль, он мне действительно нравится, потому что он лучше всего соответствует модели того, что я пытаюсь сделать. Но поскольку я не склонен обновлять ограничения после их добавления, я использую сокращение, которое активирует их одновременно с их созданием: например, newView.centerXAnchor.constraintEqualToAnchor(view.centerXAnchor).active = true
Показать ещё 13 комментариев
187

Это помогает мне узнать визуально, так что это дополнительный ответ.

Код котла

override func viewDidLoad() {
    super.viewDidLoad()

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

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

Каждый из следующих примеров не зависит от других.

Закрепить левый край

myView.leading = leadingMargin + 20

Изображение 1669

Метод 1: Стиль привязки

let margins = view.layoutMarginsGuide
myView.leadingAnchor.constraint(equalTo: margins.leadingAnchor, constant: 20).isActive = true
  • В дополнение к leadingAnchor также есть trailingAnchor, topAnchor и bottomAnchor.

Метод 2: стиль NSLayoutConstraint

NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.leading, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.leadingMargin, multiplier: 1.0, constant: 20.0).isActive = true
  • В дополнение к .leading также есть .trailing, .top и .bottom.
  • В дополнение к .leadingMargin также есть .trailingMargin, .topMargin и .bottomMargin.

Установить ширину и высоту

width = 200
height = 100

Изображение 1670

Метод 1: Стиль привязки

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

Метод 2: стиль 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

Центр в контейнере

myView.centerX = centerX
myView.centerY = centerY

Изображение 1671

Метод 1: Стиль привязки

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

Метод 2: стиль 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

Примечания

  • Стиль привязки - предпочтительный метод по сравнению с NSLayoutConstraint Style, однако он доступен только для iOS 9, поэтому, если вы поддерживаете iOS 8, вы должны использовать NSLayoutConstraint Style.
  • В приведенных выше примерах показано только одно или два ограничения, на которые основное внимание уделялось. Однако, чтобы правильно разместить myView в моем тестовом проекте, мне нужно было четыре ограничения.

Дополнительная литература

  • 2
    Очень хорошо! Одно небольшое замечание: следует указывать только одно из ограничений по сравнению с leading и centerX .
  • 1
    @ CyberDude, да, ты прав. Я хотел, чтобы все приведенные выше примеры были независимы друг от друга, а не добавляли все ограничения к одному и тому же представлению. Это не так ясно, как хотелось бы.
Показать ещё 5 комментариев
22

Если вы хотите заполнить свой супер-просмотр, я предлагаю осторожный способ:

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

Другое дело, если вам нужны не равные ограничения, проверьте NSLayoutAnchor на iOS 9. Его часто гораздо легче читать, используя напрямую NSLayoutConstraint:

    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
  • 1
    Основанный на этом моменте видео WWDC . Как правило, неэффективно активировать ограничения одно за другим, т. isActive = true не всегда является хорошей идеей. Лучше и эффективнее сгруппировать связанные ограничения в одно и активировать их все сразу, используя NSLayoutConstraint.activate .
11

Ограничения для нескольких видов на детской площадке.

быстрый 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
    }

На мой взгляд, игровая площадка xcode - это лучшее место для обучения программным ограничениям.

Изображение 1672

11

Проблема, как следует из сообщения об ошибке, заключается в том, что у вас есть ограничения типа NSAutoresizingMaskLayoutConstraints, которые конфликтуют с вашими явными ограничениями, потому что для параметра new_view.translatesAutoresizingMaskIntoConstraints установлено значение true.

Это значение по умолчанию для представлений, созданных в коде. Вы можете отключить его следующим образом:

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

Кроме того, ваши ограничения по ширине и высоте являются странными. Если вы хотите, чтобы представление имело постоянную ширину, это правильный способ:

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

(Замените 100 на ширину, которую вы хотите, чтобы она имела.)

Если целью развертывания является iOS 9.0 или новее, вы можете использовать этот более короткий код:

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

В любом случае, для такого макета (фиксированный размер и по центру в виде родителя) было бы проще использовать маску авторезистировки и позволить системе переводить маску в ограничения:

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)

Обратите внимание, что использование авторезистирования совершенно законно, даже если вы также используете автозапуск. (UIKit по-прежнему использует авторезистирование во многих местах внутри.) Проблема заключается в том, что трудно применить дополнительные ограничения для представления, которое использует авторезистор.

  • 0
    если UIKit использует внутреннее автоматическое изменение размера, может ли это объяснить неправильное поведение ограничений, закрепленных в центре? Когда я организую коллекцию UIButton-ов как подкласс UIview, якорные ограничения работают, но они не работают, когда я организую их как функции в viewcontroller. Если вы можете сэкономить время, вы можете взглянуть на этот пост [ stackoverflow.com/questions/40650951/… r ler-we-cant-фактически-add-any-new-fences-due]
  • 0
    Нет, это не объясняет неправильное поведение вашего кода.
4

Автоматическая компоновка реализуется путем применения ограничений на изображения. Используйте NSLayoutConstraint. На всех устройствах можно реализовать идеальный и красивый дизайн. Пожалуйста, попробуйте код ниже.

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()
}
}

Изображение 1673 Изображение 1674

3

Обновлено для 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
 }
}

Изображение 1675

Тип ограничений

 /*
// 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)
*/
  • 0
    Не забудьте добавить, youViewName.translatesAutoresizingMaskIntoConstraints = false
3

он немного отличается в xcode 7.3.1. это то, что я придумал

   // 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])
  • 0
    translatesAutoresizingMaskIntoConstraints = false :))
2

Хотелось бы добавить некоторую теоретическую концепцию к ответу Иману Петит, чтобы можно было понять, как работает макет.

Чтобы понять автоматическую компоновку, рассмотрите ваш взгляд как резиновый объект, который сначала сжимается.

Чтобы разместить объект на экране, нам нужно 4 обязательных элемента:

  • X координата объекта (горизонтальное положение).

  • Y координаты объекта (вертикальное положение)

  • Ширина объектов

  • Высота объектов.

1 Координата X: Существует несколько способов предоставления x координат для представления.

Такие, как Leading constraint, Trailing constraint, Horizontally center и т.д.

2 Координата Y: Существует несколько способов предоставления y координат:

Такие, как ограничение сверху, нижнее ограничение, вертикальный центр и т.д.

3 Ширина объекта: существует два способа ограничения ширины для представления:

а. Добавьте ограничение фиксированной ширины (рассмотрите это ограничение как железный стержень фиксированной ширины, и вы подключили свой объект каучуков горизонтально к нему, так что объект каучуков не будет сжиматься или расширяться)

б. Не добавляйте ограничение ширины, но добавляйте ограничение на координаты x и конец и конец ведущего конца, эти два ограничения будут расширять/сокращать ваш объект каучуков, вытягивая/толкая его с обоих концов, ведущих и заканчивая.

4 Высота объекта. Подобно ширине, есть два способа указания ограничения высоты для представления:

а. Добавьте фиксированное ограничение высоты (рассмотрите эти ограничения как железный стержень с фиксированной высотой, и вы привязали свой объект каучуков вертикально к нему, поэтому объект каучуков не сжимается и не расширяется)

б. Не добавляйте ограничение по высоте, но добавляйте ограничение на координаты x как для верхнего, так и для верхнего конца, эти два ограничения будут расширять/сокращать ваш объект каучуков, вытягивая/толкая его с обоих концов, сверху и снизу.

2

Это один из способов добавления программ программно

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
    }
}

Изображение 1676

2
    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)
  • 6
    Пожалуйста, объясните код и как он отвечает на вопрос.
1

В основном это было 3 шага

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

Это помещает ярлык "привет мир" в центр экрана.

Пожалуйста, обратитесь к ссылкам Ограничения Autolayout программно

1

Если вы обнаружите, что это было уродливо. Вы должны рассмотреть возможность использования DSL для ограничений. Например SnapKit Делает API ограничений более удобным для пользователя.

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

Я создал эти взгляды в приведенном рис. используя Autolayout программно. Вы получите глубокое понимание ограничений и как их следует применять должным образом.

Вы можете перечислить его здесь "Введение в Autolayout"

Изображение 1677

0

Вы добавляете все определенные ограничения в self.view, что неверно, поскольку ограничение ширины и высоты должно быть добавлено к вашему newView.

Кроме того, как я понимаю, вы хотите установить постоянную ширину и высоту 100: 100. В этом случае вы должны изменить свой код на:

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)

Ещё вопросы

Сообщество Overcoder
Наверх
Меню