[ios] 컨테이너보기 내에 여러보기를 균등하게 배치

자동 레이아웃은 내 인생을 어렵게 만들고 있습니다. 이론 상으로는 스위치를 켰을 때 정말 유용했지만 항상 싸우는 것 같습니다.

도움을 얻으려고 데모 프로젝트를 만들었습니다. 누구나 뷰 크기를 조정할 때마다 뷰 사이의 간격을 균등하게 늘리거나 줄이는 방법을 알고 있습니까?

다음은 세 가지 레이블입니다 (수동으로 세로로 균일하게 구분).

이미지 1

내가 원하는 것은 회전 할 때 간격 (보기 크기가 아닌)의 간격을 균등하게 조정하는 것입니다. 기본적으로 윗면과 밑면은 중심을 향해 뭉개져 있습니다.

이미지 2



답변

내 접근 방식으로 인터페이스 빌더 에서이 작업을 수행 할 수 있습니다. 당신이하는 일은 높이를 동일하게 일치하도록 설정 한 ‘스페이서보기’를 만드는 것입니다. 그런 다음 레이블에 상단 및 하단 구속 조건을 추가하십시오 (스크린 샷 참조).

여기에 이미지 설명을 입력하십시오

보다 구체적으로, ‘Spacer View 1’은 높이 제한이 1000보다 낮고 높이가 다른 모든 ‘스페이서보기’와 동일하게 슈퍼 뷰하기 위해 ‘스페이서보기 1’에 대한 제약이 있습니다. ‘Spacer View 4’에는 수퍼 뷰에 대한 공간 제약이 있습니다. 각 레이블에는 가장 가까운 ‘스페이서 뷰’에 대한 각각의 상단 및 하단 제약 조건이 있습니다.

참고 : 슈퍼 뷰를 위해 레이블에 추가 상단 / 하단 공간 제약이 없는지 확인하십시오. ‘공간보기’에있는 것만. 상단 및 하단 제약 조건이 각각 ‘Space View 1’및 ‘Spacer View 4’에 있으므로 만족할 것입니다.

Duh 1 : 뷰를 복제하고 가로 모드로 전환하여 작동하는 것을 확인할 수있었습니다.

Duh 2 : ‘스페이서 뷰’는 투명했을 수 있습니다.

Duh 3 :이 방법은 수평으로 적용 할 수 있습니다.


답변

스 패커 없어요!

원래 답변의 의견 섹션에있는 제안, 특히 @Rivera의 유용한 제안을 바탕으로 원래 답변을 단순화했습니다.

나는 이것이 얼마나 간단한지를 설명하기 위해 gif를 사용하고 있습니다. gif가 도움이 되길 바랍니다. GIF에 문제가있는 경우 아래의 기존 답변을 일반 스크린 샷과 함께 포함했습니다.

명령:

1) 버튼이나 라벨을 추가하십시오. 3 개의 버튼을 사용하고 있습니다.

2) 각 버튼의 중심 x 구속 조건을 수퍼 뷰에 추가하십시오.

여기에 이미지 설명을 입력하십시오

3) 각 버튼에서 하단 레이아웃 제약 조건으로 제약 조건을 추가하십시오.

여기에 이미지 설명을 입력하십시오

4) 위의 # 3에 추가 된 구속 조건을 다음과 같이 조정하십시오.

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

여기에 이미지 설명을 입력하십시오

5) 여기 데모가 있습니다!

여기에 이미지 설명을 입력하십시오

참고 : 버튼의 높이가 더 크면 구속 조건이 버튼의 맨 아래부터 있으므로 상수 값으로이를 보정해야합니다.


기존 답변


Apple의 문서와 Erica Sadun의 훌륭한 책 ( Auto Layout Demystified )이 말한 내용에도 불구하고 , 스페이서 없이 공간을 균일하게 볼 수 있습니다 . 이것은 IB와 코드에서 간격을두고 원하는 수의 요소에 대해 매우 간단합니다. “섹션 수식”이라는 수학 수식 만 있으면됩니다. 설명하는 것보다 수행하는 것이 더 간단합니다. IB에서 시연하여 최선을 다할 것이지만 코드에서도 쉽게 할 수 있습니다.

문제의 예에서, 당신은

1) 각 레이블을 중심 구속 조건으로 설정하여 시작하십시오. 이것은 매우 간단합니다. 각 레이블에서 아래쪽으로 드래그를 제어하십시오.

2) 우리가 사용할 다른 제한 조건, 즉 “하단 공간-하단 레이아웃 가이드”를 추가 할 수 있으므로 Shift 키를 누르고 있으십시오.

3) “하단 레이아웃 가이드-하단 레이아웃 가이드”와 “컨테이너의 수평 중앙”을 선택하십시오. 3 개 레이블 모두에 대해이 작업을 수행하십시오.

Shift 키를 누른 상태에서 각 레이블에이 두 가지 제약 조건을 추가

기본적으로 좌표를 결정하고 총 레이블 수에 1을 더한 레이블로 나누면 동적 위치를 얻기 위해 IB에 추가 할 수있는 숫자가 있습니다. 수식을 단순화하고 있지만 수평 간격 또는 수직 및 수평을 동시에 설정하는 데 사용할 수 있습니다. 매우 강력합니다!

여기에 우리의 승수가 있습니다.

라벨 1 = 1/4 = .25,

라벨 2 = 2/4 = .5,

라벨 3 = 3/4 = .75

(편집 : @Rivera는 승수 필드에서 직접 비율을 직접 사용할 수 있으며 xCode를 사용하여 수학을 수행 할 수 있다고 언급했습니다!)

4) 이제 Label1을 선택하고 하단 제약 조건을 선택하겠습니다. 이처럼 :
여기에 이미지 설명을 입력하십시오

5) 속성 관리자에서 “두 번째 항목”을 선택하십시오.

6) 드롭 다운에서 “Reverse first and second item”을 선택하십시오.

7) 상수와 wC hAny 값을 제로화합니다. 필요한 경우 여기에 오프셋을 추가 할 수 있습니다.

8) 이것은 중요한 부분입니다. 승수 필드에서 첫 번째 승수 0.25를 추가하십시오.

9) 사용자가 라벨의 y 중심에 가운데를 맞추기 위해 상단의 “첫 번째 항목”을 “CenterY”로 설정하십시오. 다음은 그 모든 모습을 보여줍니다.

여기에 이미지 설명을 입력하십시오

10) 각 레이블에 대해이 과정을 반복하고 관련 승수를 연결하십시오 (Label2의 경우 0.5, Label3의 경우 0.75). 모든 소형 장치를 갖춘 모든 방향의 최종 제품입니다! 매우 간단합니다. 나는 많은 양의 코드와 스페이서와 관련된 많은 솔루션을 찾고 있습니다. 이것은 내가이 문제에서 본 최고의 솔루션입니다.

업데이트 : @kraftydevil는 Bottom Layout Guide가 xibs가 아닌 스토리 보드에만 나타납니다. xibs에서 ‘컨테이너에 하단 공간’을 사용하십시오. 잘 잡아!

여기에 이미지 설명을 입력하십시오


답변

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

뷰의 개수가 균일하게 수퍼 내에 이격되어 들어 단순히 수평 레이아웃 각각 “가운데 맞춤 X 수퍼」제약을주고, 수직 레이아웃”가운데 맞춤 Y의 수퍼을 “및 수 승수를 설정 N:p( 참고 : 일부 행운을 빕니다 p:N-아래 참조 )

어디

N = total number of views,

p = position of the view including spaces

첫 번째 위치는 1, 그 다음 공백으로 다음 위치를 3으로 만듭니다. 따라서 p는 시리즈 [1,3,5,7,9, …]가됩니다. 여러보기에서 작동합니다.

따라서 공간을 확보 할 3 개의 뷰가있는 경우 다음과 같습니다.

IB에서 조회수를 균등하게 분산시키는 방법 설명

편집 참고 : 선택 N:p또는 p:N정렬 구속 조건의 관계 순서에 따라 다릅니다. “First Item”이 Superview.Center이면을 사용할 수 있고 p:NSuperview.Center가 “Second Item”이면을 사용할 수 있습니다 N:p. 의심스러운 경우 두 가지 모두 시도해보십시오 … 🙂


답변

iOS 9부터 Apple은 (대망의)으로 이것을 매우 쉽게 만들었습니다 UIStackView. Interface Builder에 포함하려는보기를 선택하고 Editor-> Embed In-> Stack view를 선택하십시오. 스택 뷰에 적절한 너비 / 높이 / 여백 제약 조건을 설정하고 배포 속성을 ‘같은 간격’으로 설정하십시오.

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


답변

나는 autolayout을 좋아하고 그것을 싫어하는 롤러 코스터를 타고 왔습니다. 그것을 사랑하는 열쇠는 다음을 받아들이는 것 같습니다.

  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되었지만 명확성을 위해 먼 길을 갔다.

카테고리는 현재 관심있는 사람들을위한, 그리고 균등 특정 축을 따라 뷰의 배열 간격하는 방법이있다.


답변

이러한 솔루션의 대부분은 중간 항목을 가져와 가운데에 놓을 수 있도록 홀수 개의 항목이 있는지에 달려 있습니다. 균등하게 배포하려는 항목이 짝수 인 경우 어떻게합니까? 더 일반적인 해결책은 다음과 같습니다. 이 범주는 세로 또는 가로 축을 따라 여러 항목을 균등하게 분배합니다.

슈퍼 뷰 내에 4 개의 레이블을 세로로 배포하는 사용법의 예 :

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

NSLayoutConstraint + EvenDistribution.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

NSLayoutConstraint + EevenDistribution.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


답변

정확하고 쉬운 방법은 스택 뷰를 사용하는 것입니다.

  1. 라벨보기를 스택보기에 추가하십시오 .

여기에 이미지 설명을 입력하십시오

  1. 스택 뷰를 선택하고 분포 를 같은 간격으로 설정하십시오 .

여기에 이미지 설명을 입력하십시오

  1. 스택 뷰 에 가장 가까운 인접 구속 조건에 간격을 추가 하고 프레임을 업데이트하십시오.

여기에 이미지 설명을 입력하십시오

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

여기에 이미지 설명을 입력하십시오

  1. 미리보기를 즐기십시오.

여기에 이미지 설명을 입력하십시오