source

컨테이너 뷰 내에서 여러 뷰의 간격을 균등하게 지정합니다.

ittop 2023. 4. 27. 22:44
반응형

컨테이너 뷰 내에서 여러 뷰의 간격을 균등하게 지정합니다.

자동 레이아웃이 제 삶을 어렵게 만들고 있습니다.이론적으로, 제가 전환했을 때 정말 유용할 것 같았는데, 저는 항상 그것과 싸우는 것 같습니다.

저는 도움을 찾기 위해 데모 프로젝트를 만들었습니다.보기 크기가 조정될 때마다 보기 사이의 공간을 고르게 늘리거나 줄일 수 있는 방법을 아는 사람이 있습니까?

다음은 세 개의 레이블(수동으로 수직으로 간격을 같음)입니다.

이미지1

회전할 때 간격(보기 크기가 아니라) 크기를 고르게 조정하기를 원합니다.기본적으로 위쪽 및 아래쪽 보기는 가운데를 향해 기울어져 있습니다.

이미지2

보세요, 스페이서는 안 됩니다!

원래 답변의 댓글 부분에 있는 제안, 특히 @Rivera의 도움이 되는 제안을 바탕으로 원래 답변을 단순화했습니다.

저는 이것이 얼마나 간단한지 설명하기 위해 gif를 사용하고 있습니다.저는 당신이 gif가 도움이 되기를 바랍니다.만약 당신이 gif에 문제가 있다면, 저는 아래의 기존 답을 일반 스크린 샷과 함께 포함시켰습니다.

지침:

단추 또는 레이블을 추가합니다.저는 3개의 버튼을 사용하고 있습니다.

각 버튼의 중심 x 제약 조건을 수퍼뷰에 추가합니다.

여기에 이미지 설명 입력

각 버튼의 구속조건을 맨 아래 레이아웃 구속조건에 추가합니다.

여기에 이미지 설명 입력

위의 #3에 추가된 제약 조건을 다음과 같이 조정합니다.

제약 조건을 선택하고, b) 상수를 제거하고(0으로 설정), c) 승수를 다음과 같이 변경합니다. 버튼 수 + 1을 선택한 후 맨 위에서 승수를 buttonCountPlus1:1, buttonCountPlus1:2, 마지막으로 buttonCountPlus1:3으로 설정합니다.(관심이 있으시면 아래의 오래된 답변에서 이 공식을 어디서 구했는지 설명합니다.)

여기에 이미지 설명 입력

데모가 진행 중입니다!

여기에 이미지 설명 입력

참고: 버튼의 높이가 더 큰 경우에는 버튼 하단에서 제약 조건이 발생하므로 상수 값으로 이 값을 보정해야 합니다.


오래된 대답


애플의 문서와 에리카 사둔의 훌륭한 책(Auto Layout Demystified)에도 불구하고, 스페이서 없이 균일하게 를 띄우는 것이 가능합니다.이 작업은 IB 및 코드에서 균등하게 간격을 두고 수행할 수 있는 모든 요소에 대해 매우 간단합니다.당신이 필요한 것은 "섹션 공식"이라고 불리는 수학 공식입니다.설명하는 것보다 하는 것이 더 간단합니다.IB에서 시연을 해서 최선을 다하겠지만, 코드로 하면 그만큼 쉽습니다.

문제의 예에서, 당신은 다음과 같습니다.

각 레이블에 중심 제약 조건을 설정하는 것으로 시작합니다.이것은 매우 간단합니다.각 라벨에서 하단으로 드래그만 제어하면 됩니다.

Shift 키를 누른 상태로 유지하면 "하단 공간에서 하단 레이아웃 가이드"라는 다른 제약 조건을 추가할 수 있습니다.

하단 공간에서 하단 레이아웃 안내서를 선택하고 "용기에서 수평으로 가운데"를 선택합니다.세 레이블 모두에 대해 이 작업을 수행합니다.

각 레이블에 대해 이 두 제약 조건을 추가하려면 Shift 키를 누른 상태로 유지

기본적으로 좌표를 결정하고 싶은 레이블을 총 레이블 수에 1을 더하면 IB에 추가할 수 있는 번호가 있습니다.공식을 단순화하고 있지만, 수평 간격을 설정하거나 수직과 수평을 동시에 설정하는 데 사용할 수 있습니다.그것은 매우 강력합니다!

여기 우리의 곱셈기가 있습니다.

라벨 1 = 1/4 = .25,

라벨 2 = 2/4 = .5,

라벨 3 = 3/4 = .75

(편집: @Rivera는 승수 필드에서 비율을 직접 사용하고 xCode는 산술을 사용하면 된다고 언급했습니다!)

이제 Label1을 선택하고 하단 제약 조건을 선택합니다.같이: 과같이다음과같:여기에 이미지 설명 입력

속성 관리자에서 "두 번째 항목"을 선택합니다.

드롭다운에서 "첫 번째 항목과 두 번째 항목 반전"을 선택합니다.

상수 및 wChanAny 값을 0으로 합니다.(필요한 경우 여기에 오프셋을 추가할 수 있습니다.)

다음은 중요한 부분입니다.승수 필드에 첫 번째 승수 0.25를 추가합니다.

작업하는 동안 상단의 "첫 번째 항목"을 "중앙"으로 설정합니다.Y" 레이블의 y 센터에 중심을 맞추고 싶기 때문입니다.이것이 모든 것이 어떻게 보여야 하는지입니다.

여기에 이미지 설명 입력

10) 각 레이블에 대해 이 과정을 반복하고 관련 승수(Label2의 경우 0.5, Label3의 경우 0.75)를 연결합니다.모든 소형 기기를 갖춘 모든 방향의 최종 제품입니다!아주 간단합니다.저는 수많은 코드와 스페이서를 포함한 많은 해결책을 찾고 있습니다.이것은 제가 그 문제에 대해 본 최고의 해결책입니다.

업데이트: @kraftydevil은 하단 레이아웃 가이드가 xibs가 아닌 스토리보드에만 표시된다고 추가합니다.xibs 단위의 '용기 하단 공간'을 사용합니다.잘 잡았습니다!

여기에 이미지 설명 입력

그래서 제 접근 방식은 인터페이스 빌더에서 이것을 할 수 있게 해줍니다.높이를 동일하게 일치하도록 설정한 '스페이스 뷰'를 만듭니다.그런 다음 레이블에 상단 및 하단 구속조건을 추가합니다(스크린샷 참조).

여기에 이미지 설명 입력

좀 더 구체적으로 말하자면, 저는 '스페이스 뷰 1'에서 우선순위가 1000보다 낮고 높이가 다른 모든 '스페이스 뷰'와 동일한 높이로 감독하도록 상위 제약 조건을 가지고 있습니다.'Spacer View 4'는 맨 아래 공간에 제한이 있습니다.각 레이블에는 가장 가까운 '스페이스 뷰'에 대해 각각의 상단 및 하단 제약 조건이 있습니다.

참고: '공간 뷰'에 대한 레이블에 추가적인 상단/하단 공간 제약 조건이 없어야 합니다.상단과 하단 제약 조건이 각각 '스페이스 뷰 1'과 '스페이스 뷰 4'에 있기 때문에 만족스러울 것입니다.

Duh 1: 저는 제 견해를 복제해서 여러분이 효과가 있다는 것을 알 수 있도록 단지 풍경 모드에 놓았습니다.

Duh 2: '스페이스 뷰'는 투명할 수 있었습니다.

Duh 3: 이 접근법은 수평적으로 적용될 수 있습니다.

매우 빠른 인터페이스 빌더 솔루션:

한 간격으로 되는 뷰의 는 수평의 경우 "X to 뷰에 수직 " Y" 제약 조건을 를 "Multiplier"를 "X"로 .N:p(참고: 일부는 운이 더 좋았습니다 - 아래 참조)

어디에

N = total number of views,그리고.

p = position of the view including spaces

첫 번째 위치는 1이고, 다음 위치는 공간이며, 다음 위치는 3입니다. sop은 시리즈가 됩니다 [1, 3, 5, 7, 9, ...].원하는 개수의 보기에 사용할 수 있습니다.

따라서 3개의 보기를 공백으로 둘 경우 다음과 같이 나타납니다.

IB에서 보기를 고르게 분산하는 방법에 대한 그림

편집 참고:의 선택N:p또는p:N선형 제약 조건의 관계 순서에 따라 달라집니다.첫 번째 항목이 수퍼뷰인 경우.은 터센, 사가능을 할 수 있습니다.p:N반면에 만약 슈퍼뷰라면. Item이며, "Second Item", "Second Item"을 .N:p의심스럽다면, 둘 다 시도해 보세요...:-)

iOS 9부터 Apple은 (오래전부터 기다려온)로 매우 쉽게 할 수 있게 되었습니다. Interface Builder에 포함할 뷰를 선택하고 Editor -> Embed In -> Stack view를 선택하면 됩니다.스택 뷰에 적합한 너비/높이/마진 제약 조건을 설정하고 분포 특성을 '동일한 간격'으로 설정해야 합니다.

물론 iOS 8 이하를 지원해야 한다면 다른 옵션 중 하나를 선택해야 합니다.

저는 자동 레이아웃을 사랑하고 싫어하는 롤러코스터를 탔습니다.그것을 사랑하는 비결은 다음을 받아들이는 것 같습니다.

  1. 인터페이스 빌더의 편집 및 "도움이 되는" 제약 조건 자동 생성은 가장 사소한 경우를 제외한 모든 경우에 거의 쓸모가 없습니다.
  2. 코드가 너무 반복적이고 장황하기 때문에 일반적인 작업을 단순화하기 위해 범주를 만드는 것은 생명을 구하는 것입니다.

즉, 당신이 시도하는 것은 간단하지 않고 인터페이스 빌더에서 달성하기 어려울 것입니다.코드로 하는 것은 꽤 간단합니다.이코는드로,viewDidLoad에서는 사용자가 요청하는 방식으로 세 개의 레이블을 만들고 배치합니다.

// Create three labels, turning off the default constraints applied to views created in code
UILabel *label1 = [UILabel new];
label1.translatesAutoresizingMaskIntoConstraints = NO;
label1.text = @"Label 1";

UILabel *label2 = [UILabel new];
label2.translatesAutoresizingMaskIntoConstraints = NO;
label2.text = @"Label 2";

UILabel *label3 = [UILabel new];
label3.translatesAutoresizingMaskIntoConstraints = NO;
label3.text = @"Label 3";

// Add them all to the view
[self.view addSubview:label1];
[self.view addSubview:label2];
[self.view addSubview:label3];

// Center them all horizontally
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:label1 attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0]];

[self.view addConstraint:[NSLayoutConstraint constraintWithItem:label2 attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0]];

[self.view addConstraint:[NSLayoutConstraint constraintWithItem:label3 attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0]];

// Center the middle one vertically
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:label2 attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0]];

// Position the top one half way up
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:label1 attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:label2 attribute:NSLayoutAttributeCenterY multiplier:0.5 constant:0]];

// Position the bottom one half way down
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:label3 attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:label2 attribute:NSLayoutAttributeCenterY multiplier:1.5 constant:0]];

제가 말씀드렸듯이, 이 코드는 몇 가지 범주 방법으로 훨씬 단순화되어 있습니다.UIView하지만 명확하게 하기 위해 여기서 오랫동안 해왔습니다.

이 카테고리는 관심 있는 사람들을 위해 여기에 있으며, 특정 축을 따라 일련의 뷰를 균등하게 간격을 둘 수 있는 방법이 있습니다.

스택 보기를 사용하는 것이 올바르고 쉬운 방법입니다.

  1. 스택 뷰에 레이블/뷰를 추가합니다.

여기에 이미지 설명 입력

  1. 스택 뷰를 선택하고 분포를 동일한 간격으로 설정합니다.

여기에 이미지 설명 입력

  1. 스택 뷰 및 업데이트 프레임에 가장 가까운 인접 제약 조건에 간격 추가:

여기에 이미지 설명 입력

  1. 모든 레이블에 높이 제약 조건을 추가합니다(선택 사항).고유 크기가 없는 뷰에만 필요합니다.예를 들어, 레이블에는 높이 제약 조건이 필요하지 않으며 numberOfLines = 3 또는 0만 설정하면 됩니다.

여기에 이미지 설명 입력

  1. 미리 보기:

여기에 이미지 설명 입력

이러한 솔루션의 대부분은 중간 항목을 선택하여 중앙에 배치할 수 있도록 홀수 항목 수에 따라 달라집니다.여전히 균등하게 분배되기를 원하는 항목이 짝수인 경우에는 어떻게 해야 합니까?여기 좀 더 일반적인 해결책이 있습니다.이 범주는 수직 또는 수평 축을 따라 임의의 수의 항목을 균등하게 분배합니다.

수퍼뷰 내에서 레이블 4개를 수직으로 분포시키는 사용 예:

[self.view addConstraints:
     [NSLayoutConstraint constraintsForEvenDistributionOfItems:@[label1, label2, label3, label4]
                                        relativeToCenterOfItem:self.view
                                                    vertically:YES]];

NS 레이아웃 제약 조건 + 균등 분포.h

@interface NSLayoutConstraint (EvenDistribution)

/**
 * Returns constraints that will cause a set of views to be evenly distributed horizontally
 * or vertically relative to the center of another item. This is used to maintain an even
 * distribution of subviews even when the superview is resized.
 */
+ (NSArray *) constraintsForEvenDistributionOfItems:(NSArray *)views
                             relativeToCenterOfItem:(id)toView
                                         vertically:(BOOL)vertically;

@end

NS 레이아웃 제약 조건 + 균등 분포.m

@implementation NSLayoutConstraint (EvenDistribution)

+(NSArray *)constraintsForEvenDistributionOfItems:(NSArray *)views
                           relativeToCenterOfItem:(id)toView vertically:(BOOL)vertically
{
    NSMutableArray *constraints = [NSMutableArray new];
    NSLayoutAttribute attr = vertically ? NSLayoutAttributeCenterY : NSLayoutAttributeCenterX;

    for (NSUInteger i = 0; i < [views count]; i++) {
        id view = views[i];
        CGFloat multiplier = (2*i + 2) / (CGFloat)([views count] + 1);
        NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:view
                                                                      attribute:attr
                                                                      relatedBy:NSLayoutRelationEqual
                                                                         toItem:toView
                                                                      attribute:attr
                                                                     multiplier:multiplier
                                                                       constant:0];
        [constraints addObject:constraint];
    }

    return constraints;
}

@end

오픈 소스 라이브러리 PureLayout을 확인하십시오.각 뷰 사이의 간격이 고정되어 있는 변형(필요에 따라 뷰 크기가 변경됨) 및 각 뷰의 크기가 고정되어 있는 변형(필요에 따라 뷰 사이의 간격이 변경됨)을 포함하여 뷰를 배포하기 위한 몇 가지 API 방법을 제공합니다.이러한 모든 작업은 "spacer view"를 사용하지 않고 수행됩니다.

NSArray+PureLayout에서.h:

// NSArray+PureLayout.h

// ...

/** Distributes the views in this array equally along the selected axis in their superview. Views will be the same size (variable) in the dimension along the axis and will have spacing (fixed) between them. */
- (NSArray *)autoDistributeViewsAlongAxis:(ALAxis)axis
                                alignedTo:(ALAttribute)alignment
                         withFixedSpacing:(CGFloat)spacing;

/** Distributes the views in this array equally along the selected axis in their superview. Views will be the same size (fixed) in the dimension along the axis and will have spacing (variable) between them. */
- (NSArray *)autoDistributeViewsAlongAxis:(ALAxis)axis
                                alignedTo:(ALAttribute)alignment
                            withFixedSize:(CGFloat)size;

// ...

이 모든 것이 오픈 소스이므로 Spacer View를 사용하지 않고 이를 실현하는 방법에 관심이 있다면 구현을 살펴보시기 바랍니다.(둘 다 활용하는 것에 따라 다릅니다.constant 그리고. multiplier(제약 조건에 대해).

저도 비슷한 문제가 있어서 이 게시물을 발견했습니다.그러나 현재 제공된 답변 중 원하는 방식으로 문제를 해결하는 것은 없습니다.간격을 동일하게 만들지 않고 레이블의 중심을 동일하게 분포시킵니다.이것은 같지 않다는 것을 이해하는 것이 중요합니다.저는 이것을 설명하기 위해 작은 도표를 만들었습니다.

간격 그림 보기

3개의 뷰가 있는데, 모두 20피트 높이입니다.제안된 방법 중 하나를 사용하면 뷰의 중심이 균등하게 분포되고 그림이 표시된 레이아웃이 제공됩니다.뷰의 y-중심은 동일한 간격으로 배치됩니다.그러나 상위 보기와 상위 보기 사이의 간격은 15pt인 반면 하위 보기 사이의 간격은 5pt입니다.보기 간격을 동일하게 하려면 둘 다 10pt여야 합니다. 즉, 파란색 화살표는 모두 10pt여야 합니다.

그럼에도 불구하고, 저는 아직 좋은 일반적인 해결책을 생각해내지 못했습니다.현재는 하위 뷰 사이에 "공백 뷰"를 삽입하고 간격 뷰의 높이를 동일하게 설정하는 것이 가장 좋습니다.

저는 IB에서 이 문제를 완전히 해결할 수 있었습니다.

  1. 각 하위 뷰의 중심 Y를 수퍼 뷰의 아래쪽 가장자리에 정렬하도록 제약 조건을 지정합니다.
  2. 이러한 각 제약 조건의 승수를 1/2n, 3/2n, 5/2n, …, n-1/2n으로 설정합니다. 여기서 n은 배포 중인 하위 뷰의 수입니다.

따라서 레이블이 세 개인 경우 곱셈기를 각 제약 조건에 0.166667, 0.5, 0.833333으로 설정합니다.

저는 완벽하고 간단한 방법을 찾았습니다.자동 레이아웃을 사용하면 공간 크기를 동일하게 조정할 수 없지만 보기 크기를 동일하게 조정할 수 있습니다.필드 사이에 보이지 않는 뷰를 배치하고 자동 레이아웃을 지정하여 크기를 동일하게 유지하기만 하면 됩니다.완벽하게 작동합니다!

초기 XIB

확장 XIB

하지만 한 가지 주목할 점은, 인터페이스 디자이너에서 크기를 줄였을 때, 때때로 혼동을 일으켜 라벨이 있는 곳에 남았고, 크기가 홀수로 바뀌면 충돌이 발생했다는 것입니다.그렇지 않으면 완벽하게 작동했습니다.

편집: 갈등이 문제가 된 것을 발견했습니다.그 때문에, 저는 간격 제약 조건 중 하나를 선택하여 삭제하고 두 개의 제약 조건, 즉 같거나 같거나 같거나 같지 않은 것으로 대체했습니다.둘 다 크기가 같고 다른 제약 조건보다 우선 순위가 훨씬 낮았습니다.그 결과 더 이상의 갈등은 없었습니다.

Ben Dolman의 대답을 바탕으로, 이것은 (패딩 등을 사용하여) 뷰를 더 고르게 분산시킵니다.

+(NSArray *)constraintsForEvenDistributionOfItems:(NSArray *)views
                           relativeToCenterOfItem:(id)toView vertically:(BOOL)vertically
{
    NSMutableArray *constraints = [NSMutableArray new];
    NSLayoutAttribute attr = vertically ? NSLayoutAttributeCenterY : NSLayoutAttributeCenterX;

    CGFloat min = 0.25;
    CGFloat max = 1.75;
    CGFloat d = (max-min) / ([views count] - 1);
    for (NSUInteger i = 0; i < [views count]; i++) {
        id view = views[i];
        CGFloat multiplier = i * d + min;
        NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:view
                                                                      attribute:attr
                                                                      relatedBy:NSLayoutRelationEqual
                                                                         toItem:toView
                                                                      attribute:attr
                                                                     multiplier:multiplier
                                                                       constant:0];
        [constraints addObject:constraint];
    }

    return constraints;
}

당신의 문제를 해결하는 것에 대한 멋진 설명을 가진 https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/AutoLayoutbyExample/AutoLayoutbyExample.html 을 확인하세요.

라벨을 사용하면 적어도 다음과 같이 작동합니다.

@"H:|-15-[first(==second)]-[second(==third)]-[third(==first)]-15-|

만약 첫 번째가 두 번째와 같은 폭을 가지고 있고, 두 번째가 세 번째이고, 세 번째가 첫 번째와 같은 폭을 가지고 있다면, 그들은 모두 같은 폭을 갖게 될 것입니다.수평(H)과 수직(V) 모두 가능합니다.

swift 3 버전

let _redView = UIView()
        _redView.backgroundColor = UIColor.red
        _redView.translatesAutoresizingMaskIntoConstraints = false

        let _yellowView = UIView()
        _yellowView.backgroundColor = UIColor.yellow
        _yellowView.translatesAutoresizingMaskIntoConstraints = false

        let _blueView = UIView()
        _blueView.backgroundColor = UIColor.blue
        _blueView.translatesAutoresizingMaskIntoConstraints = false

        self.view.addSubview(_redView)
        self.view.addSubview(_yellowView)
        self.view.addSubview(_blueView)

        var views = ["_redView": _redView, "_yellowView": _yellowView, "_blueView":_blueView]

        var nslayoutConstraint_H = NSLayoutConstraint.constraints(withVisualFormat: "|->=0-[_redView(40)]->=0-[_yellowView(40)]->=0-[_blueView(40)]->=0-|", options: [.alignAllTop, .alignAllBottom], metrics: nil, views: views)
        self.view.addConstraints(nslayoutConstraint_H)

        var nslayoutConstraint_V = NSLayoutConstraint.constraints(withVisualFormat: "V:[_redView(60)]", options: NSLayoutFormatOptions.init(rawValue: 0), metrics: nil, views: views)
        self.view.addConstraints(nslayoutConstraint_V)


        let constraint_red = NSLayoutConstraint.init(item: self.view, attribute: .centerY, relatedBy: .equal, toItem: _redView, attribute: .centerY, multiplier: 1, constant: 0)
        self.view.addConstraint(constraint_red)

        let constraint_yellow = NSLayoutConstraint.init(item: self.view, attribute: .centerX, relatedBy: .equal, toItem: _yellowView, attribute: .centerX, multiplier: 1, constant: 0)
        self.view.addConstraint(constraint_yellow)

        let constraint_yellow1 = NSLayoutConstraint.init(item: _redView, attribute: .centerX, relatedBy: .equal, toItem: _yellowView, attribute: .leading, multiplier: 0.5, constant: 0)
        self.view.addConstraint(constraint_yellow1)

        let constraint_yellow2 = NSLayoutConstraint.init(item: _blueView, attribute: .centerX, relatedBy: .equal, toItem: _yellowView, attribute: .leading, multiplier: 1.5, constant: 40)
        self.view.addConstraint(constraint_yellow2)

첫 번째 답변 이후로 시간이 꽤 흘렀지만, 저는 똑같은 문제를 발견했고 저의 해결책을 공유하고 싶습니다.앞으로 몇 세대 동안...

viewDidLoad:에 대한 내 견해를 설정했습니다.

- (void)viewDidLoad {

    [super viewDidLoad];

    cancelButton = [UIButton buttonWithType: UIButtonTypeRoundedRect];
    cancelButton.translatesAutoresizingMaskIntoConstraints = NO;
    [cancelButton setTitle:@"Cancel" forState:UIControlStateNormal];
    [self.view addSubview:cancelButton];

    middleButton = [UIButton buttonWithType: UIButtonTypeRoundedRect];
    middleButton.translatesAutoresizingMaskIntoConstraints = NO;
    [middleButton setTitle:@"Middle" forState:UIControlStateNormal];
    [self.view addSubview:middleButton];

    nextButton = [UIButton buttonWithType: UIButtonTypeRoundedRect];
    nextButton.translatesAutoresizingMaskIntoConstraints = NO;
    [nextButton setTitle:@"Next" forState:UIControlStateNormal];
    [self.view addSubview:nextButton];


    [self.view setNeedsUpdateConstraints];

}

그런 다음 updateViewConstraines에서 먼저 모든 제약 조건을 삭제하고 뷰 사전을 만든 다음 뷰 사이에 사용할 공간을 계산합니다.그런 다음 시각적 언어 형식을 사용하여 다음과 같은 제약 조건을 설정합니다.

- (void)updateViewConstraints {


    [super updateViewConstraints];

    [self.view removeConstraints:self.view.constraints];

    NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(cancelButton, nextButton, middleButton);

    float distance=(self.view.bounds.size.width-cancelButton.intrinsicContentSize.width-nextButton.intrinsicContentSize.width-middleButton.intrinsicContentSize.width-20-20)/  ([viewsDictionary count]-1);  // 2 times 20 counts for the left & rigth margins
    NSNumber *distancies=[NSNumber numberWithFloat:distance];

//    NSLog(@"Distancies: %@", distancies);
//    
//    NSLog(@"View Width: %f", self.view.bounds.size.width);
//    NSLog(@"Cancel Width: %f", cancelButton.intrinsicContentSize.width);
//    NSLog(@"Middle Width: %f", middleButton.intrinsicContentSize.width);
//    NSLog(@"Next Width: %f", nextButton.intrinsicContentSize.width);



    NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"|-[cancelButton]-dis-[middleButton]-dis-[nextButton]-|"
                                                                   options:NSLayoutFormatAlignAllBaseline
                                                                   metrics:@{@"dis":distancies}
                                                                     views:viewsDictionary];


    [self.view addConstraints:constraints];



    constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[nextButton]-|"
                                                          options:0
                                                          metrics:nil
                                                            views:viewsDictionary];
    [self.view addConstraints:constraints];



}

이 방법의 좋은 점은 수학을 아주 적게 해야 한다는 것입니다.이것이 완벽한 해결책이라고 말하는 것은 아니지만, 저는 제가 달성하고자 했던 레이아웃을 위해 일합니다.

도움이 되길 바랍니다.

여기에는 고유한 크기를 가지더라도 임의의 수의 하위 보기를 수직으로 중앙에 배치할 수 있는 솔루션이 있습니다.중간 수준의 컨테이너를 만들고 이 컨테이너를 수퍼 뷰의 중앙에 배치한 다음 모든 하위 뷰를 컨테이너에 넣고 서로에 대해 정렬합니다.그러나 중요한 것은 컨테이너의 크기를 정확하게 지정하고 수퍼 뷰의 중심에 배치할 수 있도록 컨테이너를 컨테이너의 상단과 하단으로 제한해야 한다는 것입니다.하위 뷰에서 정확한 높이를 지정하면 용기가 수직으로 중앙에 배치될 수 있습니다.

예에서는, 이예서는에,는,self모든 하위 보기의 중심에 있는 수퍼 뷰입니다.

NSArray *subviews = @[ (your subviews in top-to-bottom order) ];

UIView *container = [[UIView alloc] initWithFrame:CGRectZero];
container.translatesAutoresizingMaskIntoConstraints = NO;
for (UIView *subview in subviews) {
    subview.translatesAutoresizingMaskIntoConstraints = NO;
    [container addSubview:subview];
}
[self addSubview:container];

[self addConstraint:[NSLayoutConstraint constraintWithItem:container attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual
                                                    toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0f constant:0.0f]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:container attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual
                                                    toItem:self attribute:NSLayoutAttributeRight multiplier:1.0f constant:0.0f]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:container attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual
                                                    toItem:self attribute:NSLayoutAttributeCenterY multiplier:1.0f constant:0.0f]];

if (0 < subviews.count) {
    UIView *firstSubview = subviews[0];
    [container addConstraint:[NSLayoutConstraint constraintWithItem:firstSubview attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual
                                                             toItem:container attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f]];
    UIView *lastSubview = subviews.lastObject;
    [container addConstraint:[NSLayoutConstraint constraintWithItem:lastSubview attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual
                                                             toItem:container attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f]];

    UIView *subviewAbove = nil;
    for (UIView *subview in subviews) {
        [container addConstraint:[NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual
                                                                 toItem:container attribute:NSLayoutAttributeCenterX multiplier:1.0f constant:0.0f]];
        if (subviewAbove) {
            [container addConstraint:[NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual
                                                                     toItem:subviewAbove attribute:NSLayoutAttributeBottom multiplier:1.0f constant:10.0f]];
        }
        subviewAbove = subview;
    }
}

저는 방금 승수 기능을 사용하여 문제를 해결했습니다.모든 경우에 효과가 있는지는 모르겠지만, 저에게는 완벽하게 효과가 있었습니다.저는 Xcode 6.3 FYI입니다.

결국 제가 한 일은:

먼저 320px 너비의 화면에 버튼을 배치하고 320px 장치에서 원하는 방식으로 버튼을 배치했습니다.

1단계: 버튼 위치 지정

그런 다음 모든 단추를 관리하기 위해 선도적인 공간 제약 조건을 추가했습니다.

2단계: 선행 공간 제약 조건 추가

그런 다음 정수가 0이고 승수가 x 오프셋을 화면 너비로 나누도록 선행 공간의 속성을 수정했습니다(예: 첫 단추가 왼쪽 가장자리에서 8px였기 때문에 승수를 8/320으로 설정).

그런 다음 여기서 중요한 단계는 제약 조건 관계의 두 번째 항목을 수퍼뷰로 변경하는 것입니다.superview.leading 대신 trailing.이것이 중요한 이유는 감독관이기 때문입니다.제 경우 선행은 0이고 후행은 320이므로 320px 장치에서 8/320은 8px입니다. 그러면 수퍼뷰의 너비가 640 또는 그 무엇이든로 변경되면 보기가 320px 화면 크기의 너비에 상대적인 비율로 모두 이동합니다.여기 수학은 훨씬 더 이해하기 쉽습니다.

3단계 및 4단계: 승수를 xPos/screenWidth로 변경하고 두 번째 항목을 로 설정합니다.

많은 답들이 정확하지 않지만, 많은 숫자를 얻습니다.여기서는 솔루션을 프로그래밍 방식으로 작성할 입니다. 3개의 뷰는 스페이서 뷰를 사용하지 않고 수평으로 정렬되어 있지만 스토리보드에서 사용할 때 레이블의 너비를 알 수 있을 때만 작동합니다.

NSDictionary *views = NSDictionaryOfVariableBindings(_redView, _yellowView, _blueView);

[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|->=0-[_redView(40)]->=0-[_yellowView(40)]->=0-[_blueView(40)]->=0-|" options:NSLayoutFormatAlignAllTop | NSLayoutFormatAlignAllBottom metrics:nil views:views]];

[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_redView(60)]" options:0 metrics:nil views:views]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:_redView attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];

[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:_yellowView attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:_redView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:_yellowView attribute:NSLayoutAttributeLeading multiplier:0.5 constant:0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:_blueView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:_yellowView attribute:NSLayoutAttributeLeading multiplier:1.5 constant:40]];

여기 또 다른 답이 있습니다.저는 비슷한 질문에 답하다가 이 질문에 대한 링크를 보았습니다.저는 저와 비슷한 답변을 보지 못했습니다.그래서 여기에 쓰려고 생각했습니다.

  class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = UIColor.whiteColor()
        setupViews()
    }

    var constraints: [NSLayoutConstraint] = []

    func setupViews() {

        let container1 = createButtonContainer(withButtonTitle: "Button 1")
        let container2 = createButtonContainer(withButtonTitle: "Button 2")
        let container3 = createButtonContainer(withButtonTitle: "Button 3")
        let container4 = createButtonContainer(withButtonTitle: "Button 4")

        view.addSubview(container1)
        view.addSubview(container2)
        view.addSubview(container3)
        view.addSubview(container4)

        [

            // left right alignment
            container1.leftAnchor.constraintEqualToAnchor(view.leftAnchor, constant: 20),
            container1.rightAnchor.constraintEqualToAnchor(view.rightAnchor, constant: -20),
            container2.leftAnchor.constraintEqualToAnchor(container1.leftAnchor),
            container2.rightAnchor.constraintEqualToAnchor(container1.rightAnchor),
            container3.leftAnchor.constraintEqualToAnchor(container1.leftAnchor),
            container3.rightAnchor.constraintEqualToAnchor(container1.rightAnchor),
            container4.leftAnchor.constraintEqualToAnchor(container1.leftAnchor),
            container4.rightAnchor.constraintEqualToAnchor(container1.rightAnchor),


            // place containers one after another vertically
            container1.topAnchor.constraintEqualToAnchor(view.topAnchor),
            container2.topAnchor.constraintEqualToAnchor(container1.bottomAnchor),
            container3.topAnchor.constraintEqualToAnchor(container2.bottomAnchor),
            container4.topAnchor.constraintEqualToAnchor(container3.bottomAnchor),
            container4.bottomAnchor.constraintEqualToAnchor(view.bottomAnchor),


            // container height constraints
            container2.heightAnchor.constraintEqualToAnchor(container1.heightAnchor),
            container3.heightAnchor.constraintEqualToAnchor(container1.heightAnchor),
            container4.heightAnchor.constraintEqualToAnchor(container1.heightAnchor)
            ]
            .forEach { $0.active = true }
    }


    func createButtonContainer(withButtonTitle title: String) -> UIView {
        let view = UIView(frame: .zero)
        view.translatesAutoresizingMaskIntoConstraints = false

        let button = UIButton(type: .System)
        button.translatesAutoresizingMaskIntoConstraints = false
        button.setTitle(title, forState: .Normal)
        view.addSubview(button)

        [button.centerYAnchor.constraintEqualToAnchor(view.centerYAnchor),
            button.leftAnchor.constraintEqualToAnchor(view.leftAnchor),
            button.rightAnchor.constraintEqualToAnchor(view.rightAnchor)].forEach { $0.active = true }

        return view
    }
}

여기에 이미지 설명 입력

iOS9 UI StackView를 사용하면 이 작업을 매우 쉽게 수행할 수 있습니다.

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = UIColor.greenColor()
        setupViews()
    }

    var constraints: [NSLayoutConstraint] = []

    func setupViews() {

        let container1 = createButtonContainer(withButtonTitle: "Button 1")
        let container2 = createButtonContainer(withButtonTitle: "Button 2")
        let container3 = createButtonContainer(withButtonTitle: "Button 3")
        let container4 = createButtonContainer(withButtonTitle: "Button 4")

        let stackView = UIStackView(arrangedSubviews: [container1, container2, container3, container4])
        stackView.translatesAutoresizingMaskIntoConstraints = false
        stackView.axis = .Vertical
        stackView.distribution = .FillEqually
        view.addSubview(stackView)

        [stackView.topAnchor.constraintEqualToAnchor(view.topAnchor),
            stackView.bottomAnchor.constraintEqualToAnchor(view.bottomAnchor),
            stackView.leftAnchor.constraintEqualToAnchor(view.leftAnchor, constant: 20),
            stackView.rightAnchor.constraintEqualToAnchor(view.rightAnchor, constant: -20)].forEach { $0.active = true }
    }


    func createButtonContainer(withButtonTitle title: String) -> UIView {
        let button = UIButton(type: .Custom)
        button.translatesAutoresizingMaskIntoConstraints = false
        button.backgroundColor = UIColor.redColor()
        button.setTitleColor(UIColor.whiteColor(), forState: .Normal)
        button.setTitle(title, forState: .Normal)
        let buttonContainer = UIStackView(arrangedSubviews: [button])
        buttonContainer.distribution = .EqualCentering
        buttonContainer.alignment = .Center
        buttonContainer.translatesAutoresizingMaskIntoConstraints = false
        return buttonContainer
    }
}

위와 완전히 동일한 접근 방식입니다.동일하게 채워진 4개의 컨테이너 뷰가 추가되고 중앙에 정렬된 각 스택 뷰에 뷰가 추가됩니다.그러나 이 버전의 UIStackView는 일부 코드를 줄이고 보기에 좋습니다.

또 다른 접근 방식은 상단 및 하단 레이블이 뷰 상단 및 하단에 각각 상대적인 제약 조건을 가지며 중간 뷰가 첫 번째 및 세 번째 뷰에 상대적인 상단 및 하단 제약 조건을 갖도록 하는 것입니다.

안내 점선이 나타날 때까지 뷰를 서로 가까이 끌어다 놓으면 보이는 것보다 제약 조건을 더 많이 제어할 수 있습니다. 이러한 제약 조건은 객체와 수퍼 뷰 사이가 아니라 두 객체 사이에 형성될 제약 조건을 나타냅니다.

이 경우 제약 조건의 크기를 조정할 수 있도록 "동일" 대신 원하는 값보다 "동일"하도록 제약 조건을 변경할 수 있습니다.이것이 정확히 당신이 원하는 것을 할 수 있을지 확신할 수 없습니다.

Interface Builder에서 이 문제를 해결하는 매우 쉬운 방법:

중심 레이블(라벨 2)을 "용기의 수평 중심" 및 "용기의 수직 중심"으로 설정합니다.

중심 레이블과 상단 레이블(레이블 1 + 레이블 2)을 선택하고 수직 간격에 대해 두 개의 구속조건을 추가합니다.최소 간격보다 크거나 같은 입니다.최대 간격보다 작거나 같은 입니다.

중심 레이블과 하단 레이블(라벨 2 + 라벨 3)에 대해서도 동일합니다.

또한 레이블 1에 두 개의 구속조건(상위 공간에서 수퍼뷰로)을 추가하고 레이블 2에 두 개의 구속조건(하위 공간에서 수퍼뷰로)을 추가할 수 있습니다.

결과적으로 4개의 간격 모두 크기가 동일하게 변경됩니다.

저는 도움이 될 만한 기능을 만들었습니다.다음 사용 예:

 [self.view addConstraints: [NSLayoutConstraint fluidConstraintWithItems:NSDictionaryOfVariableBindings(button1, button2, button3)
                                                                asString:@[@"button1", @"button2", @"button3"]
                                                               alignAxis:@"V"
                                                          verticalMargin:100
                                                        horizontalMargin:50
                                                             innerMargin:25]];

수직 분포의 원인이 됩니다. 이미지를 포함할 수 있는 10개의 평판이 없습니다.축과 일부 여백 값을 변경하는 경우:

alignAxis:@"H"
verticalMargin:120
horizontalMargin:20
innerMargin:10

수평적인 분포를 얻을 수 있습니다.

나는 iOS 초보자이지만 voila!

균등 분포.h

@interface NSLayoutConstraint (EvenDistribution)

/**
 * Returns constraints that will cause a set of subviews
 * to be evenly distributed along an axis.
 */
+ (NSArray *)  fluidConstraintWithItems:(NSDictionary *) views
                               asString:(NSArray *) stringViews
                              alignAxis:(NSString *) axis
                         verticalMargin:(NSUInteger) vMargin
                       horizontalMargin:(NSUInteger) hMargin
                            innerMargin:(NSUInteger) inner;
@end

균등 분배.m.m.

#import "EvenDistribution.h"

@implementation NSLayoutConstraint (EvenDistribution)

+ (NSArray *) fluidConstraintWithItems:(NSDictionary *) dictViews
                              asString:(NSArray *) stringViews
                             alignAxis:(NSString *) axis
                        verticalMargin:(NSUInteger) vMargin
                      horizontalMargin:(NSUInteger) hMargin
                           innerMargin:(NSUInteger) iMargin

{
    NSMutableArray *constraints = [NSMutableArray arrayWithCapacity: dictViews.count];
    NSMutableString *globalFormat = [NSMutableString stringWithFormat:@"%@:|-%d-",
                                     axis,
                                     [axis isEqualToString:@"V"] ? vMargin : hMargin
                                     ];



        for (NSUInteger i = 0; i < dictViews.count; i++) {

            if (i == 0)
                [globalFormat appendString:[NSString stringWithFormat: @"[%@]-%d-", stringViews[i], iMargin]];
            else if(i == dictViews.count - 1)
                [globalFormat appendString:[NSString stringWithFormat: @"[%@(==%@)]-", stringViews[i], stringViews[i-1]]];
            else
               [globalFormat appendString:[NSString stringWithFormat: @"[%@(==%@)]-%d-", stringViews[i], stringViews[i-1], iMargin]];

            NSString *localFormat = [NSString stringWithFormat: @"%@:|-%d-[%@]-%d-|",
                                     [axis isEqualToString:@"V"] ? @"H" : @"V",
                                     [axis isEqualToString:@"V"] ? hMargin : vMargin,
                                     stringViews[i],
                                     [axis isEqualToString:@"V"] ? hMargin : vMargin];

            [constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:localFormat
                                                                                     options:0
                                                                                     metrics:nil
                                                                                       views:dictViews]];


    }
    [globalFormat appendString:[NSString stringWithFormat:@"%d-|",
                                [axis isEqualToString:@"V"] ? vMargin : hMargin
                                ]];

    [constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:globalFormat
                                                                             options:0
                                                                             metrics:nil
                                                                               views:dictViews]];

    return constraints;

}

@end

예, 코드를 작성하지 않고 인터페이스 작성기에서만 이 작업을 수행할 수 있습니다. 한 가지 주의할 점은 공백을 배포하는 대신 레이블의 크기를 조정하는 것입니다.이 경우 레이블 2의 X와 Y를 수퍼뷰에 맞춰 가운데에 고정합니다.그런 다음 레이블 1의 수직 공간을 수퍼뷰로 설정하고 레이블 2를 표준으로 설정한 후 레이블 3에 대해 반복합니다.레이블 2를 설정한 후 레이블 1 및 3을 설정하는 가장 쉬운 방법은 레이블이 끊어질 때까지 크기를 조정하는 것입니다.

수평 디스플레이는 다음과 같습니다. 라벨 1과 2 사이의 수직 공간이 표준으로 설정되어 있습니다.수평 표시

그리고 초상화 버전은 다음과 같습니다.여기에 이미지 설명 입력

레이블 사이의 표준 공간과 수퍼뷰에 대한 표준 공간의 차이로 인해 기준선 사이의 간격이 절대적으로 100% 동일하지 않다는 것을 알고 있습니다.번거로우시다면 사이즈를 표준이 아닌 0으로 설정해주세요.

첫 번째 항목에 대해서만 너비 값(>=폭)과 각 항목 간의 최소 거리(>=거리)를 설정했습니다.그런 다음 Ctrl을 사용하여 두 번째, 세 번째...항목 간의 종속성을 연결할 첫 번째 항목입니다.

여기에 이미지 설명 입력

파티에 늦었지만, 저는 메뉴를 가로로 띄어쓰기로 만들 수 있는 해결책이 있습니다.다음을 사용하여 쉽게 수행할 수 있습니다.==NS 레이아웃 제약 조건

const float MENU_HEIGHT = 40;

- (UIView*) createMenuWithLabels: (NSArray *) labels
    // labels is NSArray of NSString
    UIView * backgroundView = [[UIView alloc]init];
    backgroundView.translatesAutoresizingMaskIntoConstraints = false;

    NSMutableDictionary * views = [[NSMutableDictionary alloc] init];
    NSMutableString * format = [[NSMutableString alloc] initWithString: @"H:|"];
    NSString * firstLabelKey;

    for(NSString * str in labels)
    {
        UILabel * label = [[UILabel alloc] init];
        label.translatesAutoresizingMaskIntoConstraints = false;
        label.text = str;
        label.textAlignment = NSTextAlignmentCenter;
        label.textColor = [UIColor whiteColor];
        [backgroundView addSubview: label];
        [label fixHeightToTopBounds: MENU_HEIGHT-2];
        [backgroundView addConstraints: [label fixHeightToTopBounds: MENU_HEIGHT]];
        NSString * key = [self camelCaseFromString: str];
        [views setObject: label forKey: key];
        if(firstLabelKey == nil)
        {
            [format appendString: [NSString stringWithFormat: @"[%@]", key]];
            firstLabelKey = key;
        }
        else
        {
            [format appendString: [NSString stringWithFormat: @"[%@(==%@)]", key, firstLabelKey]];
        }
    }

    [format appendString: @"|"];

    NSArray * constraints = [NSLayoutConstraint constraintsWithVisualFormat: (NSString *) format
                                                                               options: 0
                                                                               metrics: nil
                                                                                 views: (NSDictionary *) views];
    [backgroundView addConstraints: constraints];
    return backgroundView;
}

저는 5개의 이미지를 수평으로 정렬하고 싶어서 작은 차이로 Mete의 반응을 따라하게 되었습니다.

첫 번째 영상은 0과 같고 1:5의 곱셈기에서 수평으로 중앙에 배치됩니다.

첫 이미지

두 번째 영상은 0과 같고 3:5의 곱셈기에서 수평으로 중앙에 배치됩니다.

그리고 나머지 이미지들도 마찬가지입니다.예를 들어, 다섯 번째(그리고 마지막) 영상은 0과 같고 9:5의 곱셈기에서 수평으로 중앙에 배치됩니다.

Mete의 설명대로 1, 3, 5, 7, 9 등의 순서로 진행됩니다.위치는 동일한 논리를 따릅니다. 첫 번째 위치는 1이고, 다음 위치는 공백이고, 다음 위치는 3입니다.

Android는 제가 모방하고 싶었던 제약 기반 레이아웃 시스템에서 뷰를 함께 연결하는 방법을 가지고 있습니다.검색 결과 여기까지 왔지만 제대로 된 답은 하나도 없었습니다.StackView를 사용하고 싶지 않았습니다. StackView는 사전에 비용을 절감하는 것보다 더 큰 슬픔을 안겨주기 때문입니다.저는 보기 사이에 배치된 UI 레이아웃 가이드를 사용하는 솔루션을 만들었습니다.너비를 제어하면 안드로이드 용어로 다양한 유형의 배포, 체인 스타일이 가능합니다.함수는 상위 뷰 대신 선행 및 후행 앵커를 허용합니다.이렇게 하면 체인을 상위 뷰 내에서 분산하는 대신 두 임의 뷰 사이에 배치할 수 있습니다.를 사용합니다.UILayoutGuideiOS 9+에서만 사용할 수 있지만 더 이상 문제가 되지 않습니다.

public enum LayoutConstraintChainStyle {
    case spread //Evenly distribute between the anchors
    case spreadInside //Pin the first & last views to the sides and then evenly distribute
    case packed //The views have a set space but are centered between the anchors.
}

public extension NSLayoutConstraint {

    static func chainHorizontally(views: [UIView],
                                  leadingAnchor: NSLayoutXAxisAnchor,
                                  trailingAnchor: NSLayoutXAxisAnchor,
                                  spacing: CGFloat = 0.0,
                                  style: LayoutConstraintChainStyle = .spread) -> [NSLayoutConstraint] {
    var constraints = [NSLayoutConstraint]()
    guard views.count > 1 else { return constraints }
    guard let first = views.first, let last = views.last, let superview = first.superview else { return constraints }

    //Setup the chain of views
    var distributionGuides = [UILayoutGuide]()
    var previous = first
    let firstGuide = UILayoutGuide()
    superview.addLayoutGuide(firstGuide)
    distributionGuides.append(firstGuide)
    firstGuide.identifier = "ChainDistribution\(distributionGuides.count)"
    constraints.append(firstGuide.leadingAnchor.constraint(equalTo: leadingAnchor))
    constraints.append(first.leadingAnchor.constraint(equalTo: firstGuide.trailingAnchor, constant: spacing))
    views.dropFirst().forEach { view in
        let g = UILayoutGuide()
        superview.addLayoutGuide(g)
        distributionGuides.append(g)
        g.identifier = "ChainDistribution\(distributionGuides.count)"
        constraints.append(contentsOf: [
            g.leadingAnchor.constraint(equalTo: previous.trailingAnchor),
            view.leadingAnchor.constraint(equalTo: g.trailingAnchor)
        ])
        previous = view
    }
    let lastGuide = UILayoutGuide()
    superview.addLayoutGuide(lastGuide)
    constraints.append(contentsOf: [lastGuide.leadingAnchor.constraint(equalTo: last.trailingAnchor),
                                    lastGuide.trailingAnchor.constraint(equalTo: trailingAnchor)])
    distributionGuides.append(lastGuide)

    //Space the according to the style.
    switch style {
    case .packed:
        if let first = distributionGuides.first, let last = distributionGuides.last {
            constraints.append(first.widthAnchor.constraint(greaterThanOrEqualToConstant: spacing))
            constraints.append(last.widthAnchor.constraint(greaterThanOrEqualToConstant: spacing))
            constraints.append(last.widthAnchor.constraint(equalTo: first.widthAnchor))
            constraints.append(contentsOf:
                distributionGuides.dropFirst().dropLast()
                    .map { $0.widthAnchor.constraint(equalToConstant: spacing) }
                )
        }
    case .spread:
        if let first = distributionGuides.first {
            constraints.append(contentsOf:
                distributionGuides.dropFirst().map { $0.widthAnchor.constraint(equalTo: first.widthAnchor) })
        }
    case .spreadInside:
        if let first = distributionGuides.first, let last = distributionGuides.last {
            constraints.append(first.widthAnchor.constraint(equalToConstant: spacing))
            constraints.append(last.widthAnchor.constraint(equalToConstant: spacing))
            let innerGuides = distributionGuides.dropFirst().dropLast()
            if let key = innerGuides.first {
                constraints.append(contentsOf:
                    innerGuides.dropFirst().map { $0.widthAnchor.constraint(equalTo: key.widthAnchor) }
                )
            }
        }
    }

    return constraints
}

테을생면됩니다성하를 만들면 됩니다.isScrollEnabled = false.

언급URL : https://stackoverflow.com/questions/13075415/evenly-space-multiple-views-within-a-container-view

반응형