developer tip

iOS 11 안전 영역 레이아웃 가이드 하위 호환성

copycodes 2020. 12. 3. 08:04
반응형

iOS 11 안전 영역 레이아웃 가이드 하위 호환성


안전 영역 레이아웃 가이드가 11 미만의 iOS와 호환됩니까?

여기에 이미지 설명 입력


새로운 안전 영역 레이아웃 가이드로 작업하고 iOS 9 및 iOS 10과의 하위 호환성을 유지했습니다. (편집 : @NickEntin의 주석에서 지적했듯이이 구현은 상태 표시 줄이 존재한다고 가정합니다. iPhone X의 가로 모드에서는 사실입니다. 결과적으로 상단에 많은 공간 (20 포인트)이 생겼지 만 완벽하게 작동합니다.

예를 들어보기를 상태 표시 줄 아래 10 포인트 (iPhone X의 센서 하우징 아래 10 포인트)로 설정하려는 경우 :

  1. XIB에서 File Inspector를 확인하여 금고 로 이동하여 활성화하십시오 Use Safe Area Layout Guides.
  2. >=(크거나 같음) 제약 조건, 상수 30(20 점 높이 인 상태 표시 줄에 10 점 간격을두기를 원하기 때문에 30) 및 우선 순위 High(750) 를 사용하여 뷰의 상단에서 기본 뷰의 상단까지 제약 조건을 만듭니다 .
  3. =(동일) 제약, 상수 10및 우선 순위 Low(250) 를 사용하여 뷰의 상단에서 안전 영역의 상단까지 제약 조건을 만듭니다 .

하단의보기 (및 안전 영역의 앞 / 뒤 또는 왼쪽 / 오른쪽)에 대해서도 동일하게 수행 할 수 있습니다.

  1. XIB에서 File Inspector를 확인하여 금고 로 이동하여 활성화하십시오 Use Safe Area Layout Guides.
  2. >=(크거나 같음) 제약, 상수 10및 우선 순위 High(750) 를 사용하여 뷰의 맨 아래에서 기본 뷰의 맨 아래까지 제약 조건을 만듭니다 .
  3. =(동일) 제약, 상수 10및 우선 순위 Low(250) 를 사용하여 뷰의 하단에서 안전 영역의 하단까지 제약 조건을 만듭니다 .

iOS 9 및 iOS 10 용 안전 영역의 하위 호환성은 스토리 보드를 사용하는 경우에만 작동합니다. xibs를 사용하는 경우 대체 할 레이아웃 가이드가 없습니다. https://forums.developer.apple.com/thread/87329

해결 방법은 다음 중 하나 인 것 같습니다.

(a) xib를 스토리 보드로 마이그레이션하거나

(b) 프로그래밍 방식으로 몇 가지 추가 제약 조건을 추가합니다.

(a)가 실제로 옵션이 아닌 경우 수동 접근 방식은 다음과 같습니다.

xib에 안전 영역 (즉, 상태 표시 줄 또는 탐색 표시 줄 아래) 내에 유지하려는보기가 있다고 가정합니다.

  1. 보기와 iOS 11의 안전 영역 사이에 xib에 제약 조건을 추가합니다. 최상위 제약 조건에 우선 순위 750을 할당합니다.

    상단 제약 추가

  2. 뷰 컨트롤러에서 속성을 추가합니다.

    @property (nonatomic, strong) NSLayoutConstraint *topLayoutConstraint;
    

    그리고 viewDidLayoutSubviews에서 :

    - (void)viewDidLayoutSubviews {
        [super viewDidLayoutSubviews];
    
        if (@available(iOS 11, *)) {
            // safe area constraints already set
        }
        else {
            if (!self.topLayoutConstraint) {
                self.topLayoutConstraint = [self.<yourview>.topAnchor constraintEqualToAnchor:self.topLayoutGuide.bottomAnchor];
                [self.topLayoutConstraint setActive:YES];
            }
        }
    }
    

    새로운 제약 조건은 iOS 9 및 iOS 10에 대해서만 생성되며 기본 우선 순위는 1000이며 xib의 제약 조건을 재정의합니다.

  3. 홈 인디케이터를 피해야하는 경우 하단 구속에 대해 반복합니다.

Swift 4 버전 :

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    if #available(iOS 11, *) {
        // safe area constraints already set
    } else {
        if topLayoutConstraint == nil {
            topLayoutConstraint = <yourview>.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor)
            topLayoutConstraint?.isActive = true
        }
    }
}

Xcode 9 GM에서 관찰 한 iOS 11의 안전 영역 제약과 관련하여 적어도 하나의 하위 호환성 문제가 있습니다. 안전 영역 제약이있는 푸시 된 뷰 컨트롤러입니다.

탐색 모음이 숨겨져 있고 안전 영역 상단 제한보기를 푸시하면 푸시 된보기가 iOS 9 및 10의 상태 표시 줄과 겹칩니다.

탐색 표시 줄이 표시되고 "상단 표시 줄 아래"가 비활성화 된 경우, 푸시 된보기는 여전히 탐색 표시 줄 아래로 슬라이드하여 화면 상단으로 이동합니다. 탐색 모음이 올바르게 배치됩니다.

iOS 11에서는 두 경우 모두 레이아웃이 정확합니다.

다음은 간단한 예입니다. http://www.filedropper.com/foobar

그리고 여기에 탐색 표시 줄이 숨겨진 비디오가 있습니다 (왼쪽에 iOS 10.3, 오른쪽에 iOS 11) : https://vimeo.com/234174841/1e27a96a87

다음은 탐색 모음이 표시되는 버전입니다 (니브에서 활성화 됨) : https://vimeo.com/234316256/f022132d57

나는 이것을 레이더 ​​# 34477706으로 제출했습니다.

탐색 모음 표시 사례를 지적 해 주신 @Sander 에게 감사드립니다 .


스토리 보드없이 xib를 사용하는 경우 iOS 10에 레이아웃 가이드가 없습니다. 따라서 xib를 스토리 보드로 이동하여 이전 버전과의 호환성을 유지하세요.


예, 프로젝트 / 앱은 문제없이 iOS 11 이전의 iOS 버전에서 작동합니다. iOS 11 이전 버전에서는 Safe Area Layout을 일반 AutoLayout으로 대체 / 고려하며 Rules of Top and Bottom 레이아웃 가이드를 따릅니다.

두 플랫폼 (iOS 11 및 이전 버전 iOS 10)에서 'SafeAreaLayout'을 사용하거나 사용하지 않고 기존 프로젝트를 테스트했습니다. 잘 작동합니다.

다음 사항을 확인하십시오.

  • AutoLayout에서 프로젝트 / 사용자 인터페이스를 디자인 한 경우; UIElement의 제약 조건은 상위 및 하단 레이아웃 가이드 (superview가 아님)를 따릅니다. 따라서 SafeAreaLayout 옵션을 한 번 클릭 (활성화)하면 스토리 보드의 모든 인터페이스 빌더 파일에 대해 SafeArea 레이아웃이 자동으로 올바르게 구현됩니다.

  • SafeAreaLayout에서 프로젝트 / 사용자 인터페이스를 디자인 한 경우; 그런 다음 iOS 이전 버전의 상단 및 하단 레이아웃 가이드를 자동으로 따릅니다.

다음은 결과가 포함 된 샘플 스냅 샷입니다. 안전 영역 레이아웃을 활성화 또는 비활성화하면 기존 디자인에 영향을주지 않습니다.

안전 영역 레이아웃 : 여기에 이미지 설명 입력

AutoLayout

여기에 이미지 설명 입력

간단히 말해서, 귀하의 질문에 대한 대답은 "11 이전의 iOS와 호환되는 안전 영역 레이아웃 가이드 활성화"입니다.

프로젝트 / 앱에서 안전 영역 레이아웃을 구현할 수 있으며 안전 영역 레이아웃을 Top으로 변환하여 이전 iOS 버전에서 잘 작동합니다. 및 하단 레이아웃.


Objective-C에서 iOS 10에서 좋은 결과를 얻었습니다. xib에서 SafeArea를 사용하는 경우 다음을 추가 할 수 있습니다 viewDidLoad.

if (@available(iOS 11.0, *)) {}
else {
    self.edgesForExtendedLayout = UIRectEdgeNone;
}

"안전 영역 레이아웃 가이드"는 이전 버전과 호환됩니다. 글쎄, xib에서 사용하지 않는 한. 스토리 보드를 사용하면 괜찮아 보입니다.

내보기 상단의 첫 번째 개체에서 "상단 레이아웃 제약"에 액세스하여 문제를 해결했습니다.

@property (weak, nonatomic) IBOutlet NSLayoutConstraint *topLayoutConstraint;

그런 다음 상수 값을 해당 제약 조건으로 변경하고보기를 새로 고칩니다. 예를 들어 탐색 모음 (높이 44)과 상태 표시 줄 (높이 20)을 사용하는 경우 :

if (SYSTEM_VERSION_LESS_THAN(@"11.0")) {
    _topLayoutConstraint.constant = 64;
    [self.view layoutIfNeeded];
}

다음과 같이 정의 된 SYSTEM_VERSION_LESS_THAN으로 :

#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)

NSLayoutConstraint.NET에 고정 된 하위 클래스 만 있으면 더 편리한 방법을 찾았습니다 safeArea.

UIView에서 ViewController를 가져와야하므로 다소 엉망이지만 Apple이 마침내 Xibs의 safeArea에 대한 하위 호환성을 수정하기 전까지는 쉽고 좋은 대안입니다.

아강:

class SafeAreaBackwardsCompatabilityConstraint: NSLayoutConstraint {
private weak var newConstraint: NSLayoutConstraint?

override var secondItem: AnyObject? {
    get {
        if #available(iOS 11.0, *) {}
        else {
            if let vc = (super.secondItem as? UIView)?.parentViewController, newConstraint == nil {
                newConstraint = (self.firstItem as? UIView)?.topAnchor.constraint(equalTo: vc.topLayoutGuide.bottomAnchor)
                newConstraint?.isActive = true
                newConstraint?.constant = self.constant
            }
        }
        return super.secondItem
    }
}

override var priority: UILayoutPriority {
    get {
        if #available(iOS 11.0, *) { return super.priority }
        else { return 750 }
    }
    set { super.priority = newValue }
}
}

private extension UIView {
var parentViewController: UIViewController? {
    var parentResponder: UIResponder? = self
    while parentResponder != nil {
        parentResponder = parentResponder!.next
        if let viewController = parentResponder as? UIViewController {
            return viewController
        }
    }
    return nil
}
}

Xib :

여기에 이미지 설명 입력


iOS 9에서 WKWebView 및 안전 영역과의 하위 호환성 문제가 있습니다. 어떤 이유로 WKWebView는 단순히 안전 영역 레이아웃 설정을 무시합니다.


Objective-C에서 iPhone-X의 상단 및 하단 여백

if (@available(iOS 11, *)) {

    NSLayoutConstraint *bottomConstraint   = [NSLayoutConstraint constraintWithItem:self.childView
                                                                              attribute:NSLayoutAttributeBottom
                                                                              relatedBy:NSLayoutRelationEqual
                                                                                 toItem:self.parentView.safeAreaLayoutGuide
                                                                              attribute:NSLayoutAttributeBottom
                                                                             multiplier:1.0
                                                                               constant:0];


    NSLayoutConstraint *topConstraint   = [NSLayoutConstraint constraintWithItem:self.childView
                                                                       attribute:NSLayoutAttributeTop
                                                                       relatedBy:NSLayoutRelationEqual
                                                                          toItem:self.parentView.safeAreaLayoutGuide
                                                                       attribute:NSLayoutAttributeTop
                                                                      multiplier:1.0
                                                                        constant:0];


} else {

    NSLayoutConstraint *bottomConstraint   = [NSLayoutConstraint constraintWithItem:self.childView
                                                                          attribute:NSLayoutAttributeBottom
                                                                          relatedBy:NSLayoutRelationEqual
                                                                             toItem:self.parentView
                                                                          attribute:NSLayoutAttributeBottom
                                                                         multiplier:1.0
                                                                           constant:0];


    NSLayoutConstraint *topConstraint   = [NSLayoutConstraint constraintWithItem:self.childView
                                                                       attribute:NSLayoutAttributeTop
                                                                       relatedBy:NSLayoutRelationEqual
                                                                          toItem:self.parentView
                                                                       attribute:NSLayoutAttributeTop
                                                                      multiplier:1.0
                                                                        constant:0];

}

내 프로젝트로 한 작업은 다음과 같습니다.

제 경우에는 my topConstraintbottomConstraints가 모두 @IBOutlets입니다. 이것은 iOS 8.

상단 및 하단 제약 조건에 대한 초기 구성은 일반 iPhone 용이므로 iPhone X에 대한 제약 조건 만 편집하고 있습니다.

    // iOS 11 Layout Fix. (For iPhone X)
    if #available(iOS 11, *) {
        self.topConstraint.constant = self.topConstraint.constant + self.view.safeAreaInsets.top

        self.bottomConstraint.constant = self.bottomConstraint.constant + self.view.safeAreaInsets.bottom
    }

.

참고 : self.view SuperView를 사용하는 이유입니다.safeAreaInsets


모든 ViewController가 확장하는 일반 ViewController가있는 경우 다른 솔루션은 조정해야하는 항목을 IBOutletCollection에 넣고 해당 GenericViewController에서 프로그래밍 방식으로 조정하는 것입니다. 내 코드는 다음과 같습니다.

@IBOutlet var adjustTopSpaceViews: [UIView]?

override func viewDidLoad() {
    super.viewDidLoad()
    adjustViews()
    ....
}

func adjustViews() {
    guard let views = adjustTopSpaceViews,
        ProcessInfo.processInfo.operatingSystemVersion.majorVersion < 11 else {
            return
    }
    let statusBarHeight = UIApplication.shared.statusBarFrame.height
    for subview in views {
        subview.superview?.constraints.filter({ (constraint) -> Bool in
            return constraint.firstAttribute == .top
                && constraint.secondAttribute == .top
                && (constraint.firstItem as? UIView == subview || constraint.secondItem as? UIView == subview)
        }).forEach({ (constraint) in
            constraint.constant += (constraint.firstItem as? UIView == subview) ? statusBarHeight : -statusBarHeight
        })
    }
}

다음은 신속한 4+의 iOS 9에서 iOS 11+ 솔루션 래퍼입니다.

    let safeAreaTopAnchor:NSLayoutYAxisAnchor?
    if #available(iOS 11.0, *) {
        safeAreaTopAnchor = contentView.safeAreaLayoutGuide.topAnchor
    } else {
        // Fallback on earlier versions

        var parentViewController: UIViewController? {
            var parentVCResponder: UIResponder? = self
            while parentVCResponder != nil {
                parentVCResponder = parentVCResponder!.next
                if let viewController = parentVCResponder as? UIViewController {
                    return viewController
                }
            }
            return nil
        }

        safeAreaTopAnchor = parentViewController?.topLayoutGuide.bottomAnchor

    }

스위프트 5

그냥 해요. 간단하고 실물에 매우 가깝습니다 ( 'r'만 추가됨).

extension UIView {
var saferAreaLayoutGuide: UILayoutGuide {
    get {
        if #available(iOS 11.0, *) {
            return self.safeAreaLayoutGuide
        } else {
            return self.layoutMarginsGuide
        }
    }
}

다음과 같이 사용하십시오.

button.topAnchor.constraint(equalTo: view.saferAreaLayoutGuide.topAnchor, constant: 16)

참고 URL : https://stackoverflow.com/questions/46184197/ios-11-safe-area-layout-guide-backwards-compatibility

반응형