[Ios] 숨겨진 UIView가있는 AutoLayout?


Answers

숨겨진 상태로 상수 0 을 사용하는 방법과 다시 표시하면 상수를 사용하는 방법은 기능적이지만 콘텐츠의 크기가 유연하지 않으면 만족스럽지 않습니다. 유연한 콘텐츠를 측정하고 상수를 다시 설정해야합니다. 서버 또는 UI 이벤트로 인해 콘텐츠의 크기가 변경되면 문제가 발생합니다.

나는 더 나은 해결책을 가지고있다.

아이디어는 우리가 요소를 숨길 때 autolayout 공간을 차지하지 않도록 0 ​​높이 규칙을 높은 우선 순위로 설정하는 것입니다.

방법은 다음과 같습니다.

1. 인터페이스 빌더에서 0의 너비 (또는 높이)를 낮은 우선 순위로 설정하십시오.

인터페이스 빌더는 우선 순위가 낮기 때문에 충돌에 대해 큰소리하지 않습니다. 우선 순위를 999로 일시적으로 설정하여 높이 동작을 테스트하십시오 (1000은 프로그래밍 방식으로 변경 될 수 없으므로 사용하지 않을 것입니다). 인터페이스 빌더는 아마도 충돌하는 제약 조건에 대해 큰소리를 낼 것입니다. 관련 객체의 우선 순위를 900 정도로 설정하여 문제를 해결할 수 있습니다.

2. 코드에서 너비 제약 조건의 우선 순위를 수정할 수 있도록 콘센트를 추가하십시오.

3. 요소를 숨길 때 우선 순위를 조정하십시오.

cell.alertTimingView.hidden    = place.closingSoon != true
cell.alertTimingWidth.priority = place.closingSoon == true ? 250 : 999
Question

비즈니스 로직에 따라 UIViews , 가장 자주 UILabels 를 표시하거나 숨기는 것이 매우 일반적인 패러다임 인 것 같습니다. 내 질문은, AutoLayout을 사용하여 프레임이 0x0 인 것처럼 숨겨진보기에 응답하는 가장 좋은 방법은 무엇입니까? 다음은 1-3 기능의 동적 목록의 예입니다.

지금은 버튼에서 마지막 라벨까지 10px의 상단 공간이 있는데, 레이블이 숨겨져있을 때 분명히 위로 올라가지 않습니다. 현재로서는이 제약 조건의 콘센트를 만들고 표시 할 레이블의 수에 따라 상수를 수정합니다. 음수의 상수 값을 사용하여 숨겨진 프레임 위로 버튼을 밀었 기 때문에 이것은 분명히 조금 해킹되었습니다. 실제 레이아웃 요소에 제약이 없으며, 다른 요소의 알려진 높이 / 패딩을 기반으로하는 비열한 정적 계산뿐 아니라 AutoLayout이 구축 된 것과 분명히 싸우므로 나쁜 것입니다.

필자는 동적 라벨에 따라 새로운 제약 조건을 만들 수는 있지만 마이크로 스케일링과 많은 공백을 없애기위한 많은 자세한 정보가 필요합니다. 더 나은 접근법이 있습니까? 프레임 크기를 0,0으로 변경하고 AutoLayout이 제약 조건을 수정하지 않고 그 일을 처리하게하려면 어떻게해야합니까? 보기를 완전히 삭제 하시겠습니까?

솔직히, 숨겨진보기의 컨텍스트에서 상수를 수정하는 것은 간단한 계산으로 한 줄의 코드 만 필요합니다. constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant: 새 제약 조건을 constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant: 것은 너무 무거워 보입니다.

2018 년 2 월 수정 : UIStackView Ben의 대답보기




이 경우 작성자 레이블의 높이를 적절한 IBOutlet에 매핑합니다.

@property (retain, nonatomic) IBOutlet NSLayoutConstraint* authorLabelHeight;

제약 조건의 높이를 0.0f로 설정하면 재생 버튼의 높이가 허용하기 때문에 "패딩"을 유지합니다.

cell.authorLabelHeight.constant = 0; //Hide 
cell.authorLabelHeight.constant = 44; //Show




여기에 많은 솔루션이 있지만 내 일반적인 접근 방식은 다시 다릅니다 :)

호르헤 아리마니 (Jorge Arimany)와 TMin의 대답과 비슷한 두 세트의 제약 조건을 설정하십시오.

세 개의 표시된 구속 조건 모두 Constant에 대해 동일한 값을가집니다. A1과 A2로 표시된 제약 조건은 Priority가 500으로 설정되어 있고 B로 표시된 제약 조건에는 250으로 설정된 Priority가 있습니다 (또는 코드에서 UILayoutProperty.defaultLow ).

제약 B를 IBOutlet에 연결합니다. 그런 다음 요소를 숨길 때 우선 순위 우선 순위를 높음 (750)으로 설정하면됩니다.

constraintB.priority = .defaultHigh

그러나 요소가 표시되면 우선 순위를 다시 낮게 (250) 설정하십시오.

constraintB.priority = .defaultLow

제약 B에 대해 isActive 를 변경하는 것 isActive 접근법에 대한 (아주 작은) 장점은 일시적인 요소가 다른 방법으로 뷰에서 제거되면 여전히 작동 제약이 있다는 것입니다.




내가 선호하는 방법은 Jorge Arimany가 제안한 방법과 매우 유사합니다.

여러 제약 조건을 만드는 것을 선호합니다. 먼저 두 번째 레이블이 표시 될 때까지 제약 조건을 만듭니다. 버튼과 두 번째 레이블 사이의 구속 조건에 대한 콘센트를 만듭니다 (objc를 사용하는 경우 강력 함을 확인하십시오). 이 제약 조건은 단추와 두 번째 레이블이 표시 될 때 높이 사이의 높이를 결정합니다.

그런 다음 두 번째 단추가 숨겨져있을 때 단추와 맨 위 레이블 간의 높이를 지정하는 다른 제한 조건을 작성하십시오. 두 번째 구속 조건의 콘센트를 만들고이 콘센트에 강한 포인터가 있는지 확인하십시오. 그런 다음 인터페이스 빌더에 installed 확인란의 선택을 취소하고 첫 번째 제약 조건의 우선 순위가이 두 번째 제약 조건 우선 순위보다 낮은 지 확인하십시오.

마지막으로 두 번째 레이블을 숨기면이 제약 조건의 .isActive 속성을 토글하고 setNeedsDisplay() 호출합니다.

그리고 그것입니다, 매직 넘버, 수학, 당신이 켜고 끄기 위해 여러 가지 제약 조건을 가지고 있다면 콘센트 컬렉션을 사용하여 상태별로 정리할 수 있습니다. (AKA는 하나의 OutletCollection에 모든 숨겨진 제약 조건을 유지하고 다른 개체에는 숨겨진 제약 조건을 숨기고 각각의 컬렉션을 반복하여 .isActive 상태를 전환합니다).

Ryan Romanchuk은 다중 제약 조건을 사용하고 싶지 않지만 micromanage-y가 아닌 것처럼 느껴졌습니다. 프로그래밍 방식으로 뷰와 제약 조건을 동적으로 생성하는 것이 더 간단합니다. (필자는 그가 오른쪽 질문을 읽고).

간단한 예제를 만들었습니다. 유용하게 사용되기를 바랍니다 ...

import UIKit

class ViewController: UIViewController {

    @IBOutlet var ToBeHiddenLabel: UILabel!


    @IBOutlet var hiddenConstraint: NSLayoutConstraint!
    @IBOutlet var notHiddenConstraint: NSLayoutConstraint!


    @IBAction func HideMiddleButton(_ sender: Any) {

        ToBeHiddenLabel.isHidden = !ToBeHiddenLabel.isHidden
        notHiddenConstraint.isActive = !notHiddenConstraint.isActive
        hiddenConstraint.isActive = !hiddenConstraint.isActive

        self.view.setNeedsDisplay()
    }
}




나는이 바람직한 동작을 위해 UIKit 이 제공하는보다 우아한 접근 방식이 없다는 것에 놀랐다. 할 수 있기를 원하는 것은 매우 보편적 인 것처럼 보입니다.

IBOutlets 제약 조건을 연결하고 그 상수를 0 설정하면 뷰에 하위 뷰가있을 때 NSLayoutConstraint 경고가 발생 하므로 자동 레이아웃 제약이있는 UIView 를 숨기거나 표시하는 간단하고 안정적인 방법을 제공하는 확장 프로그램을 작성하기로 결정했습니다.

뷰를 숨기고 외부 구속 조건을 제거하기 만하면됩니다. 뷰를 다시 표시하면 제약 조건이 다시 추가됩니다. 유일한주의 사항은 주변보기에 유연한 장애 조치 제약 조건을 지정해야한다는 것입니다.

편집 이 답변은 iOS 8.4 이하를 대상으로합니다. iOS 9에서는 UIStackView 방식을 사용하십시오.




나는 방금 UILabel이 공간을 차지하지 못하도록 숨기고 텍스트를 빈 문자열로 설정해야한다는 것을 알았습니다. (iOS 9)

이 사실 / 버그를 아는 것은 일부 사람들이 레이아웃을 단순화하는 데 도움이 될 수 있습니다. 원래 질문의 레이아웃을 단순화 할 수도 있으므로 게시 할 것입니다.