Как программно установить ограничения соотношения сторон в iOS?

85

Я использовал автоматический макет для своих контроллеров представления. Я установил позиции V и H в ограничениях, но я хочу знать, как я могу увеличить размер кнопки, когда он меняется на 5s, 6 и 6 Plus. Вот так я добавил ограничения для кнопки входа в систему:

NSArray *btncon_V=[NSLayoutConstraint constraintsWithVisualFormat:@"V:[btnLogin(40)]" options:0 metrics:nil views:viewsDictionary];
[btnLogin addConstraints:btncon_V];

NSArray *btncon_POS_H=[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-100-[btnLogin]-100-|" options:0 metrics:nil views:viewsDictionary];
[self.view addConstraints:btncon_POS_H];


NSArray *btncon_POS_V=[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-70-[Title]-130-[lblFirst]-0-[lblSecond]-20-[textusername]-10-[txtpassword]-10-[btnLogin]" options:0 metrics:nil views:viewsDictionary];

[self.view addConstraints:btncon_POS_V];

Но моя проблема в том, что, хотя он управляет левым и правым боковым зазором, в iPhone 6 и 6 Plus он растягивается, поскольку высота фиксирована. Как я могу увеличить размер в соответствии с размером экрана? Я думаю, это может быть соотношение сторон, но как я могу установить ограничение соотношения сторон в коде?

IRD
источник
2
Отметьте этот ответ: stackoverflow.com/a/12526630/3202193
Ашиш Каккад,

Ответы:

84

Как это. Попробуй один раз.

[self.yourview setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.yourview addConstraint:[NSLayoutConstraint
                                  constraintWithItem:self.yourview
                                  attribute:NSLayoutAttributeHeight
                                  relatedBy:NSLayoutRelationEqual
                                  toItem:self.yourview
                                  attribute:NSLayoutAttributeWidth
                                  multiplier:(self.yourview.frame.size.height / self.yourview.frame.size.width)
                                  constant:0]];

или вместо (self.yourview.frame.size.height / self.yourview.frame.size.width)вы можете использовать любое значение с плавающей запятой. Благодарю.

Swift 3.0 -

self.yourview!.translatesAutoresizingMaskIntoConstraints = false
self.yourview!.addConstraint(NSLayoutConstraint(item: self.yourview!,
                                          attribute: NSLayoutAttribute.height,
                                          relatedBy: NSLayoutRelation.equal,
                                          toItem: self.yourview!,
                                          attribute: NSLayoutAttribute.width,
                                          multiplier: self.yourview.frame.size.height / self.yourview.frame.size.width,
                                          constant: 0))
Махеш Агравал
источник
Это дает мне эту ошибку. Завершение приложения из-за неперехваченного исключения «NSInternalInconsistencyException», причина: «Множитель не конечен! Это незаконно. множитель: nan '
IRD
2
это означает, что в сценарии, например, если высота равна 100, а ширина равна 200, и в моем коде вы задали множитель 0,5, тогда, если ваша высота увеличится до 150, изменив любое другое ограничение, ширина автоматически увеличится до 300. Но для этого вам нужно для увеличения одного ограничения вида, например ширины или высоты.
Махеш Агравал
1
он будет иметь высоту: ширина = 1: 2, то есть 0,5.
Махеш Агравал,
3
Не забудьте добавить эту строку перед установкой каких-либо ограничений программно: [self.yourview setTranslatesAutoresizingMaskIntoConstraints:NO];
atulkhatri 01
1
При использовании ограничений все мои размеры кадра были нулевыми. Вместо этого, чтобы получить соотношение сторон, я использовалself.yourview.intrinsicContentSize
Phlippie Bosman 07
89

Якоря макета - это наиболее удобный способ программной установки ограничений.

Допустим, вы хотите установить для кнопки соотношение сторон 5: 1, тогда вам следует использовать:

button.heightAnchor.constraint(equalTo: button.widthAnchor, multiplier: 1.0/5.0).isActive = true

Вот полный код:

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let button = UIButton(type: .custom)
        button.setTitle("Login", for: .normal)
        button.backgroundColor = UIColor.darkGray

        self.view.addSubview(button)

        button.translatesAutoresizingMaskIntoConstraints = false

        let margins = view.layoutMarginsGuide

        button.leadingAnchor.constraint(equalTo: margins.leadingAnchor, constant: 20.0).isActive = true
        button.trailingAnchor.constraint(equalTo: margins.trailingAnchor, constant: -20.0).isActive = true
        button.bottomAnchor.constraint(equalTo: margins.bottomAnchor, constant: -20.0).isActive = true
        button.heightAnchor.constraint(equalTo: button.widthAnchor, multiplier: 1.0/5.0).isActive = true
    }

}

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

Просмотр результатов

Евгений Брюсов
источник
14

Swift 3:

yourView.addConstraint(NSLayoutConstraint(item: yourView,
                                          attribute: .height,
                                          relatedBy: .equal,
                                          toItem: yourView,
                                          attribute: .width,
                                          multiplier: 9.0 / 16.0,
                                          constant: 0))
RNHTTR
источник
1
Для iOS 8 и выше вы должны использовать свойство isActive NSLayoutConstraint вместо вызова addConstraint (:). aspectRatioConstraint.isActive = true
dvdblk
Почему бы вам не использовать .widthв качестве первого атрибута? В результате attr2 * multiplier соотношение сторон будет width / heightтаким, что width = height * aspectRatio, если мы поместим .heightв первый атрибут, а aspectRatioв multiplier- результат будет полностью обратным.
Кими Чиу,
13

Вы можете установить «Ограничение высоты» во время разработки в Интерфейсном Разработчике. Просто установите флажок «Удалить во время сборки», и он удалится, когда приложение запустится.

введите описание изображения здесь После этого вы можете добавить ограничение «Соотношение сторон», например, в методе viewDidLoad.

В Xamain.iOS для "16: 9" это выглядит так:

    this.ImageOfTheDay.AddConstraint(NSLayoutConstraint.Create(
            this.ImageOfTheDay,
            NSLayoutAttribute.Height,
            NSLayoutRelation.Equal,
            this.ImageOfTheDay,
            NSLayoutAttribute.Width,
            9.0f / 16.0f,
            0));

Или, как сказал Махеш Агравал :

    [self.ImageOfTheDay addConstraint:[NSLayoutConstraint
                              constraintWithItem:self.ImageOfTheDay
                              attribute:NSLayoutAttributeHeight
                              relatedBy:NSLayoutRelationEqual
                              toItem:self.ImageOfTheDay
                              attribute:NSLayoutAttributeWidth
                              multiplier:(9.0f / 16.0f)
                              constant:0]];
Занаил
источник
12

Расширение помощника на UIView

extension UIView {

    func aspectRation(_ ratio: CGFloat) -> NSLayoutConstraint {

        return NSLayoutConstraint(item: self, attribute: .height, relatedBy: .equal, toItem: self, attribute: .width, multiplier: ratio, constant: 0)
    }
}

И использование:

view.aspectRation(1.0/1.0).isActive = true

Михал Зиобро
источник
и использование: view.aspectRation (1.0 / 1.0)
Michał Ziobro
1
Это действительно элегантное решение, запрещающее несколько типов: 1. Параметр toItem установлен .selfвместо self2. И использование в комментариях должно быть. view.aspectRation(1.0/1.0).isActive = true Я тестировал это в Xcode 10.2.1 Swift 5.
Панкадж Кулкарни
3

Я попробовал все ответы выше, но не сработал, и это мое решение с быстрым 3:

let newConstraint = NSLayoutConstraint(item: yourView, attribute: .width, relatedBy: .equal, toItem: yourView, attribute: .height, multiplier: 560.0/315.0, constant: 0)
yourView.addConstraint(newConstraint)
NSLayoutConstraint.activate([newConstraint])  
NSLayoutConstraint.deactivate(yourView.constraints)
yourView.layoutIfNeeded()
Tuandapen
источник
Вы всегда должны деактивировать (потенциально конфликтующие) ограничения перед добавлением новых, чтобы избежать ошибок автоматического размещения
Джон
0

Для представлений есть ограничения, а также есть свойства.

Соотношение сторон - это свойство представления , поэтому вы можете установить его в режиме содержимого, например

imageView.contentMode = .scaleAspectFit

это приведет к тому, что представление не изменит соотношения, если, например,

  • высота или ширина больше, чем умещается на экране
  • высота была жестко запрограммирована и поэтому не может адаптироваться к экранам разных размеров.
Валериана
источник
Вопрос не в ImageView и его режиме содержимого, а в автоматическом макете и ограничениях. Из Interface Builder вы можете установить ограничение соотношения сторон, которое в конце создает ограничение ширины к высоте с множителем.
Gunhan
@Gunhan вопрос касается того, как установить его программно. Так что иметь возможность установить его в построителе интерфейса приятно знать, но это не имеет отношения к этому вопросу.
валериана
Я думаю, вы неправильно поняли то, что я сказал ранее. В этом вопросе никто не говорит об ImageView. ИТ - это автоматическая компоновка и ограничения, которые нужно делать программно. Я сказал, что когда вы устанавливаете его в построителе интерфейса, он создает ограничение ширины и высоты. Я не говорил вам создавать его через IB. Чтобы сделать то же самое программно, вы должны создать его вот view.widthAnchor.constraint(equalTo: view.heightAnchor, multiplier: aspectRatio, constant: 0)так
Gunhan