[ios] 프로그래밍 방식으로 CenterX / CenterY 제약 추가

표시 할 항목이 없으면 섹션을 표시하지 않는 UITableViewController가 있습니다. 이 코드로 표시 할 항목이 없음을 사용자에게 알리기 위해 레이블을 추가했습니다.

label = UILabel(frame: CGRectMake(20, 20, 250, 100))
label.text = "Nothing to show"
self.tableView.addSubview(label)

하지만 이제는 수평 및 수직 중앙에 배치하고 싶습니다. 일반적으로 스크린 샷에서 강조 표시된 두 가지 옵션 (높이 및 너비에 대한 옵션 포함)을 선택합니다.

여기에 이미지 설명 입력

제약 조건을 추가하기 위해 다음 코드를 시도했지만 앱이 오류와 함께 충돌합니다.

label = UILabel(frame: CGRectMake(20, 20, 250, 100))
label.text = "Nothing to show"

let xConstraint = NSLayoutConstraint(item: label, attribute: .CenterX, relatedBy: .Equal, toItem: self.tableView, attribute: .CenterX, multiplier: 1, constant: 0)
let yConstraint = NSLayoutConstraint(item: label, attribute: .CenterY, relatedBy: .Equal, toItem: self.tableView, attribute: .CenterY, multiplier: 1, constant: 0)

label.addConstraint(xConstraint)
label.addConstraint(yConstraint)

오류:

When added to a view, the constraint's items must be descendants of that view (or the view itself). This will crash if the constraint needs to be resolved before the view hierarchy is assembled. Break on -[UIView _viewHierarchyUnpreparedForConstraint:] to debug.
2014-12-23 08:17:36.755 [982:227877] *** Assertion failure in -[UILabel _layoutEngine_didAddLayoutConstraint:roundingAdjustment:mutuallyExclusiveConstraints:], /SourceCache/UIKit/UIKit-3318.16.21/NSLayoutConstraint_UIKitAdditions.m:560

앱이 기기 회전을 지원하므로 라벨은 항상 가로 및 세로 중앙에 있어야합니다.

내가 도대체 ​​뭘 잘못하고있는 겁니까? 이러한 제약 조건을 어떻게 성공적으로 추가합니까?

감사!



답변

Swift 3 / Swift 4 업데이트 :

iOS 8부터는 isActive속성을 로 설정하여 제약 조건을 활성화 할 수 있으며 활성화해야 합니다 true. 이를 통해 제약 조건이 적절한 뷰에 추가 될 수 있습니다. 제약 조건을 포함하는 배열을 전달하여 한 번에 여러 제약 조건을 활성화 할 수 있습니다.NSLayoutConstraint.activate()

let label = UILabel(frame: CGRect.zero)
label.text = "Nothing to show"
label.textAlignment = .center
label.backgroundColor = .red  // Set background color to see if label is centered
label.translatesAutoresizingMaskIntoConstraints = false
self.tableView.addSubview(label)

let widthConstraint = NSLayoutConstraint(item: label, attribute: .width, relatedBy: .equal,
                                         toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 250)

let heightConstraint = NSLayoutConstraint(item: label, attribute: .height, relatedBy: .equal,
                                          toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 100)

let xConstraint = NSLayoutConstraint(item: label, attribute: .centerX, relatedBy: .equal, toItem: self.tableView, attribute: .centerX, multiplier: 1, constant: 0)

let yConstraint = NSLayoutConstraint(item: label, attribute: .centerY, relatedBy: .equal, toItem: self.tableView, attribute: .centerY, multiplier: 1, constant: 0)

NSLayoutConstraint.activate([widthConstraint, heightConstraint, xConstraint, yConstraint])

더 나은 솔루션 :

이 질문에 대한 답이 원래 있었기 때문에 레이아웃 앵커가 도입되어 제약 조건을 훨씬 쉽게 만들 수 있습니다. 이 예에서는 제약 조건을 만들고 즉시 활성화합니다.

label.widthAnchor.constraint(equalToConstant: 250).isActive = true
label.heightAnchor.constraint(equalToConstant: 100).isActive = true
label.centerXAnchor.constraint(equalTo: self.tableView.centerXAnchor).isActive = true
label.centerYAnchor.constraint(equalTo: self.tableView.centerYAnchor).isActive = true

또는 다음을 사용하여 동일 NSLayoutConstraint.activate():

NSLayoutConstraint.activate([
    label.widthAnchor.constraint(equalToConstant: 250),
    label.heightAnchor.constraint(equalToConstant: 100),
    label.centerXAnchor.constraint(equalTo: self.tableView.centerXAnchor),
    label.centerYAnchor.constraint(equalTo: self.tableView.centerYAnchor)
])

참고 : 제약 조건을 만들고 활성화 하기 전에 항상 하위 뷰를 뷰 계층 구조에 추가하십시오 .


원래 답변 :

제약 조건은 self.tableView. 레이블을의 하위보기로 추가하고 self.tableView있으므로 제약 조건을 “공통 조상”에 추가해야합니다.

   self.tableView.addConstraint(xConstraint)
   self.tableView.addConstraint(yConstraint)

@mustafa 및 @kcstricks는 의견에서 지적한 것처럼, 당신은 설정해야 label.translatesAutoresizingMaskIntoConstraints하는 false. 이렇게하면 프레임이 더 이상 사용되지 않기 때문에 제약 조건이있는 레이블 widthheight레이블도 지정해야합니다 . 마지막으로, 당신은 또한 설정해야합니다 textAlignment.Center텍스트가 레이블에 중앙에 오도록.

    var  label = UILabel(frame: CGRectZero)
    label.text = "Nothing to show"
    label.textAlignment = .Center
    label.backgroundColor = UIColor.redColor()  // Set background color to see if label is centered
    label.translatesAutoresizingMaskIntoConstraints = false
    self.tableView.addSubview(label)

    let widthConstraint = NSLayoutConstraint(item: label, attribute: .Width, relatedBy: .Equal,
        toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 250)
    label.addConstraint(widthConstraint)

    let heightConstraint = NSLayoutConstraint(item: label, attribute: .Height, relatedBy: .Equal,
        toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 100)
    label.addConstraint(heightConstraint)

    let xConstraint = NSLayoutConstraint(item: label, attribute: .CenterX, relatedBy: .Equal, toItem: self.tableView, attribute: .CenterX, multiplier: 1, constant: 0)

    let yConstraint = NSLayoutConstraint(item: label, attribute: .CenterY, relatedBy: .Equal, toItem: self.tableView, attribute: .CenterY, multiplier: 1, constant: 0)

    self.tableView.addConstraint(xConstraint)
    self.tableView.addConstraint(yConstraint)


답변

컨테이너 중앙

여기에 이미지 설명 입력

아래 코드는 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 code for one of the constraint methods below
    // ...
}

방법 1 : 앵커 스타일

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

방법 2 : NSLayoutConstraint 스타일

NSLayoutConstraint(item: myView, attribute: NSLayoutConstraint.Attribute.centerX, relatedBy: NSLayoutConstraint.Relation.equal, toItem: view, attribute: NSLayoutConstraint.Attribute.centerX, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint(item: myView, attribute: NSLayoutConstraint.Attribute.centerY, relatedBy: NSLayoutConstraint.Relation.equal, toItem: view, attribute: NSLayoutConstraint.Attribute.centerY, multiplier: 1, constant: 0).isActive = true

메모

  • 앵커 스타일은 NSLayoutConstraint 이지만 iOS 9에서만 사용할 수 있으므로 iOS 8을 지원하는 경우에도 NSLayoutConstraint스타일 을 사용해야합니다 .
  • 길이 및 너비 제한도 추가해야합니다.
  • 내 전체 답변은 여기에 있습니다 .


답변

ObjectiveC는 다음과 같습니다.

    myView.translatesAutoresizingMaskIntoConstraints = NO;

    [[myView.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor] setActive:YES];

    [[myView.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor] setActive:YES];


답변

프로그래밍 방식으로 다음 제약 조건을 추가하여 수행 할 수 있습니다.

NSLayoutConstraint *constraintHorizontal = [NSLayoutConstraint constraintWithItem:self
                                                                      attribute:NSLayoutAttributeCenterX
                                                                      relatedBy:NSLayoutRelationEqual
                                                                         toItem:self.superview
                                                                      attribute:attribute
                                                                     multiplier:1.0f
                                                                       constant:0.0f];

NSLayoutConstraint *constraintVertical = [NSLayoutConstraint constraintWithItem:self
                                                                        attribute:NSLayoutAttributeCenterY
                                                                        relatedBy:NSLayoutRelationEqual
                                                                           toItem:self.superview
                                                                        attribute:attribute
                                                                       multiplier:1.0f
                                                                         constant:0.0f];


답변

Swift 5에서는 다음과 같습니다.

label.translatesAutoresizingMaskIntoConstraints = false
label.centerXAnchor.constraint(equalTo: vc.view.centerXAnchor).isActive = true
label.centerYAnchor.constraint(equalTo: vc.view.centerYAnchor).isActive = true


답변

이 질문이 특히 테이블 뷰에 관한 것이 중요하지 않고 다른 뷰 위에 하나의 뷰를 중앙에 배치하려면 여기에서 수행하십시오.

    let horizontalConstraint = NSLayoutConstraint(item: newView, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem: parentView, attribute: NSLayoutAttribute.CenterX, multiplier: 1, constant: 0)
    parentView.addConstraint(horizontalConstraint)

    let verticalConstraint = NSLayoutConstraint(item: newView, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal, toItem: parentView, attribute: NSLayoutAttribute.CenterY, multiplier: 1, constant: 0)
    parentView.addConstraint(verticalConstraint)


답변

나를위한 해결책은을 만들고 하위보기로 UILabel추가하는 것이 었습니다 UIButton. 마지막으로 버튼 내에서 중앙에 제약 조건을 추가했습니다.

UILabel * myTextLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 75, 75)];
myTextLabel.text = @"Some Text";
myTextLabel.translatesAutoresizingMaskIntoConstraints = false;

[myButton addSubView:myTextLabel];

// Add Constraints
[[myTextLabel centerYAnchor] constraintEqualToAnchor:myButton.centerYAnchor].active = true;
[[myTextLabel centerXAnchor] constraintEqualToAnchor:myButton.centerXAnchor].active = true;