Visual Format Language를 사용하여 슈퍼 뷰에서 뷰 중심 맞추기


160

방금 iOS 용 AutoLayout을 배우기 시작했고 Visual Format Language를 살펴 보았습니다.

한 가지를 제외하고는 모두 잘 작동합니다. 수퍼 뷰 내에서 중심을 볼 수는 없습니다.
VFL에서 가능합니까? 아니면 직접 구속 조건을 직접 만들어야합니까?

답변:


232

현재 VFL 사용하여 수퍼 뷰에서 뷰를 중앙에 배치하는 것이 불가능한 것처럼 보이지 않습니다 . 그러나 단일 VFL 문자열과 단일 추가 제약 조건 (축당)을 사용하여 수행하는 것은 그리 어렵지 않습니다.

VFL : "|-(>=20)-[view]-(>=20)-|"

[NSLayoutConstraint constraintWithItem:view
                             attribute:NSLayoutAttributeCenterX
                             relatedBy:NSLayoutRelationEqual
                                toItem:view.superview
                             attribute:NSLayoutAttributeCenterX
                            multiplier:1.f constant:0.f];

하나는 당신이 단순히 이것을 할 수 있다고 생각할 것입니다 (이 질문을 보았을 때 처음에 생각하고 시도한 것입니다).

[NSLayoutConstraint constraintsWithVisualFormat:@"|-(>=20)-[view(==200)]-(>=20)-|"
                                 options: NSLayoutFormatAlignAllCenterX | NSLayoutFormatAlignAllCenterY
                                 metrics:nil
                                   views:@{@"view" : view}];

위의 변형을 내 의지에 구부리려고 여러 가지 변형을 시도했지만 두 축 ( H:|V:)에 대해 두 개의 별도 VFL 문자열이 명시 적으로있는 경우에도 슈퍼 뷰에 적용되지 않는 것으로 보입니다 . 그런 다음 옵션 VFL에 적용될 때 정확하게 시도하고 격리하기 시작했습니다 . VFL의 수퍼 뷰 에는 적용 되지 않는 것으로 보이며 VFL 문자열에 언급 된 명시 적 뷰에만 적용됩니다 (일부 경우 실망).

앞으로 애플은 VFL의 슈퍼 뷰 외에 단 하나의 명시적인 뷰만있을 때만 VFL 옵션이 슈퍼 뷰를 고려할 수있는 새로운 옵션을 추가하기를 희망합니다. 또 다른 해결책은 VFL로 전달되는 다른 옵션이 될 수 있습니다 NSLayoutFormatOptionIncludeSuperview.

말할 필요도없이, 나는 VFL에 대해이 질문에 대답하려고 많은 것을 배웠습니다.


2
자세한 답변을 주셔서 감사합니다. 그러나 VFL을 사용하는 유일한 이유는 그러한 추악한 제약을 제거하는 것입니다. 너무 나쁜 애플은 아직 이것을 지원하지 않습니다 ...
Christian Schnorr

@larsacus 아래 답변이 왜 효과가 있는지에 대해 언급 해 주시겠습니까? 저를 엉망으로 만들었습니다.
Matt G

8
아래의 Evgeny의 답변은 자동 레이아웃 엔진 이 동일한 의미 객체를 나타내는 경우에도 개별 내부 엔티티로 취급 |하고 [superview]별도의 내부 엔티티로 사용 하기 때문에 작동 합니다. 을 사용하여 [superview]자동 레이아웃은 정렬 메트릭에 superview 객체를 포함시킵니다 (github 링크의 답변에서 NSLayoutFormatAlignAllCenterY/ X메트릭).
larsacus

@larsacus 굉장합니다, 감사합니다!
Matt G

현재 iOS 7.x와 함께 제공되는 VFL 버전에 제한이 여전히 적용되는지 알고 있습니까?
Drux

138

예. Visual Format Language를 사용하여 슈퍼 뷰에서 뷰를 중앙에 배치 할 수 있습니다. 수직 및 수평 모두. 데모는 다음과 같습니다.

https://github.com/evgenyneu/center-vfl


15
이것은 굉장합니다. 이것을 확장하고 왜 작동하는지 설명 할 수 있습니까?
tapi

3
나는 표시된 답변에 더 가까운 것을 사용했지만 결국 당신의 github 첨부 파일에 +1
Rembrandt Q. Einstein

4
@Dan 작동하지 않으면 너비와 높이에 대한 제약 조건이 필요할 수 있습니다. VFL은 너비 : @ "[label (== 200)]", 높이 : @ "V : [label (== 200)]"
Jonathan Zhan

1
결과가 왜 | [수퍼 뷰]가 다른가요? 이것은 레이더해야하거나 내가 따르고 있지 않은 일입니까?
Matt G

3
구속 조건 형식을 구문 분석 할 수 없음 : 옵션은 필요한 뷰가 수평 모서리에 맞춰 정렬되어 수평 레이아웃에도 허용되지 않습니다. H : [superview]-(<= 1)-[label1]
grabner

82

제약 조건을 수동으로 만드는 것이 좋습니다.

[superview addConstraint:
 [NSLayoutConstraint constraintWithItem:view
                              attribute:NSLayoutAttributeCenterX
                              relatedBy:NSLayoutRelationEqual
                                 toItem:superview
                              attribute:NSLayoutAttributeCenterX
                             multiplier:1
                               constant:0]];
[superview addConstraint:
 [NSLayoutConstraint constraintWithItem:view
                              attribute:NSLayoutAttributeCenterY
                              relatedBy:NSLayoutRelationEqual
                                 toItem:superview
                              attribute:NSLayoutAttributeCenterY
                             multiplier:1
                               constant:0]];

이제 NSLayoutAnchor 를 사용 하여 AutoLayout을 프로그래밍 방식으로 정의 할 수 있습니다 .

(iOS 9.0 이상에서 사용 가능)

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

iOS와 macOS에서 자동 레이아웃을 쉽게하기 위해 DSL 인 SnapKit을 사용하는 것이 좋습니다 .

view.snp.makeConstraints({ $0.center.equalToSuperview() })

1
내 맥락에서 가장 잘 작동했습니다 .VFL은 없습니다.
brainray

경고 :Warning once only: Detected a case where constraints ambiguously suggest a height of zero for a tableview cell's content view. We're considering the collapse unintentional and using standard height instead.
타파스 팔

10

절대적으로 다음과 같이 할 수있었습니다.

[NSLayoutConstraint constraintsWithVisualFormat:@"H:[view]-(<=1)-[subview]"
                                        options:NSLayoutFormatAlignAllCenterY
                                        metrics:nil
                                          views:NSDictionaryOfVariableBindings(view, subview)];

여기 에서 이것을 배웠 습니다. 위의 코드는 분명히 Y에 의해 하위 뷰를 볼 수 있습니다.

스위프트 3 :

        NSLayoutConstraint.constraints(withVisualFormat: "H:[view]-(<=1)-[subview]",
                                       options: .alignAllCenterY,
                                                       metrics: nil,
                                                       views: ["view":self, "subview":_spinnerView])

7

아래 코드를 추가하고 버튼을 화면 중앙에 두십시오. 물론 가능합니다.

[self.view addConstraints:[NSLayoutConstraint
                           constraintsWithVisualFormat:@"H:|-[button]-|"
                           options:NSLayoutFormatAlignAllCenterY
                           metrics:0
                           views:views]];

[self.view addConstraints:[NSLayoutConstraint
                           constraintsWithVisualFormat:@"V:|-[button]-|"
                           options:NSLayoutFormatAlignAllCenterX
                           metrics:0
                           views:views]];

1

나는 그것을 원하지 않는다는 것을 알고 있지만 물론 여백을 계산하고 시각적 형식 문자열을 만드는 데 사용할 수 있습니다.)

어쨌든 불행히도 VFL을 사용하여 '자동'할 수는 없습니다. 적어도 아직은 아닙니다.


NSString stringWithFormat :을 사용하여 런타임에 VFL 문자열을 동적으로 빌드 할 수 있습니다.
TRVD1707

1

@Evgenii의 답변 덕분에 요지에서 전체 예제를 만듭니다.

맞춤 높이로 빨간색 정사각형을 세로로 가운데에 맞 춥니 다.

https://gist.github.com/yallenh/9fc2104b719742ae51384ed95dcaf626

직관적이지 않은 VFL을 사용하거나 구속 조건을 수동으로 사용하여 뷰를 세로로 가운데에 맞출 수 있습니다. 그건 그렇고, VFL에서 centerY와 height를 함께 결합 할 수 없습니다 :

"H:[subView]-(<=1)-[followIcon(==customHeight)]"

현재 솔루션에서 VFL 제약 조건이 별도로 추가되었습니다.


0

수행해야 할 것은 사전에 사전보기를 선언해야한다는 것입니다. 사용하는 대신을 사용 |하십시오 @{@"super": view.superview};.

그리고 옵션으로 NSLayoutFormatAlignAllCenterX수직 및 NSLayoutFormatAlignAllCenterY수평에 적합합니다.


0

추가보기를 사용할 수 있습니다.

NSDictionary *formats =
@{
  @"H:|[centerXView]|": @0,
  @"V:|[centerYView]|": @0,
  @"H:[centerYView(0)]-(>=0)-[yourView]": @(NSLayoutFormatAlignAllCenterY),
  @"V:[centerXView(0)]-(>=0)-[yourView]": @(NSLayoutFormatAlignAllCenterX),
};
NSDictionary *views = @{
  @"centerXView": centerXView, 
  @"centerYView": centerYView, 
  @"yourView": yourView,
};
 ^(NSString *format, NSNumber *options, BOOL *stop) {
     [superview addConstraints:
      [NSLayoutConstraint constraintsWithVisualFormat:format
                                              options:options.integerValue
                                              metrics:nil
                                                views:views]];
 }];

깔끔하게하려면 centerXView.hidden = centerYView.hidden = YES;.

추신 : 영어가 제 2 언어이기 때문에 여분의 뷰를 "자리 표시 자"라고 부를 수 있는지 확실하지 않습니다. 누군가 저에게 말해 줄 수 있다면 감사하겠습니다.


여기에 뭔가 빠졌습니다. 선언 에서 블록을 어떻게 호출 합니까? 그것은 당신이 그것을 넣는 방식으로 합법적 인 코드가 아닙니다
ishahak

0

Interface Builder기반 솔루션을 위해 여기에 온 사람들 (Google이 여기로 안내합니다)의 경우 const width / height 제약 조건을 추가하고 하위보기-> 컨트롤 드래그로 슈퍼 뷰로 이동-> "수직 뷰에서 가로 / 세로 중심"을 선택하십시오.


0

이게 내 방법이야

//create a 100*100 rect in the center of superView
var consts = NSLayoutConstraint.constraints(withVisualFormat: "H:|-space-[myView]-space-|", options: [], metrics:["space":view.bounds.width/2-50], views:["myView":myView])

consts += NSLayoutConstraint.constraints(withVisualFormat: "V:|-space-[myView]-space-|", options: [], metrics: ["space":view.bounds.height/2-50], views: ["myView":myView])

-1

u가 제약 조건 대신 이것을 사용할 수 있다고 말하면됩니다.

child.center = [parent convertPoint:parent.center fromView:parent.superview];

4
그 말은 장치를 회전 시키거나 화면 크기를 조정하는 등의 경우 그가 요구하는 것이 아니며 작동하지 않을 것입니다.
jeffjv

-1

스위프트 2의 @ igor-muzyka 답변 :

NSLayoutConstraint.constraintsWithVisualFormat("H:[view]-(<=1)-[subview]", 
                                               options: .AlignAllCenterY,
                                               metrics: nil,
                                               views: ["view":view, "subview":subview])

-3

VFL을 사용하는 대신 인터페이스 빌더에서이를 쉽게 수행 할 수 있습니다. 메인 스토리 보드에서 중앙에 놓으려는 뷰를 Ctrl + 클릭하십시오. ctrl을 누른 상태에서 슈퍼 뷰로 드래그하여 "중앙 X"또는 "중앙 Y"를 선택하십시오. 코드가 필요하지 않습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.