[ios] 자동 레이아웃을 사용하여 UIScrollview에서 제약 조건을 설정하려면 어떻게해야합니까?

나는 자동 레이아웃 전에 사소한 스크롤보기 설정을 달성하기 위해 혼합 및 순수 자동 레이아웃 접근법 에 대한 다양한 솔루션을 시험하는 데 이틀을 보냈으며 현재 공식적입니다. 너무 어리석어 야합니다. 나는 이것을 스토리 보드에서 주로 설정하고 있습니다 (잘, 그것은 그대로입니다).

도움을 청합니다.

뷰 트리 :

UIView
-UIView
-UIView
..-UIScrollview
...-UIButton
...-UIButton
...-UIButton

버튼은 가로로 스크롤해야합니다 (왼쪽에서 오른쪽으로 또는 그 반대로). 사람이 할 수 주십시오 나를 사용하여이 순수한 자동 레이아웃을 달성하기 위해 제약 조건을 설정하는 방법을 알려 ???

나는 혼합 접근법을 다음과 같이 시도했다.

UIView
- UIView
- UIView
..-UIScrollview
...-UIView (contentview)
....-UIButton
....-UIButton
....-UIButton

… 설정 고정 너비와 높이와에 대한 제약 contentviewtranslatesAutoresizingMaskIntoConstraints애플의 기술 문서에 따라 설정. 버튼과 스크롤보기는 제약 조건을 사용하여 설정됩니다. 이것은 스크롤 뷰 스크롤 (yay)을 얻지 만 아아, 너무 멀리 스크롤됩니다! 내가 알 수있는 한, 스크롤 너비는 내가 contentview를 설정 한 것보다 두 배가됩니까 ??? !!! ???

contentview유무에 관계없이 순수한 자동 레이아웃 접근법을 시도했습니다 . translatesAutoresizingMaskIntoConstraints=NO 제외한 모든 보기는 입니다 self.view. 버튼의 너비 / 높이 제한은 고정되어 있으며 스크롤보기의 네 가장자리에 모두 고정되어 있습니다. 스크롤이 없습니다.

그래서 나는 그것이 올바르게 작동하지 않는 이유에 대해 완전히 당황했습니다. 도움이 필요하면 다른 정보가 필요하면 문의하십시오!

솔루션이있는 스크린 샷
-buttonZ 제약 조건 :

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

@ Jamie Forrest 편집
그래서 솔루션은 마지막 버튼의 잘못된 후행 제약 조건으로 판명되었습니다. 6441 대신 내가 설정 한 값은 -6441입니다. 까다로운 점은 스토리 보드에서 값을 설정할 때 핀 도구 모음에 두 가지 옵션이 있다는 것입니다.

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

현재 캔버스 값은 음수이고 (스크롤이 없음) 아래 옵션은 양수입니다 (스크롤 활성화 중). 이것은 내가 바보가 아니지만 적어도 반맹 인 것 같아요. 내 방어를 위해 XCode가 “잘못된”설정에 대한 오류를 표시하지 않는 것이 다소 혼란스럽지 않습니까?

다시 편집
이제 재미있다 … 후행 값을 -6441 (스크롤 없음)에서 6441 사용 스크롤로 변경. 그러나 나의 오랜 친구 인 “너무 많은 contentsize”가 돌아 왔으며, 콘텐츠 크기가 두 배로 커졌습니다! 올바른 컨텐츠 스크롤을 얻는 솔루션은 후행 제한 조건을 ZERO! 스토리 보드에서 작업 할 때 분명하지 않지만 @Infinity James ‘코드를 보면 이것이 있어야합니다.



답변

여기에 붙여 넣었을 때 구속 조건의 정확한 값과 설정을 확인하기가 어렵 기 때문에 잘못된 위치의 스크린 샷을 볼 수는 없습니다.

설정에서 무엇이 잘못되었는지에 대한 설명 대신, 설명하는 것과 매우 유사한 뷰 계층 구조 및 제약 조건 설정을 사용하여 기본 샘플 프로젝트 를 만들었습니다 . 가로 스크롤은 샘플 프로젝트에서 예상 한대로 작동하며, Apple은 기술 노트 에서 설명하는 “Pure AutoLayout”접근 방식을 사용합니다 .

또한 원래 자동 레이아웃 작업을 수행하는 데 많은 문제가있었습니다 UIScrollView. 그것이 작동하게하는 열쇠는 스크롤보기의 모든 항목이 함께 스크롤 목록의 모든면에 연결되어 AutoLayout 시스템이 contentSize를 결정할 수있는 제약 조건을 갖도록하는 것입니다 프레임보다 큰 스크롤보기. 코드에서 그렇게하려고하는 것처럼 보이지만 contentSize를 너무 작게 만드는 불필요한 제약이있을 수 있습니다.

또한 다른 사람들이 언급했듯이 AutoLayout 및 UIScrollview를 사용하면 더 이상 contentSize를 명시 적으로 설정하지 않습니다. 자동 레이아웃 시스템은 제약 조건에 따라 contentSize를 계산합니다.

또한 이 eBook 장이이 모든 것이 어떻게 작동하는지 이해하는 데 매우 도움 된다는 것을 알았습니다 . 이 모든 것이 도움이되기를 바랍니다.


답변

LOL은 바보 클럽에 오신 것을 환영합니다. 저는 창립자 중 한 사람입니다. :디

수직 스크롤의 경우 : 작동시킬 수있는 유일한 방법 (iOS 8, Xcode 6 및 순수 자동 레이아웃)은 스크롤보기에 다음 제약 조건을 추가하는 것입니다 (모두 수퍼 뷰와 관련됨).

  • 동일한 폭
  • 동등한 높이
  • 중심 Y 정렬
  • 중심 X 정렬

내 구조 :

  UIView
   - ScrollView
    - Subview
    - Subview
    - Subview
    - Subview
    - ...

이것이 최종 결과입니다.

데모

이것은 설정입니다 :

설정
전체 화면

그리고 여기 프로젝트가 있습니다.

희망적으로 이것은 누군가가 오전 5시에 잠들지 못하게 할 것입니다. :디


답변

간단한 자체 포함 된 예

질문에 대한 많은 표와 답변에 대한 많은 표로 판단하면 사람들은 여기서 이해할 수 있고 빠른 해결책을 찾지 못합니다. 하나 추가해 보겠습니다. 이 프로젝트는 Interface Builder에서 완전히 수행 된 독립적 인 예제입니다. 10 분 이내에 작업을 수행 할 수 있어야합니다. 그런 다음 배운 개념을 자신의 프로젝트에 적용 할 수 있습니다.

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

원래 질문은 스크롤 버튼에 대해 묻습니다. 여기서는 UIViews를 사용 하지만 원하는 뷰를 나타낼 수 있습니다. 스토리 보드 스크린 샷이이 형식에 비해 더 작기 때문에 가로 스크롤도 선택했습니다. 그러나 세로 스크롤의 원리는 동일합니다.

주요 컨셉

  • UIScrollView하나 개의 서브 뷰를 사용해야합니다. 스크롤하려는 모든 내용을 담을 수있는 컨텐츠보기 역할을하는 ‘UIView’입니다.
  • 내용보기와 스크롤보기의 부모 가 가로 스크롤의 높이를 동일하게 설정하십시오. (세로 스크롤의 경우 동일한 너비)
  • 스크롤 가능한 모든 컨텐츠의 너비가 설정되어 있고 모든면에 고정되어 있는지 확인하십시오.

새로운 프로젝트를 시작하십시오

단일 뷰 응용 프로그램 일 수 있습니다.

스토리 보드

이 예에서는 가로 스크롤보기를 만듭니다. View Controller를 선택한 다음 Size Inspector에서 Freeform을 선택하십시오. 너비 1,000와 높이를 확인하십시오 300. 이것은 스토리 보드에 스크롤 할 컨텐츠를 추가 할 공간을 제공합니다.

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

스크롤보기 추가

UIScrollView뷰 컨트롤러의 루트 뷰에 4면을 모두 추가 하고 고정합니다.

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

컨텐츠 뷰 추가

UIView스크롤보기에 하위보기로 추가하십시오 . 이것이 핵심입니다. 스크롤 뷰에 많은 하위 뷰를 추가하지 마십시오. 하나만 추가하면 UIView됩니다. 스크롤하려는 다른보기에 대한 컨텐츠보기가됩니다. 컨텐츠보기를 네면 모두의 스크롤보기에 고정하십시오.

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

동등한 높이

이제 문서 개요 Command에서 내용보기와 스크롤보기의 부모보기 를 모두 클릭 하여 모두 선택하십시오. 그런 다음 높이를 동일하게 설정하십시오 ( Control컨텐츠 뷰에서 스크롤 뷰로 드래그). 이것은 또한 핵심입니다. 가로로 스크롤하기 때문에 스크롤보기의 내용보기는 이러한 방식으로 설정하지 않으면 얼마나 높은지 알 수 없습니다.

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

노트 :

  • 콘텐츠를 세로로 스크롤하는 경우 콘텐츠보기의 너비를 스크롤보기의 부모 너비와 동일하게 설정합니다.

내용 추가

세 개를 UIView더하고 모든 제약 조건을 부여 하십시오 . 나는 모든 것에 8 포인트 마진을 사용했습니다.

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

제약 사항 :

  • 녹색보기 : 위쪽, 왼쪽 및 아래쪽 가장자리를 고정하십시오. 너비를 400으로 만듭니다.
  • 빨간색보기 : 위쪽, 왼쪽 및 아래쪽 가장자리를 고정합니다. 너비를 300으로 만듭니다.
  • 자주색보기 : 네 모서리 가장자리를 모두 고정합니다. 남은 공간 (이 경우 268)의 너비를 지정하십시오.

스크롤 뷰가 컨텐츠 뷰의 너비를 알 수 있도록 너비 제한을 설정하는 것도 중요 합니다.

끝마친

그게 다야. 지금 프로젝트를 실행할 수 있습니다. 이 답변 상단의 스크롤 이미지와 같이 작동해야합니다.

수직 스크롤의 경우,이 예제에서 모든 너비와 높이 방향을 바꾸십시오 (테스트 및 작동).

추가 연구


답변

contentSize는 UIScrollView 내부에 제약 조건을 적용하여 암시 적으로 설정됩니다.

예를 들어 UIView 내부에 UIScrollView가 있습니까? 확실히 알 수 있습니다.

    UIView *containerView               = [[UIView alloc] init];
    UIScrollView *scrollView            = [[UIScrollView alloc] init];
    [containerView addSubview:scrollView];
    containerView.translatesAutoresizingMaskIntoConstraints = NO;
    scrollView.translatesAutoresizingMaskIntoConstraints    = NO;
    NSDictionary *viewsDictionary       = NSDictionaryOfVariableBindings(containerView, scrollView);

    [containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[scrollView]|"
                                                                          options:kNilOptions
                                                                          metrics:nil
                                                                            views:viewsDictionary]];
    [containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scrollView]|"
                                                                          options:kNilOptions
                                                                          metrics:nil

그러면 scrollView가 containerView의 크기를 채우도록 설정됩니다 (containerView는 특정 크기 여야합니다).

그런 다음 UIScrollView의 contentSize를 다음과 같이 버튼을 보유 할 수있을 정도로 크게 설정하여 UIScrollView의 contentSize를 조정할 수 있습니다.

    UIButton *buttonA                   = [[UIButton alloc] init];
    UIButton *buttonB                   = [[UIButton alloc] init];
    UIButton *buttonC                   = [[UIButton alloc] init];
    [scrollView addSubview:buttonA];
    [scrollView addSubview:buttonB];
    [scrollView addSubview:buttonC];
    buttonA.translatesAutoresizingMaskIntoConstraints       = NO;
    buttonB.translatesAutoresizingMaskIntoConstraints       = NO;
    buttonC.translatesAutoresizingMaskIntoConstraints       = NO;

    viewsDictionary                     = NSDictionaryOfVariableBindings(scrollView, buttonA, buttonB, buttonC);

    [scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[buttonA]-|"
                                                                       options:kNilOptions
                                                                       metrics:nil
                                                                         views:viewsDictionary]];
    [scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[buttonA]-[buttonB]-[buttonC]-|"
                                                                       options:NSLayoutFormatAlignAllBaseline
                                                                       metrics:nil
                                                                         views:viewsDictionary]];


답변

UIScrollView와 함께 AutoLayout을 사용하는 것에 대해 너무 많은 질문이 있습니다. 우리가 무시할 핵심은 UIScrollView의 내부 뷰가 콘텐츠 뷰 에 대해 제약을 가하지 만 UIScrollView 자체 는 제한 하지 않는다는 것입니다. 기술 노트 TN2154를 참조하십시오 .

UIScrollView 클래스는 경계의 원점을 변경하여 내용을 스크롤합니다. 자동 레이아웃에서이 작업을 수행하려면 스크롤보기의 위쪽, 왼쪽, 아래쪽 및 오른쪽 가장자리가 컨텐츠보기의 가장자리를 의미합니다.

다음 그림은이를 보여줍니다.
여기에 이미지 설명을 입력하십시오

후미 공간이 500 포인트임을 알 수 있습니다. UIScrollView를 제한하면 뷰가 누락되고 프레임을 업데이트해야합니다. 그러나 경고 나 오류는 없습니다. 모든 구속 조건이 컨텐츠보기에 대한 것이기 때문입니다.

UIScrollView는 내부 뷰의 제약 조건에 따라 콘텐츠 뷰의 크기를 계산합니다. (예를 들어, 컨텐츠 크기 : 너비 = 100 (리딩 스페이스) + 200 (뷰의 너비) + 500 (트레일 스페이스), 높이 = 131 (맨 위 간격) + 200 (높이) + 269 (맨 아래 간격)

UIScrollView에서 뷰에 대한 제약 조건을 추가하는 방법 :

  1. 컨텐츠 뷰에서 뷰의 위치를 ​​이미징합니다.
  2. 컨텐츠 뷰의 가장자리에 상단, 오른쪽, 하단, 왼쪽 간격을 추가하고 이러한 뷰의 너비와 높이를 추가하십시오.

그리고 모든 것이 끝났습니다.

스크롤보기로 AutoLayout을 처리하는 쉬운 방법은 스크롤보기에서 모든 하위보기를 포함하는 컨테이너보기를 추가하는 것입니다.

결론 : UIScrollView를 사용하여 AutoLayout을 이해하는 요점은 내부 뷰가 컨텐츠 뷰에 ​​대해서는 제한을 두지 만 UIScrollView 자체는 제한하지 않는다는 것입니다.

첨부 된 예제 코드


답변

다음 솔루션은 자동 레이아웃이 있고 contentSize가없는 scrollView에 효과적 이었습니다 .

  1. n scrollView를 끌어서 viewController로 이동하고 원하는 공간을 덮기 위해 모든 제약 조건을 적용하십시오.
  2. scrollView 내부 에 UIView를 끌어다 놓고 scrollView의 전체 공간을 덮고 scrollView의 상단, 왼쪽, 오른쪽, 하단 공간에 제약 조건을 적용하십시오 .
  3. 스크롤 필요에 따라 내부보기 의 높이 (및 가로 스크롤이 필요한 경우 너비)를 설정하십시오 . 필요한 경우 코드에서이 부분을 수행 할 수도 있습니다.
  4. 중요 합니다. 포인트 (3)에서 높이를 약간 큰 값으로 설정 한 후 포인트 (2)로 돌아가서 Xcode가 강제로 변경할 때 Xcode가 변경했을 수 있으므로 상단, 왼쪽, 오른쪽, 하단 값 을 0 으로 다시 설정해야합니다. 높이를 (3)으로 변경했습니다.

그리고 당신은 끝났습니다. 이제이 뷰에 원하는 수의 컨트롤을 추가하고 서로 관련된 제약 조건을 적용 할 수 있습니다 (이 뷰 없이는 작동하지 않는 것 같습니다). 이 뷰를 사용하지 않으려면 scrollView와 관련된 각 컨트롤에 대해 제약 조건을 적용해야합니다 (서로 관련되지 않음).


압도적 인 팁 ………..

중요 합니다. 명확성을 위해 UIScrollView의 너비1000이고 높이는 100입니다. (실제로 이러한 값은 물론 장치의 너비 등에 따라 동적입니다. 그러나 지금은 너비가 1000이고 높이가 100이라고 말합니다.) 가로 스크롤을 수행한다고 가정 해 봅시다. UIScrollView 안에 UIView를 넣습니다. ( “컨텐츠 뷰”입니다.) 컨텐츠 뷰의 상하 좌우 선행 4 개를 모두 스크롤 뷰로 설정하십시오. 잘못된 것 같더라도 모두 0으로 만듭니다. 콘텐츠 UIView의 높이를 100으로 설정하고 잊어 버리십시오. 이제 가로로 스크롤하기를 원하므로 콘텐츠 뷰의 너비를 1225로 설정하십시오.

컨텐츠보기의 너비는 이제 상위 스크롤보기의 너비보다 225 더 큽니다. 괜찮습니다. 사실, 당신은 그렇게해야합니다. 참고

… 후행 너비를 음수 225로 설정 하지 마십시오

평소처럼 너비를 “일치시켜야”한다고 생각할 입니다. 그러나 그렇게하면 전혀 작동하지 않습니다.

선행 및 후행 숫자를 ZERO로 설정해야합니다 (너비가 “더 큰”임에도 불구하고 음수는 아님).

흥미롭게도 실제로 선행 / 트레일 숫자를 양수 값 ( “50”)으로 설정할 수 있으며 바운스의 여백을 제공합니다. (종종 멋지게 보입니다. 시도해보십시오.) 양쪽 끝에있는 음수 값은 “자동으로 끊어집니다”.

화나게도 종종 Xcode (7.3.1 현재),

이 값을 ‘유용하게’음수로 설정합니다!

자동으로 집계하려고하기 때문입니다. 그렇다면 자동으로 중단됩니다. 첫 번째 인스턴스에서 네 개의 값을 모두 0으로 설정하십시오. 예제에서 컨텐츠 뷰의 너비를 “1000”보다 훨씬 넓게 설정하십시오.


편집 :
필자는 대부분의 요구 사항에 대해 UIScrollView 대신 UITableView를 사용했습니다. tableView가 훨씬 유연하고 역동적 인 것처럼 보입니다.


답변

에 문제가 있다고 가정합니다 contentSize. “순수한”자동 레이아웃 접근 방식을 사용할 때 처리 방법에 대한 이 블로그 게시물 을 확인하십시오 contentSize. 요점은 제약 조건이 암시 적으로 내용 크기를 정의한다는 것입니다. 자동 레이아웃을 사용할 때 명시 적으로 설정하지 마십시오. 블로그 게시물 끝에 예제 프로젝트를 첨부하여 작동 방식을 보여줍니다.