programing

iPhone X에서 UIView의 safeAreaInsets는 0입니다.

newsource 2023. 8. 28. 21:02

iPhone X에서 UIView의 safeAreaInsets는 0입니다.

나는 아이폰 X에 적응하기 위해 앱을 업데이트하고 있습니다.지금은 하나를 제외한 모든 보기가 정상적으로 작동합니다.전체 화면을 포괄하는 사용자 정의 UI 보기를 제공하는 뷰 컨트롤러가 있습니다.에를 에.UIScreen.main.bounds모든 레이아웃이 완료되기 전에 보기의 크기를 확인합니다(CollectionView에 대한 올바른 항목Size를 입력하기 위해 필요합니다).저는 이제 그런 일을 할 수 있을 거라고 생각했습니다.UIScreen.main.bounds.size.height - safeAreaInsets.bottom적절한 사용 가능한 크기를 얻기 위해.iPhoneX(시뮬레이터) 안전한 AreaInsets(아이폰X)에서 시도 중인 (0,0,0,0)을 반환한다는 것입니다.아이디어 있어요?다른 보기에서는 safeAreaInsets에 대한 올바른 번호를 얻습니다.

감사해요!

최근에 viewDidLoad가 트리거되자마자 안전 영역 inset이 반환되는(0, 0, 0, 0) 유사한 문제가 발생했습니다.보기 로드의 나머지 부분보다 부분적으로 늦게 설정된 것 같습니다.

viewSafeAreaInsetsDidChanged를 재정의하고 대신 레이아웃을 수행하여 해결했습니다.

override func viewSafeAreaInsetsDidChange() {
 // ... your layout code here
} 

해결책은 이미 알고 있습니다.는 저는모구작수있다었니습고행에서 .init의 크기가 safeAreaInsets에서 합니다.layoutSubviews()

저는 아이폰 X의 키보드를 위한 길을 만들기 위해 보기를 위로 이동하려고 시도하는 중에도 이 문제에 부딪혔습니다.화면이 그려졌을 때 이 시점에서 하위 보기가 배치된 것으로 알고 있지만 기본 보기의 safeAreaInset은 항상 0입니다.위에서 언급했듯이, 내가 발견한 해결책은 키 윈도를 가져와서 대신 세트로 안전 영역을 확인하는 것입니다.

Obj-C:

CGFloat bottomInset = [UIApplication sharedApplication].keyWindow.safeAreaInsets.bottom;

스위프트:

let bottomInset = UIApplication.shared.keyWindow?.safeAreaInsets.bottom

그런 다음 이 값을 사용하여 필요에 따라 구속조건을 조정하거나 프레임을 볼 수 있습니다.

다른 뷰 내에 하위 뷰인 뷰가 있습니다.iPhoneX의 해당 보기에서 safeAreaInsets를 올바르게 가져올 수 없습니다. layoutSubviews에 넣더라도 항상 0을 반환합니다.마지막 해결책은 매력적으로 작동할 수 있는 안전한 AreaInset을 감지하기 위해 다음 UIS 화면 확장을 사용하는 것입니다.

extension UIScreen {

    func widthOfSafeArea() -> CGFloat {

        guard let rootView = UIApplication.shared.keyWindow else { return 0 }

        if #available(iOS 11.0, *) {

            let leftInset = rootView.safeAreaInsets.left

            let rightInset = rootView.safeAreaInsets.right

            return rootView.bounds.width - leftInset - rightInset

        } else {

            return rootView.bounds.width

        }

    }

    func heightOfSafeArea() -> CGFloat {

        guard let rootView = UIApplication.shared.keyWindow else { return 0 }

        if #available(iOS 11.0, *) {

            let topInset = rootView.safeAreaInsets.top

            let bottomInset = rootView.safeAreaInsets.bottom

            return rootView.bounds.height - topInset - bottomInset

        } else {

            return rootView.bounds.height

        }

    }

}

뷰 컨트롤러에서 "self.view.safeAreaInset"을 사용하려고 합니다.먼저 컨트롤러의 라이프사이클 방법인 "viewDidLoad"에서 NSInsetZero를 사용한 다음 인터넷에서 검색하여 정답을 얻으면 로그는 다음과 같습니다.

ViewController loadView() SafeAreaInsets :UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0)
ViewController viewDidLoad() SafeAreaInsets :UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0)
ViewController viewWillAppear() SafeAreaInsets :UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0)
ViewController viewDidLayoutSubviews() SafeAreaInsets :UIEdgeInsets(top: 44.0, left: 0.0, bottom: 34.0, right: 0.0)
ViewController viewDidAppear() SafeAreaInsets :UIEdgeInsets(top: 44.0, left: 0.0, bottom: 34.0, right: 0.0)

safeAreaInset에 필요한 올바른 방법을 선택하여 사용할 수 있습니다!

Swift iOS 11,12,13+

var insets : UIEdgeInsets = .zero

 override func viewDidLoad() {
     super.viewDidLoad()

     insets = UIApplication.shared.delegate?.window??.safeAreaInsets ?? .zero
     //Or you can use this
     insets = self.view.safeAreaInsets
}

제 경우에는 UICollectionView inside viewDidLoad()를 추가하고 있었습니다.

collectionView = UICollectionView(frame: view.safeAreaLayoutGuide.layoutFrame, collectionViewLayout: createCompositionalLayout())

안타깝게도 이 단계에서 안전한 영역 배치 가이드는 여전히 0입니다.

다음을 추가하여 해결했습니다.

override func viewDidLayoutSubviews() {
    collectionView.frame = view.safeAreaLayoutGuide.layoutFrame
}

컨테이너 뷰 컨트롤러의 viewDidAppear(_:) 메서드는 에 있는 뷰를 설명하기 위해 내장된 하위 뷰 컨트롤러의 안전 영역을 확장합니다.

뷰가 뷰 계층에 추가될 때까지 뷰에 대한 안전 영역 집합이 정확하지 않으므로 이 방법을 수정합니다.

override func viewDidAppear(_ animated: Bool) {

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

     var newSafeArea = view.safeAreaInsets

     // Adjust the safe area to accommodate 
     //  the width of the side view.

     if let sideViewWidth = sideView?.bounds.size.width {
        newSafeArea.right += sideViewWidth
     }

    // Adjust the safe area to accommodate 
    //  the height of the bottom view.
    if let bottomViewHeight = bottomView?.bounds.size.height {
       newSafeArea.bottom += bottomViewHeight
    }

    // Adjust the safe area insets of the 
    //  embedded child view controller.
    let child = self.childViewControllers[0]
    child.additionalSafeAreaInsets = newSafeArea
  } 
}

저도 같은 문제에 부딪혔습니다.제 경우에는 통화 후 삽입하는 보기의 크기가 정확할 것입니다.view.layoutIfNeeded().그view.safeAreaInsets이 후에 설정되었지만, 오직.top값이 정확했습니다.맨 아래 값은 그대로였습니다.0(iPhone X의 경우).

어떤 점에서, 어떤 점에서,safeAreaInsets올바르게 설정되었습니다. 뷰의 중단점을 추가했습니다.safeAreaInsetsDidChange()방법.이것은 여러 번 불려졌지만, 내가 봤을 때만.CALayer.layoutSublayers()역추적에서 값이 올바르게 설정되었습니다.

그래서 제가 대신했습니다.view.layoutIfNeeded()의 옆에CALayer의 상대편view.layer.layoutIfNeeded()그것은 결과적으로.safeAreaInsets바로 설정하여 문제를 해결할 수 있습니다.

TL;DR

교체하다

view.layoutIfNeeded()

타고

view.layer.layoutIfNeeded()
[UIApplication sharedApplication].keyWindow.safeAreaInsets return none zero

그냥 해보세요.self.view.safeAreaInsets대신에UIApplication.shared.keyWindow?.safeAreaInsets응용 프로그램 키 Window를 통해 요청할 때 iOS 11.x.x 장치에서 안전 영역 삽입이 채워지지 않는 것 같습니다.

layoutSubviews 또는 viewDidLayoutSubviews까지 뷰 레이아웃은 보장되지 않습니다.이러한 라이프사이클 방법 이전에는 절대 크기에 의존하지 마십시오.그렇게 하면 일관성 없는 결과가 나올 것입니다.

안전 영역 safeAreaInset을 계산하려면 뷰에서 확인합니다.Load()에서와 마찬가지로 뷰가 형성되지 않은 것으로 나타납니다().올바른 삽입이 나타날 것입니다!

서브클래스를 할 수 없는 경우, 이것을 사용할 수 있습니다.UIView연장의

다음과 같은 API를 제공합니다.

view.onSafeAreaInsetsDidChange = { [unowned self] in
   self.updateSomeLayout()
}

확장자가 다음을 추가합니다.onSafeAreaInsetsDidChange개체 연결을 사용하는 속성입니다.그런 다음 스와이즐링합니다.UIView.safeAreaInsetsDidChange()마감을 호출하는 방법(있는 경우).

extension UIView {
    
    typealias Action = () -> Void
    
    var onSafeAreaInsetsDidChange: Action? {
        get {
            associatedObject(for: "onSafeAreaInsetsDidChange") as? Action
        }
        set {
            Self.swizzleSafeAreaInsetsDidChangeIfNeeded()
            set(associatedObject: newValue, for: "onSafeAreaInsetsDidChange")
        }
    }
    
    static var swizzled = false
    
    static func swizzleSafeAreaInsetsDidChangeIfNeeded() {
        guard swizzled == false else { return }
        swizzle(
            method: "safeAreaInsetsDidChange",
            originalSelector: #selector(originalSafeAreaInsetsDidChange),
            swizzledSelector: #selector(swizzledSafeAreaInsetsDidChange),
            for: Self.self
        )
        swizzled = true
    }
    
    @objc func originalSafeAreaInsetsDidChange() {
        // Original implementaion will be copied here.
    }
    
    @objc func swizzledSafeAreaInsetsDidChange() {
        originalSafeAreaInsetsDidChange()
        onSafeAreaInsetsDidChange?()
    }
}

일부 도우미(및 참조)를 사용하지만 지글링 및 개체 연결 API를 직접 사용하는 경우에는 실제로 필요하지 않습니다.

언급URL : https://stackoverflow.com/questions/47032855/safeareainsets-in-uiview-is-0-on-an-iphone-x