[ios] 자동 레이아웃 제약 조건을 사용할 때 뷰의 현재 너비와 높이를 어떻게 얻을 수 있습니까?

나는 프레임 속성에 대해 말하는 것이 아닙니다. 그로부터 당신은 xib에서 뷰의 크기를 얻을 수 있기 때문입니다. 제약 조건 (회전 후 또는 이벤트에 대한 응답으로)으로 인해 뷰의 크기가 조정되는시기에 대해 이야기하고 있습니다. 현재 너비와 높이를 얻는 방법이 있습니까?

너비 및 높이 제약 조건을 찾기 위해 제약 조건을 반복하려고 시도했지만 내부 제약 조건이있을 때 매우 깨끗하지 않고 실패합니다 (둘을 구분할 수 없기 때문에). 또한 실제로 너비 및 높이 제한이있는 경우에만 작동하며 크기를 조정하기 위해 다른 제한에 의존하는 경우에는 작동하지 않습니다.

이게 왜 그렇게 어려운가요? ARG!



답변

대답은 [view layoutIfNeeded]입니다.

그 이유는 다음과 같습니다.

view.bounds.size.widthview.bounds.size.height(또는을 사용하지 않는 한 동일한 프레임)을 검사하여 뷰의 현재 너비와 높이를 여전히 얻습니다 view.transform.

원하는 것이 기존 제약 조건에 내포 된 너비와 높이 인 경우, 제약 조건을 수동으로 검사하지 않는 것이 정답입니다. 자동 레이아웃 시스템의 전체 제약 해결 논리를 다시 구현해야 해석 할 수 있기 때문입니다. 제약. 대신해야 할 일은 자동 레이아웃에 해당 레이아웃을 업데이트하도록 요청 하여 제약 조건을 해결하고 올바른 솔루션으로 view.bounds 값을 업데이트 한 다음 view.bounds를 검사하는 것입니다.

레이아웃 업데이트를 위해 자동 레이아웃을 어떻게 요청합니까? [view setNeedsLayout]자동 레이아웃이 런 루프의 다음 턴에 레이아웃을 업데이트하도록하려면 호출 하십시오.

그러나 레이아웃을 즉시 업데이트하여 나중에 현재 함수 내에서 또는 실행 루프가 시작되기 전 다른 지점에서 새 경계 값에 즉시 액세스 할 수 있도록하려면[view setNeedsLayout] 및 을 호출해야합니다 [view layoutIfNeeded].

두 번째 질문 : “직접 참조가없는 경우 높이 / 너비 제약 조건을 어떻게 변경할 수 있습니까?”

IB에서 제약 조건을 생성하는 경우 최상의 솔루션은 뷰 컨트롤러 또는 뷰에 IBOutlet을 생성하여 직접 참조 할 수 있도록하는 것입니다. 코드에서 제약 조건을 만든 경우에는 만들 때 내부 약한 속성의 참조를 유지해야합니다. 다른 사람이 제약 조건을 생성 한 경우 뷰의 view.constraints 속성과 전체 뷰 계층 구조를 검사하고 중요한 NSLayoutConstraint를 찾는 논리를 구현하여이를 찾아야합니다. 이 질문에 대한 간단한 대답이 보장되지 않을 때 경계 크기를 결정한 특정 제약 조건을 효과적으로 결정해야하기 때문에 잘못된 방법 일 수 있습니다. 최종 경계 값은 여러 제약 조건의 매우 복잡한 시스템에 대한 솔루션이 될 수 있습니다.


답변

나는이에 상단과 하단 테두리를 추가 할 필요 비슷한 문제를 가지고 UITableView그에서의 제약 조건 설정에 따라 크기를 조절 UIStoryboard. 을 사용하여 업데이트 된 제약 조건에 액세스 할 수있었습니다 - (void)viewDidLayoutSubviews. 이것은 뷰를 서브 클래 싱하고 레이아웃 메서드를 재정의 할 필요가 없도록 유용합니다.

/*** SET TOP AND BOTTOM BORDERS ON TABLE VIEW ***/
- (void)addBorders
{
    CALayer *topBorder           = [CALayer layer];
    topBorder.frame              = CGRectMake(0.0f, self.tableView.frame.origin.y, 320.0f, 0.5f);
    topBorder.backgroundColor    = [UIColor redColor].CGColor;

    CALayer *bottomBorder        = [CALayer layer];
    bottomBorder.frame           = CGRectMake(0.0f, (self.tableView.frame.origin.y + self.tableView.frame.size.height), 320.0f, 0.5f);
    bottomBorder.backgroundColor = [UIColor redColor].CGColor;

    [self.view.layer addSublayer:topBorder];
    [self.view.layer addSublayer:bottomBorder];
}

/*** GET AUTORESIZED FRAME DIMENSIONS ***/
- (void)viewDidLayoutSubviews{
    [self addBorders];
}

메서드에서 메서드를 호출하지 않으면 viewDidLayoutSubview아래쪽 테두리가 화면 밖의 어딘가에 있으므로 위쪽 테두리 만 올바르게 그려집니다.


답변

특히 TableviewCell을 사용하여 여전히 이러한 문제에 직면 할 수있는 사람들을 위해.

메소드를 재정의하십시오.

-(void)layoutSubviews
{
//your code here like drawing a shadow
}

UITableViewCell 또는 UICollectionViewCell의 경우 셀의 하위 클래스를 만들고 동일한 메서드를 재정의합니다.

-(void)layoutSubviews
{
//your code here like drawing a shadow
}


답변

사용 -(void)viewWillAppear:(BOOL)animated및 전화 [self.view layoutIfNeeded];-내가 시도한 작동합니다.

사용 -(void)viewDidLayoutSubviews하면 확실히 작동하지만 UI가 업데이트 / 변경을 요구할 때마다이 메서드가 호출 되기 때문 입니다. 관리하기 어려울 것입니다. 소프트 키는 이러한 호출 루프를 피하기 위해 bool 변수를 사용하는 것입니다. 더 나은 사용 viewWillAppear. 기억 viewWillAppear뷰가 다시로드 된 경우 또한 (재 할당없이) 호출됩니다.


답변

프레임은 여전히 ​​유효합니다. 결국 뷰는 프레임 속성을 사용하여 자신을 배치합니다. 모든 제약 조건을 기반으로 해당 프레임을 계산합니다. 제약 조건은 초기 레이아웃에만 사용됩니다 (그리고 회전 후와 같이 view에서 layoutSubviews가 호출 될 때마다). 그 후 위치 정보는 프레임 속성에 있습니다. 아니면 다르게보고 있습니까?


답변