너비와 높이가 프로그래밍 방식으로 자동 레이아웃을 사용하는 superView와 같습니까?


83

나는 인터넷에서 많은 스 니펫을 찾고 있었지만 여전히 내 문제에 대한 답을 찾을 수 없습니다. 내 질문은 scrollView (SV)가 있고 사용자가 장치 버튼을 회전 할 때 동일한 프레임을 갖도록 해당 superview의 너비와 높이가 동일한 scrollView (SV) 내부에 프로그래밍 방식으로 버튼을 추가하고 싶습니다. scrollView (SV)의. NSLayout / NSLayoutConstraint를 수행하는 방법? 감사

답변:


125

누군가가 스위프트 솔루션을 찾고 있다면 서브 뷰 프레임을 수퍼 뷰 경계에 바인딩 할 때마다 도움이 될 스위프트 확장을UIView 만들 것입니다.

스위프트 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]))
    }
}

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

'? 필요한 초기화 (aDecoder 코더)'는 .xib를 사용하여 사용자 정의의 UIView를 만들 때 bindFrameToSuperviewBounds는 내에서 호출되어야 단지 self.addSubview (self.view) 후
user1603721

시각적 형식을 사용하는 솔루션은 안전 영역에 적합하지 않습니다. 예를 들어 내비게이션 컨트롤러 내부에있는 뷰에서 navbar와 툴바를 표시하는 뷰에서 호출하는 경우 뷰가 navbar 아래로 이동하고 툴바 아래로 이동하면 아래로 이동합니다.
Andy Ibanez

이것은 Swift 5의 솔루션으로도 작동합니다. AutoLayout을 사용하여 사용자 지정 subView를 parentView 크기에 맞게 조정할 수 없습니다. 하위 뷰가 추가되면 이것을 사용하면 매력으로 작동합니다.
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])
Berik

당신은 사용할 수 있습니다[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

addConstraintremoveConstraintUIView의 메소드는 더 이상 사용되지 않으므로 '제약 조건 생성 편의'를 사용할 가치가 있습니다.

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 20.07.16

8

접근법 # 1 : UIView 확장을 통해

여기의 더 많은 기능 에 접근 스위프트 3 + A를 전제 조건 대신의 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 프레임 워크에 통합 되어 있어 프로젝트에보다 편리한 UI 도우미를 추가합니다.


접근 방식 # 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

Swift 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

A는 Dschee의 솔루션 @ 후속으로, 여기에 빠른 3.0 구문입니다 (제발 참고 : 이것은 내 솔루션을하지 , 난 그냥 스위프트 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 귀하의 링크 뒤에있는 토론을 읽은 후 실제로 이것이 의미가 있다고 생각합니다. 원래 답변에 대한 의견과 결합하여 새로운 답변을 제공해야하지만 (질문에 대한) PatrickHaugh의 의견에 동의합니다. 그런 다음 (향후 찬성 투표를 얻기 위해) 답변을 업데이트하는 것은 원래 포스터에 달려 있습니다. 링크 감사합니다!
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),
            ])
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.