[ios] Xcode 8 및 iOS10부터 viewDidLayoutSubviews에서보기 크기가 적절하지 않습니다.

Xcode 8을 사용 viewDidLoad하면 모든 viewcontroller 하위 뷰의 크기가 1000×1000 인 것 같습니다. 이상한 일이지만 괜찮 viewDidLoad습니다. 뷰의 크기를 올바르게 조정하는 데 더 좋은 곳은 아닙니다.

하지만 viewDidLayoutSubviews그렇습니다!

그리고 현재 프로젝트에서 버튼 크기를 인쇄하려고합니다.

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];

    NSLog(@"%@", self.myButton);
}

로그에는 myButton의 크기가 (1000×1000)으로 표시됩니다! 예를 들어 버튼 클릭에 로그온하면 로그에 정상적인 크기가 표시됩니다.

자동 레이아웃을 사용하고 있습니다.

버그입니까?



답변

이제 Interface Builder를 통해 사용자는 스토리 보드의 모든 뷰 컨트롤러 크기를 동적으로 변경하여 특정 장치의 크기를 시뮬레이션 할 수 있습니다.

이 기능을 사용하기 전에 사용자는 각 뷰 컨트롤러 크기를 수동으로 설정해야합니다. 따라서 뷰 컨트롤러는 initWithCoder초기 프레임을 설정하는 데 사용되는 특정 크기로 저장되었습니다 .

이제 initWithCoder스토리 보드에 정의 된 크기를 사용하지 않고 viewcontroller보기 및 모든 하위보기에 대해 1000×1000 px 크기를 정의하는 것 같습니다 .

뷰는 항상 다음 레이아웃 솔루션 중 하나를 사용해야하므로 이는 문제가되지 않습니다.

  • 자동 레이아웃 및 모든 제약 조건이 뷰를 올바르게 레이아웃합니다.

  • autoresizingMask, 어떤 제약도 연결되지 않은 각 뷰를 레이아웃합니다 ( autolayout 및 margin 제약 조건은 이제 동일한 뷰에서 호환됩니다 \ o /! ).

그러나 이것은 이다 보기 층, 등에 관련된 모든 레이아웃 물건에 대한 문제 cornerRadius도 있기 때문에, 자동 레이아웃자동 크기 마스크 레이어 속성에 적용됩니다.

이 문제에 답하기 위해 일반적인 방법은 viewDidLayoutSubviews컨트롤러에 있거나 layoutSubview뷰에있는 경우 사용하는 것입니다. 이 시점에서 ( super상대 메서드 를 호출하는 것을 잊지 마세요 ) 모든 레이아웃 작업이 완료되었음을 확신합니다!

예쁜 있는지? 흠 … 완전히는 아닙니다. 제가이 질문을 한 이유입니다. 어떤 경우에는 뷰가이 방법에서 여전히 1000×1000 크기를 가지고 있습니다. 내 질문에 대한 답이 없다고 생각합니다. 이에 대한 최대 정보를 제공하려면 다음을 수행하십시오.

1- 세포를 배치 할 때만 발생합니다! 에서 UITableViewCell& UICollectionViewCell서브 클래스가 layoutSubview호출되지 않습니다 파단이 제대로 밖으로 누워된다.

2- @EugenDimboiu가 언급했듯이 (유용한 경우 답변을 올려주세요) [myView layoutIfNeeded]레이아웃되지 않은 하위 뷰를 호출 하면 제 시간에 올바르게 레이아웃됩니다.

- (void)layoutSubviews {
    [super layoutSubviews];
    NSLog (self.myLabel); // 1000x1000 size 
    [self.myLabel layoutIfNeeded];
    NSLog (self.myLabel); // normal size
}

3- 제 생각에는 이것은 확실히 버그입니다. 레이더에 제출했습니다 (id 28562874).

추신 : 저는 영어 원어민이 아니므로 문법을 수정해야하는 경우 게시물을 자유롭게 편집 할 수 있습니다.)

PS2 : 더 나은 해결책이 있다면 다른 답을 쓰지 마십시오. 받아 들인 대답을 이동하겠습니다.


답변

버튼에 둥근 모서리를 사용하고 있습니까? layoutIfNeeded()전에 전화 해보세요 .


답변

해결 방법 : 내부 랩의 모든 것을 viewDidLayoutSubviews에서 DispatchQueue.main.async.

// swift 3

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    DispatchQueue.main.async {
        // do stuff here
    }
}


답변

이것이 정확한 질문이 아니라는 것을 알고 있지만 업데이트와 마찬가지로 viewDidLayoutSubviews에 올바른 프레임 크기가 있음에도 불구하고 일부 뷰가 엉망이 된 유사한 문제가 발생했습니다. iOS 10 릴리스 노트에 따르면 :

“view에 layoutIfNeeded를 보내는 것은 뷰를 이동시킬 것으로 예상되지 않지만, 이전 릴리스에서 뷰에 translatesAutoresizingMaskIntoConstraints가 NO로 설정되어 있고 제약 조건에 의해 배치 된 경우 layoutIfNeeded는 레이아웃을 보내기 전에 레이아웃 엔진과 일치하도록 뷰를 이동합니다. 이러한 변경 사항은이 동작을 수정하고 수신자의 위치와 일반적으로 해당 크기는 layoutIfNeeded의 영향을받지 않습니다.

일부 기존 코드는 현재 수정 된이 잘못된 동작에 의존 할 수 있습니다. iOS 10 이전에 연결된 바이너리에 대한 동작 변경은 없지만 iOS 10에서 빌드 할 때 -layoutIfNeeded를 이전 수신자였던 translatesAutoresizingMaskIntoConstraints 뷰의 수퍼 뷰에 전송하거나 이전에 위치를 지정하고 크기를 조정하여 일부 상황을 수정해야 할 수 있습니다 ( 또는 원하는 동작에 따라) layoutIfNeeded.

super를 호출하기 전에 자동 레이아웃을 재정의하는 자동 레이아웃을 사용하는 사용자 정의 UIView 하위 클래스가있는 타사 앱 및 super를 호출하기 전에 자체에 대한 더티 레이아웃은 iOS 10에서 다시 빌드 할 때 레이아웃 피드백 루프를 트리거 할 위험이 있습니다. 후속 layoutSubviews 호출을 올바르게 보내면 다음을 확인해야합니다. 어느 시점에서 자신의 레이아웃을 더럽히는 것을 중지합니다 (iOS 10 이전 릴리스에서는이 호출을 건너 뛰었습니다). “

기본적으로 translatesAutoresizingMaskIntoConstraints를 사용하는 경우 View의 자식 개체에서 layoutIfNeeded를 호출 할 수 없습니다. 이제 layoutIfNeeded를 호출하는 것이 superView에 있어야하며 viewDidLayoutSubviews에서 계속 호출 할 수 있습니다.


답변

프레임이 layoutSubViews에서 정확하지 않은 경우 (아닙니다) 메인 스레드에서 약간의 코드를 비동기로 전달할 수 있습니다. 이것은 시스템이 레이아웃을 할 시간을줍니다. 전달한 블록이 실행되면 프레임의 크기가 적절합니다.


답변

이것은 나를 위해 (어리석게 성가신) 문제를 해결했습니다.

- (void) viewDidLayoutSubviews {

    [super viewDidLayoutSubviews];

    self.view.frame = CGRectMake(0,0,[[UIScreen mainScreen] bounds].size.width,[[UIScreen mainScreen] bounds].size.height);

}

편집 / 참고 : 이것은 전체 화면 ViewController를위한 것입니다.


답변

사실 viewDidLayoutSubviews또한 시야의 틀을 설정하기에 가장 좋은 장소는 아닙니다. 내가 이해하는 한, 지금부터 수행해야 할 유일한 곳 layoutSubviews은 실제 뷰 코드의 메서드입니다. 내가 옳지 않았 으면 좋겠어, 사실이 아니라면 누군가 나를 바로 잡아 줘!