[objective-c] 프로그래밍 방식으로 레이아웃 제약 만들기

많은 사람들이 이미 이것에 대해 많은 질문을했지만 대답을하더라도 제대로 작동하지 않는다는 것을 알고 있습니다.

스토리 보드에서 제약을 다룰 때는 쉽지만 코드에서는 힘들다. 예를 들어, 화면 방향에 따라 화면의 높이가 오른쪽에 유지되는 뷰를 만들려고합니다. 이것은 내 코드입니다.

UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 748)];
myView.backgroundColor = [UIColor redColor];
[self.view addSubview:myView];
[self.view addConstraints:[NSLayoutConstraint
    constraintsWithVisualFormat:@"V:|-[myView(>=748)]-|"
    options:0 metrics:nil
    views:NSDictionaryOfVariableBindings(myView)]];

일부 제약 조건을 충족하지 않습니다. 나는 무엇이 잘못되었는지 모르겠다. 또한 왜 같은 self.myView지역 변수 대신 같은 속성을 사용할 수 myView없습니까?



답변

코드에서 자동 레이아웃을 사용할 때 프레임을 설정해도 아무 효과가 없습니다. 따라서 위의 뷰에서 너비를 200으로 지정했다는 사실은 제약 조건을 설정할 때 아무런 의미가 없습니다. 뷰의 제약 조건이 명확하게 설정 되려면 주어진 상태에 대한 x 위치, y 위치, 너비 및 높이의 네 가지가 필요합니다.

현재 위의 코드에는 두 개만 있습니다 (슈퍼 뷰를 기준으로 한 높이와 수퍼 뷰를 기준으로 한 y 위치). 이 외에도 뷰의 수퍼 뷰 제약 조건이 설정되는 방식에 따라 충돌 할 수있는 두 가지 필수 제약 조건이 있습니다. 경우 수퍼가 지정 그것의 높이가 748보다 약간 작은 값 것이 필요한 제약 조건을 가지고 있었다, 당신은 “시켰음 제약”예외를 얻을 것이다.

제약 조건을 설정하기 전에 뷰의 너비를 설정했다는 사실은 의미가 없습니다. 이전 프레임도 고려하지 않고 해당 뷰에 대해 지정한 모든 제약 조건을 기반으로 새 프레임을 계산합니다. 코드에서 자동 레이아웃을 처리 할 때 일반적으로 initWithFrame:CGRectZero또는 단순히를 사용하여 새보기를 만듭니다 init.

질문에서 구두로 설명한 레이아웃에 필요한 제약 조건 세트를 만들려면 완전히 지정된 레이아웃을 제공하기 위해 가로 제약 조건을 추가하여 너비와 x 위치를 제한해야합니다.

[self.view addConstraints:[NSLayoutConstraint
    constraintsWithVisualFormat:@"V:|-[myView(>=748)]-|"
    options:NSLayoutFormatDirectionLeadingToTrailing
    metrics:nil
    views:NSDictionaryOfVariableBindings(myView)]];

[self.view addConstraints:[NSLayoutConstraint
    constraintsWithVisualFormat:@"H:[myView(==200)]-|"
    options:NSLayoutFormatDirectionLeadingToTrailing
    metrics:nil
    views:NSDictionaryOfVariableBindings(myView)]];

이 레이아웃을 구두로 설명하면 수직 제약 조건부터 다음과 같이 읽습니다.

myView는 수퍼 뷰의 높이를 표준 공간과 동일한 상단 및 하단 패딩으로 채 웁니다. myView의 superview의 최소 높이는 748pts입니다. myView의 너비는 200pts이며 superview에 대한 표준 공간과 동일한 오른쪽 패딩이 있습니다.

슈퍼 뷰의 높이를 제한하지 않고 전체 슈퍼 뷰의 높이를 단순히 뷰가 채우도록 (>=748)하려면 시각적 형식 텍스트에서 매개 변수를 생략하면 됩니다. (>=748)높이를 지정하기 위해 매개 변수가 필요 하다고 생각하는 경우-이 경우 에는 필요하지 않습니다. 막대 ( |) 또는 공백 ( |-, -|) 구문이 있는 막대를 사용하여 뷰를 수퍼 뷰의 가장자리에 고정하면 뷰에 y를 제공합니다. -position (단일 모서리에 뷰 고정) 및 높이가있는 y 위치 (양쪽 모서리에 뷰 고정)를 사용하여 뷰에 대한 제약 설정을 충족합니다.

두 번째 질문과 관련하여 :

사용 NSDictionaryOfVariableBindings(self.myView)(myView에 대한 속성 설정이있는 경우)을 self.myViewVFL 텍스트 에 사용하기 위해 VFL에 공급 하면 자동 레이아웃이 VFL 텍스트를 구문 분석하려고 할 때 예외가 발생할 수 있습니다. 그것은 사전 키의 점 표기법과 사용하려는 시스템과 관련이 있습니다 valueForKeyPath:. 유사한 질문과 답변을 보려면 여기를 참조하십시오 .


답변

안녕하세요 저는 제약 조건과 “방법”을 위해이 페이지를 많이 사용하고 있습니다. 내가 필요하다는 것을 깨닫는 데 영원히 걸렸습니다.

myView.translatesAutoresizingMaskIntoConstraints = NO;

이 예제가 작동하도록합니다. Userxxx, Rob M. 그리고 특히 여기에 설명과 코드에 대해 larsacus에게 감사드립니다. 매우 귀중했습니다.

다음은 위의 예제를 실행하기위한 전체 코드입니다.

UIView *myView = [[UIView alloc] init];
myView.backgroundColor = [UIColor redColor];
myView.translatesAutoresizingMaskIntoConstraints = NO;  //This part hung me up 
[self.view addSubview:myView];
//needed to make smaller for iPhone 4 dev here, so >=200 instead of 748
[self.view addConstraints:[NSLayoutConstraint
                           constraintsWithVisualFormat:@"V:|-[myView(>=200)]-|"
                           options:NSLayoutFormatDirectionLeadingToTrailing
                           metrics:nil
                           views:NSDictionaryOfVariableBindings(myView)]];

[self.view addConstraints:[NSLayoutConstraint
                           constraintsWithVisualFormat:@"H:[myView(==200)]-|"
                           options:NSLayoutFormatDirectionLeadingToTrailing
                           metrics:nil
                           views:NSDictionaryOfVariableBindings(myView)]];


답변

Swift 버전

Swift 3 업데이트

이 예제는 Interface Builder에서 수행하는 것과 동일한 다음 제약 조건을 프로그래밍 방식으로 추가하는 두 가지 방법을 보여줍니다.

너비와 높이

여기에 이미지 설명 입력

컨테이너 중심

여기에 이미지 설명 입력

상용구 코드

override func viewDidLoad() {
    super.viewDidLoad()

    // set up the view
    let myView = UIView()
    myView.backgroundColor = UIColor.blue
    myView.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(myView)

    // Add constraints code here (choose one of the methods below)
    // ...
}

방법 1 : 앵커 스타일

// width and height
myView.widthAnchor.constraint(equalToConstant: 200).isActive = true
myView.heightAnchor.constraint(equalToConstant: 100).isActive = true

// center in container
myView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
myView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true

방법 2 : NSLayoutConstraint 스타일

// width and height
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

// center in container
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이지만 iOS 9에서만 사용할 수 있으므로 iOS 8을 지원하는 경우에도 NSLayoutConstraint스타일 을 사용해야합니다 .
  • 프로그래밍 방식으로 제약 조건 만들기 문서 도 참조하세요 .
  • 고정 제약을 추가하는 유사한 예는 이 답변 을 참조하십시오 .


답변

속성에 대한 두 번째 질문에 대해서는 self.myView클래스에서 속성으로 선언 한 경우에만 사용할 수 있습니다 . myView은 지역 변수 이기 때문에 그렇게 사용할 수 없습니다. 이에 대한 자세한 내용은 Declared Properties 에 대한 apple 문서를 참조하는 것이 좋습니다 .


답변

self.myViewmyView와 같은 지역 변수 대신 같은 속성을 사용할 수없는 이유는 무엇입니까?

사용해보십시오 :

NSDictionaryOfVariableBindings(_view)

대신에 self.view


답변

또한 iOS9 에서는 새로운 도우미 클래스 NSLayoutAnchor의 하위 클래스를 사용하여 “보다 간결하고 읽기 쉬운” 제약 조건을 프로그래밍 방식으로 정의 할 수 있습니다 .

문서의 예 :

[self.cancelButton.leadingAnchor constraintEqualToAnchor:self.saveButton.trailingAnchor constant: 8.0].active = true;


답변