Ширина та висота дорівнюють його superView за допомогою програмного авторозкладки?


83

Я шукав багато фрагментів у мережі, і досі не можу знайти відповіді на свою проблему. Моє питання полягає в тому, що у мене є scrollView (SV), і я хочу додати кнопку всередині scrollView (SV) програмно з однаковою шириною та висотою його супервигляду, яка є scrollView (SV), щоб при обертанні користувача кнопка пристрою мала однаковий кадр scrollView (SV). як зробити NSLayout / NSLayoutConstraint? Дякую

Відповіді:


125

Якщо хтось шукає рішення Swift - я б створив розширенняUIView Swift, яке допоможе вам кожного разу, коли ви хочете прив’язати кадр підпоглядів до його меж суперпереглядів:

Свіфт 2:

extension UIView {

    /// Adds constraints to this `UIView` instances `superview` object to make sure this always has the same size as the superview.
    /// Please note that this has no effect if its `superview` is `nil` – add this `UIView` instance as a subview before calling this.
    func bindFrameToSuperviewBounds() {
        guard let superview = self.superview else {
            print("Error! `superview` was nil – call `addSubview(view: UIView)` before calling `bindFrameToSuperviewBounds()` to fix this.")
            return
        }

        self.translatesAutoresizingMaskIntoConstraints = false
        superview.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-0-[subview]-0-|", options: .DirectionLeadingToTrailing, metrics: nil, views: ["subview": self]))
        superview.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-0-[subview]-0-|", options: .DirectionLeadingToTrailing, metrics: nil, views: ["subview": self]))
    }

}

Свіфт 3:

extension UIView {

    /// Adds constraints to this `UIView` instances `superview` object to make sure this always has the same size as the superview.
    /// Please note that this has no effect if its `superview` is `nil` – add this `UIView` instance as a subview before calling this.
    func bindFrameToSuperviewBounds() {
        guard let superview = self.superview else {
            print("Error! `superview` was nil – call `addSubview(view: UIView)` before calling `bindFrameToSuperviewBounds()` to fix this.")
            return
        }

        self.translatesAutoresizingMaskIntoConstraints = false
        superview.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[subview]-0-|", options: .directionLeadingToTrailing, metrics: nil, views: ["subview": self]))
        superview.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-0-[subview]-0-|", options: .directionLeadingToTrailing, metrics: nil, views: ["subview": self]))
    }
}

Свіфт 4.2:

extension UIView {

    /// Adds constraints to this `UIView` instances `superview` object to make sure this always has the same size as the superview.
    /// Please note that this has no effect if its `superview` is `nil` – add this `UIView` instance as a subview before calling this.
    func bindFrameToSuperviewBounds() {
        guard let superview = self.superview else {
            print("Error! `superview` was nil – call `addSubview(view: UIView)` before calling `bindFrameToSuperviewBounds()` to fix this.")
            return
        }

        self.translatesAutoresizingMaskIntoConstraints = false
        self.topAnchor.constraint(equalTo: superview.topAnchor, constant: 0).isActive = true
        self.bottomAnchor.constraint(equalTo: superview.bottomAnchor, constant: 0).isActive = true
        self.leadingAnchor.constraint(equalTo: superview.leadingAnchor, constant: 0).isActive = true
        self.trailingAnchor.constraint(equalTo: superview.trailingAnchor, constant: 0).isActive = true

    }
}

Тоді просто назвіть це так :

// after adding as a subview, e.g. `view.addSubview(subview)`
subview.bindFrameToSuperviewBounds()

під час створення користувацького UIView за допомогою .xib, bindFrameToSuperviewBounds слід викликати в межах 'required init? (coder aDecoder)' відразу після self.addSubview (self.view)
user1603721

Варто зазначити, що рішення, що використовують візуальний формат, не є безпечними для зони. Якщо, наприклад, ви викликаєте це у поданні, яке знаходиться всередині навігаційного контролера, що показує панелі навігації та панелі інструментів, ваш вигляд буде переходити під панель навігації та під панель інструментів, якщо вона йде так далеко вниз.
Andy Ibanez,

Це також працює як рішення для Swift 5. Я не зміг змусити свій власний subView адаптуватися до розміру parentView за допомогою AutoLayout. Використовуючи це після додавання підзаголовка, це працювало як шарм.
toni_piu

Рішення Swift 4.2 працює добре. Ви навіть можете зробити його дещо коротшим, видаливши constant: 0деталь.
Zyphrax

69

Я не впевнений, що це найефективніший спосіб це зробити, але це працює ..

UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.translatesAutoresizingMaskIntoConstraints = NO;
// initialize


[coverForScrolView addSubview:button];

NSLayoutConstraint *width =[NSLayoutConstraint
                                    constraintWithItem:button
                                    attribute:NSLayoutAttributeWidth
                                    relatedBy:0
                                    toItem:coverForScrolView
                                    attribute:NSLayoutAttributeWidth
                                    multiplier:1.0
                                    constant:0];
NSLayoutConstraint *height =[NSLayoutConstraint
                                     constraintWithItem:button
                                     attribute:NSLayoutAttributeHeight
                                     relatedBy:0
                                     toItem:coverForScrolView
                                     attribute:NSLayoutAttributeHeight
                                     multiplier:1.0
                                     constant:0];
NSLayoutConstraint *top = [NSLayoutConstraint
                                   constraintWithItem:button
                                   attribute:NSLayoutAttributeTop
                                   relatedBy:NSLayoutRelationEqual
                                   toItem:coverForScrolView
                                   attribute:NSLayoutAttributeTop
                                   multiplier:1.0f
                                   constant:0.f];
NSLayoutConstraint *leading = [NSLayoutConstraint
                                       constraintWithItem:button
                                       attribute:NSLayoutAttributeLeading
                                       relatedBy:NSLayoutRelationEqual
                                       toItem:coverForScrolView
                                       attribute:NSLayoutAttributeLeading
                                       multiplier:1.0f
                                       constant:0.f];
[coverForScrolView addConstraint:width];
[coverForScrolView addConstraint:height];
[coverForScrolView addConstraint:top];
[coverForScrolView addConstraint:leading];

4
Було б набагато ефективніше використовуватиNSLayoutConstraint.activateConstraints([width, height, top, leading])
Берік,

Ви можете використовувати[coverForScrolView addConstraints:@[width, height, top, leading]];
Іслам Q.

1
варто зазначити (через роки) цей код надзвичайно застарілий . тепер набагато простіше додати обмеження - див. будь-яку відповідь 2017 року
Fattie,

49

Це посилання може вам допомогти, дотримуйтесь інструкцій: http://www.raywenderlich.com/20881/beginning-auto-layout-part-1-of-2

РЕДАГУВАТИ:

використовуйте наступний фрагмент коду, де subview - це ваш subivew.

[subview setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.view addConstraints:[NSLayoutConstraint
                           constraintsWithVisualFormat:@"H:|-0-[subview]-0-|"
                           options:NSLayoutFormatDirectionLeadingToTrailing
                           metrics:nil
                           views:NSDictionaryOfVariableBindings(subview)]];
[self.view addConstraints:[NSLayoutConstraint
                           constraintsWithVisualFormat:@"V:|-0-[subview]-0-|"
                           options:NSLayoutFormatDirectionLeadingToTrailing
                           metrics:nil
                           views:NSDictionaryOfVariableBindings(subview)]];

4
У цьому випадку візуальним форматом може бути також V:|[subview]|іH:|[subview]|
Густаво Барбоза

4
варто зазначити (через роки) цей код надзвичайно застарілий . тепер набагато простіше додати обмеження - див. будь-яку відповідь 2017 року
Fattie,

19

addConstraintі removeConstraintметоди для UIView будуть застарілими, тому варто використовувати 'зручності створення обмежень':

view.topAnchor.constraint(equalTo: superView.topAnchor, constant: 0).isActive = true
view.bottomAnchor.constraint(equalTo: superView.bottomAnchor, constant: 0).isActive = true
view.leadingAnchor.constraint(equalTo: superView.leadingAnchor, constant: 0).isActive = true
view.trailingAnchor.constraint(equalTo: superView.trailingAnchor, constant: 0).isActive = true

Це добре працює. Ви навіть можете зробити його дещо коротшим, видаливши constant: 0деталь.
Zyphrax

8

Підхід №1: Через розширення UIView

Ось більш функціональний підхід у Swift 3+ з попередньою умовою замість print(що може легко загинути в консолі). Цей повідомляє про помилки програміста як про невдалі збірки.

Додайте це розширення до свого проекту:

extension UIView {
    /// Adds constraints to the superview so that this view has same size and position.
    /// Note: This fails the build if the `superview` is `nil` – add it as a subview before calling this.
    func bindEdgesToSuperview() {
        guard let superview = superview else {
            preconditionFailure("`superview` was nil – call `addSubview(view: UIView)` before calling `bindEdgesToSuperview()` to fix this.")
        }
        translatesAutoresizingMaskIntoConstraints = false
        ["H:|-0-[subview]-0-|", "V:|-0-[subview]-0-|"].forEach { visualFormat in
            superview.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: visualFormat, options: .directionLeadingToTrailing, metrics: nil, views: ["subview": self]))
        }
    }
}

Тепер просто назвіть це так:

// after adding as a subview, e.g. `view.addSubview(subview)`
subview.bindEdgesToSuperview()

Зверніть увагу, що вищезазначений метод вже інтегрований у мій фреймворк HandyUIKit, який також додає ще кілька зручних помічників інтерфейсу користувача у ваш проект.


Підхід №2: Використання фреймворку

Якщо ви багато працюєте з програмними обмеженнями у своєму проекті, то я рекомендую вам перевірити SnapKit . Це робить роботу з обмеженнями набагато простішою та менш схильною до помилок .

Дотримуйтесь інструкцій із встановлення в документації, щоб включити SnapKit у свій проект. Потім імпортуйте його у верхній частині вашого файлу Swift:

import SnapKit

Тепер ви можете досягти того ж саме лише цим:

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

6

Свіфт 3:

import UIKit

extension UIView {

    func bindFrameToSuperviewBounds() {
        guard let superview = self.superview else {
            print("Error! `superview` was nil – call `addSubview(view: UIView)` before calling `bindFrameToSuperviewBounds()` to fix this.")
            return
        }

        self.translatesAutoresizingMaskIntoConstraints = false
        superview.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[subview]-0-|", options: .directionLeadingToTrailing, metrics: nil, views: ["subview": self]))
        superview.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-0-[subview]-0-|", options: .directionLeadingToTrailing, metrics: nil, views: ["subview": self]))
    }

}

Якщо ви лише змінили код, щоб зробити його сумісним із Swift 3, вам слід скоріше відредагувати відповідь оригінальних плакатів, замість того, щоб публікувати нову відповідь (оскільки це не зміна оригінальних плакатів). Якщо у вас недостатньо балів для редагування, тоді прокоментуйте оригінальний пост із натяком на зміни, необхідні для дотримання Swift 3. Оригінальний плакат (або хтось інший, хто бачить ваш коментар), можливо, оновить відповідь. Таким чином ми забезпечуємо чистоту потоку від дублікатів відповідей та застарілого коду.
Jeehut

Привіт @Dschee - Я повністю з вами згоден, але ми "помиляємося". погляд на консенсус на сайті в кращу чи гіршу сторону є протилежним тому, що ви висловлюєте тут. meta.stackoverflow.com/questions/339024/… (я постійно ігнорую рішення консенсусу, роблю те, що є розумним, а потім потрапляю в біду від модів :))
Fattie,

2

Свіфт 4 за допомогою NSLayoutConstraint:

footerBoardImageView.translatesAutoresizingMaskIntoConstraints = false
let widthConstraint  = NSLayoutConstraint(item: yourview, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: superview, attribute: NSLayoutAttribute.width, multiplier: 1, constant: 0)
let heightConstraint = NSLayoutConstraint(item: yourview, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: superview, attribute: NSLayoutAttribute.height, multiplier: 1, constant: 0)
superview.addConstraints([widthConstraint, heightConstraint])

1

Як додаткова відповідь і відповідь для тих, хто не проти включення сторонніх бібліотек, бібліотека PureLayout пропонує спосіб зробити саме це. Після встановлення бібліотеки це так просто, як

myView.autoPinEdgesToSuperviewEdges()

Є й інші бібліотеки, які також можуть забезпечити подібну функціональність залежно від смаку, наприклад. Кладка , Картографія .


1

Я вибрав найкращі елементи з інших відповідей:

extension UIView {
  /// Adds constraints to this `UIView` instances `superview` object to make sure this always has the same size as the superview.
  /// Please note that this has no effect if its `superview` is `nil` – add this `UIView` instance as a subview before calling this.
  func bindFrameToSuperviewBounds() {
    guard let superview = self.superview else {
      print("Error! `superview` was nil – call `addSubview(view: UIView)` before calling `bindFrameToSuperviewBounds()` to fix this.")
      return
    }

    self.translatesAutoresizingMaskIntoConstraints = false

    NSLayoutConstraint.activate([
      self.topAnchor.constraint(equalTo: superview.topAnchor),
      self.bottomAnchor.constraint(equalTo: superview.bottomAnchor),
      self.leadingAnchor.constraint(equalTo: superview.leadingAnchor),
      self.trailingAnchor.constraint(equalTo: superview.trailingAnchor)
    ])
  }
}

Ви можете використовувати його таким чином, наприклад, у своєму користувацькому UIView:

let myView = UIView()
myView.backgroundColor = UIColor.red

self.addSubview(myView)
myView.bindFrameToSuperviewBounds()

0

Як продовження рішення @ Dschee, ось синтаксис швидкого 3.0: (Зверніть увагу: це не моє рішення , я щойно виправив його для Swift 3.0)

extension UIView {

    /// Adds constraints to this `UIView` instances `superview` object to make sure this always has the same size as the superview.
    /// Please note that this has no effect if its `superview` is `nil` – add this `UIView` instance as a subview before calling this.
    func bindFrameToSuperviewBounds() {
        guard let superview = self.superview else {
            print("Error! `superview` was nil – call `addSubview(view: UIView)` before calling `bindFrameToSuperviewBounds()` to fix this.")
            return
        }

        self.translatesAutoresizingMaskIntoConstraints = false
        superview.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[subview]-0-|", options: .directionLeadingToTrailing, metrics: nil, views: ["subview": self]))
    superview.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-0-[subview]-0-|", options: .directionLeadingToTrailing, metrics: nil, views: ["subview": self]))
}

1
Якщо ви лише змінили код, щоб зробити його сумісним із Swift 3, вам слід скоріше відредагувати відповідь оригінальних плакатів, замість того, щоб публікувати нову відповідь (оскільки це не зміна оригінальних плакатів). Якщо у вас недостатньо балів для редагування, тоді прокоментуйте оригінальний пост із натяком на зміни, необхідні для дотримання Swift 3. Оригінальний плакат (або хтось інший, хто бачить ваш коментар), можливо, оновить відповідь. Таким чином ми забезпечуємо чистоту потоку від дублікатів відповідей та застарілого коду.
Jeehut

Я з вами повністю згоден, @Dschee, але є (для мене, абсурдно) коментар на Мете , що «ми не робимо , що на SO» ... meta.stackoverflow.com/questions/339024 / ...
Fattie

@JoeBlow Прочитавши обговорення за вашим посиланням, я насправді вважаю, що це теж має сенс. Я погоджуюсь з коментарем Патріка Хо (щодо питання), однак, що має бути дана нова відповідь у поєднанні з коментарем до оригінальної відповіді. Тоді вихідний плакат повинен оновити свою відповідь (щоб отримати майбутні голоси) чи ні. Дякую за посилання!
Jeehut

Га, добре, це все велика частина того, чому в минулому я залишався вірним хітом і бігуном. Я захоплюю свою відповідь, перетворюю її на поточний синтаксис і продовжую моє кодування. Основною причиною, яку я розмістив таким чином, є те, що коли я навчав swift, мене часто запитували про те, як знайти рішення в будь-якій версії swift, яка була поточною, оскільки нові кодери мали проблеми з оновленням своїх декларацій функцій. Це було одним з провідних джерел розчарувань, а також можливістю протиставити два стилі коду. У результаті студент зміг передбачити подібні зміни в інших фрагментах коду.
James Larcombe

0

Мені потрібно було повністю висвітлити суперв'ю. Інші не робили цього під час зміни орієнтації. Тож я написав новий, який робить - використовуючи довільний множник розміру 20. Не соромтеся змінювати свої потреби. Також зверніть увагу на те, що насправді робить підпрограму набагато більшою за суперперегляд, яка може відрізнятися від вимог.

extension UIView {
    func coverSuperview() {
        guard let superview = self.superview else {
            assert(false, "Error! `superview` was nil – call `addSubview(_ view: UIView)` before calling `\(#function)` to fix this.")
            return
        }
        self.translatesAutoresizingMaskIntoConstraints = false
        let multiplier = CGFloat(20.0)
        NSLayoutConstraint.activate([
            self.heightAnchor.constraint(equalTo: superview.heightAnchor, multiplier: multiplier),
            self.widthAnchor.constraint(equalTo: superview.widthAnchor, multiplier: multiplier),
            self.centerXAnchor.constraint(equalTo: superview.centerXAnchor),
            self.centerYAnchor.constraint(equalTo: superview.centerYAnchor),
            ])
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.