programing

상단과 하단의 높이에 안전한 영역을 확보합니다.

yellowcard 2023. 4. 15. 08:41
반응형

상단과 하단의 높이에 안전한 영역을 확보합니다.

안전하지 않은 지역에 대해 위아래 높이를 모두 얻는 가장 적절한 방법은 무엇일까요?

여기에 이미지 설명 입력

다음을 시도해 보십시오.

목표 C에서

if (@available(iOS 11.0, *)) {
    UIWindow *window = UIApplication.sharedApplication.windows.firstObject;
    CGFloat topPadding = window.safeAreaInsets.top;
    CGFloat bottomPadding = window.safeAreaInsets.bottom;
}

인스위프트

if #available(iOS 11.0, *) {
    let window = UIApplication.shared.keyWindow
    let topPadding = window?.safeAreaInsets.top
    let bottomPadding = window?.safeAreaInsets.bottom
}

Swift - iOS 13.0 이후

// Windows 어레이의 첫 번째 요소를 Key Window가 사용하지 않도록 사용

if #available(iOS 13.0, *) {
    let window = UIApplication.shared.windows.first
    let topPadding = window.safeAreaInsets.top
    let bottomPadding = window.safeAreaInsets.bottom
}

레이아웃 가이드 사이의 높이를 구하려면

let guide = view.safeAreaLayoutGuide
let height = guide.layoutFrame.size.height

★★★★★★★★★★★★★★★★★.full frame height = 812.0,safe area height = 734.0

녹색 뷰의 프레임은 다음과 같습니다.guide.layoutFrame

여기에 이미지 설명 입력

스위프트 4, 5

뷰는 API에 의해 큐잉되고 뷰가 메모리에 로드된 후 처리되기 때문에 뷰 컨트롤러의 라이프사이클 중 어느 곳에서나 구속조건을 사용하여 뷰를 안전한 영역 앵커에 고정시킬 수 있습니다.그러나 안전 뷰.를 들어 뷰 컨트롤러의 라이프 사이클이 끝날 때까지 기다려야 합니다.viewDidLayoutSubviews().

이는 모든 뷰 컨트롤러에 연결됩니다.

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    let topSafeArea: CGFloat
    let bottomSafeArea: CGFloat

    if #available(iOS 11.0, *) {
        topSafeArea = view.safeAreaInsets.top
        bottomSafeArea = view.safeAreaInsets.bottom
    } else {
        topSafeArea = topLayoutGuide.length
        bottomSafeArea = bottomLayoutGuide.length
    }

    // safe area values are now available to use
}

API의 설계방법과 디바이스 방향 변경 등 모든 뷰 변경 시 값이 갱신되기 때문에 윈도우에서 (가능한 경우) 해제하는 것보다 이 방법을 선호합니다.

그러나 일부 커스텀 표시 뷰 컨트롤러는 위의 방법을 사용할 수 없습니다(일시 컨테이너 뷰에 있기 때문에 의심됩니다).이 경우 루트 뷰 컨트롤러에서 값을 얻을 수 있습니다.이 값은 현재 뷰 컨트롤러의 라이프 사이클 중 어디에서나 항상 사용할 수 있습니다.

anyLifecycleMethod()
    guard let root = UIApplication.shared.keyWindow?.rootViewController else {
        return
    }
    let topSafeArea: CGFloat
    let bottomSafeArea: CGFloat

    if #available(iOS 11.0, *) {
        topSafeArea = root.view.safeAreaInsets.top
        bottomSafeArea = root.view.safeAreaInsets.bottom
    } else {
        topSafeArea = root.topLayoutGuide.length
        bottomSafeArea = root.bottomLayoutGuide.length
    }

    // safe area values are now available to use
}

여기 있는 다른 대답들은 다 통하지 않았지만, 이건 통했어

var topSafeAreaHeight: CGFloat = 0
var bottomSafeAreaHeight: CGFloat = 0

  if #available(iOS 11.0, *) {
    let window = UIApplication.shared.windows[0]
    let safeFrame = window.safeAreaLayoutGuide.layoutFrame
    topSafeAreaHeight = safeFrame.minY
    bottomSafeAreaHeight = window.frame.maxY - safeFrame.maxY
  }

여기 있는 모든 답변이 도움이 됩니다. 도움을 주신 모든 분들 덕분입니다.

그러나 안전 구역의 토픽은 조금 혼란스러워서 잘 문서화되어 있지 않은 것 같습니다.

한 한 하겠습니다.safeAreaInsets,safeAreaLayoutGuide ★★★★★★★★★★★★★★★★★」LayoutGuide.

7에서는, 이 iOS 을 도입했습니다.topLayoutGuide ★★★★★★★★★★★★★★★★★」bottomLayoutGuideUIViewController상태, 네비게이션, 탭바 등의 UIKit 바에 의해 컨텐츠가 숨겨지지 않도록 제약조건을 작성할 수 있었습니다.이러한 레이아웃 가이드에서는 컨텐츠의 제약조건을 지정할 수 있었습니다.상단 또는 하단의 네비게이션 요소(UIKit 바, 상태 바, 네비게이션, 탭 바…)에 의해 컨텐츠가 숨겨지는 것을 피할 수 있었습니다.

예를 들어 tableView를 작성하려면 위의 화면에서 다음과 같은 작업을 수행합니다.

self.tableView.contentInset = UIEdgeInsets(top: -self.topLayoutGuide.length, left: 0, bottom: 0, right: 0)

iOS 11에서는 Apple이 이러한 속성을 단일 안전 영역 레이아웃 가이드로 대체하는 것을 권장하지 않습니다.

애플에 의한 안전 구역

안전 영역은 전체 인터페이스의 가시적인 부분 내에 뷰를 배치하는 데 도움이 됩니다.UIKit 정의 뷰 컨트롤러는 콘텐츠 위에 특별한 뷰를 배치할 수 있습니다.예를 들어 네비게이션컨트롤러는 기본 뷰컨트롤러의 콘텐츠 위에 네비게이션바를 표시합니다.이러한 보기는 부분적으로 투명하더라도 여전히 아래에 있는 내용을 차단합니다.TVOS에서 세이프 영역에는 스크린 베젤로 덮인 영역을 나타내는 오버스캔 삽입도 포함됩니다.

iPhone 8 및 iPhone X 시리즈의 안전 영역을 다음에 나타냅니다.

여기에 이미지 설명 입력

safeAreaLayoutGuide의 특성입니다.UIView

★★★★★★★★★★★★★★의 높이를 .safeAreaLayoutGuide:

extension UIView {
   var safeAreaHeight: CGFloat {
       if #available(iOS 11, *) {
        return safeAreaLayoutGuide.layoutFrame.size.height
       }
       return bounds.height
  }
}

그러면 사진의 화살표 높이가 반환됩니다.

이제 홈 스크린의 최고 "노치" 표시 높이와 최저 표시 높이를 얻는 것은 어떨까요?

에서는 ★★★★★★를 사용합니다.safeAreaInsets

뷰의 안전 영역에는 뷰 컨트롤러의 뷰를 가리는 탐색 막대, 탭 막대, 도구 모음 및 기타 상위 항목이 포함되지 않은 영역이 반영됩니다.(tvOS에서는 세이프 영역은 화면 베젤에 가려지지 않는 영역을 반영합니다.)뷰의 경계 직사각형에 이 특성의 삽입물을 적용하여 뷰에 대한 안전 영역을 얻습니다.뷰가 현재 뷰 계층에 설치되어 있지 않거나 아직 화면에 표시되지 않으면 이 속성의 가장자리 삽입은 0입니다.

다음은 iPhone 8 및 iPhone X 시리즈 중 하나에서 안전하지 않은 영역과 가장자리와의 거리를 보여 줍니다.

여기에 이미지 설명 입력

여기에 이미지 설명 입력

네비게이션 바가 추가된 경우

여기에 이미지 설명 입력

여기에 이미지 설명 입력

',어,어,,어,어,어,어,어?'를 사용하겠습니다.safeAreaInset

솔루션에는 중요한 점에서 차이가 있지만

첫 번째:

self.view.safeAreaInsets

그러면 EdgeInset이 반환되며, 이제 상단 및 하단에 액세스하여 삽입된 내용을 확인할 수 있습니다.

두 번째:

UIApplication.shared.windows.first{$0.isKeyWindow }?.safeAreaInsets

첫 번째 뷰는 삽입되므로 네비게이션바가 있는 경우 고려되지만 두 번째 뷰는 창의 safeAreaInset에 액세스하기 때문에 네비게이션바는 고려되지 않습니다.

Swift 5, X코드 11.4

`UIApplication.shared.keyWindow` 

폐지 경고가 표시됩니다.iOS 13.0에서는 "key Window"가 사용되지 않습니다. 연결된 모든 장면에서 키 창을 반환하므로 여러 장면을 지원하는 애플리케이션에는 사용하지 마십시오.저는 이렇게 써요.

extension UIView {

    var safeAreaBottom: CGFloat {
         if #available(iOS 11, *) {
            if let window = UIApplication.shared.keyWindowInConnectedScenes {
                return window.safeAreaInsets.bottom
            }
         }
         return 0
    }

    var safeAreaTop: CGFloat {
         if #available(iOS 11, *) {
            if let window = UIApplication.shared.keyWindowInConnectedScenes {
                return window.safeAreaInsets.top
            }
         }
         return 0
    }
}

extension UIApplication {
    var keyWindowInConnectedScenes: UIWindow? {
        return windows.first(where: { $0.isKeyWindow })
    }
}

iOS 11에는 safeArea가 변경되었음을 알려주는 메서드가 있습니다.

override func viewSafeAreaInsetsDidChange() {
    super.viewSafeAreaInsetsDidChange()
    let top = view.safeAreaInsets.top
    let bottom = view.safeAreaInsets.bottom
}

이는 Swift의 심플한 2라인 솔루션으로서 뷰 라이프 사이클 전체에 걸쳐 유효합니다.

let top    = UIApplication.shared.windows[0].safeAreaInsets.top
let bottom = UIApplication.shared.windows[0].safeAreaInsets.bottom

난 개인적으로 그게 필요했어viewDidLoad그리고.view.safeAreaInsets아직 계산되지 않았습니다.

safeAreaLayoutGuide 뷰가 화면에 표시되는 경우 이 가이드에는 탐색 막대, 탭 막대, 도구 모음 및 기타 상위 뷰에서 다루지 않는 뷰 부분이 반영됩니다.(tvOS에서 세이프 영역은 화면 베젤을 덮지 않은 영역을 나타냅니다.)뷰가 현재 뷰 계층에 설치되어 있지 않거나 아직 화면에 표시되지 않는 경우 레이아웃 가이드 가장자리는 뷰의 가장자리와 동일합니다.

스크린샷의 빨간색 화살표 높이를 확인하려면 다음과 같이 하십시오.

self.safeAreaLayoutGuide.layoutFrame.size.height

Swift 5 확장

이는 내선번호로 사용할 수 있으며 UIApplication.topSafeAreaHeight와 함께 호출할 수 있습니다.

extension UIApplication {
    static var topSafeAreaHeight: CGFloat {
        var topSafeAreaHeight: CGFloat = 0
         if #available(iOS 11.0, *) {
               let window = UIApplication.shared.windows[0]
               let safeFrame = window.safeAreaLayoutGuide.layoutFrame
               topSafeAreaHeight = safeFrame.minY
             }
        return topSafeAreaHeight
    }
}

UIApplication의 확장은 옵션이며, UIView의 확장 또는 원하는 모든 기능을 사용할 수 있습니다.또, 글로벌 기능의 확장도 가능합니다.

저는 코코아팟 프레임워크로 일하고 있는데 만약을 위해UIApplication.shared사용할 수 없습니다.safeAreaInsets의 시야에 있는window:

if #available(iOS 11.0, *) {
    let insets = view.window?.safeAreaInsets
    let top = insets.top
    let bottom = insets.bottom
}
UIWindow *window = [[[UIApplication sharedApplication] delegate] window]; 
CGFloat fBottomPadding = window.safeAreaInsets.bottom;

Swift의 경우UI:

코드

private struct SafeAreaInsetsKey: EnvironmentKey {
    static var defaultValue: EdgeInsets {
        UIApplication.shared.windows[0].safeAreaInsets.insets
    }
}

extension EnvironmentValues {
    
    var safeAreaInsets: EdgeInsets {
        self[SafeAreaInsetsKey.self]
    }
}

private extension UIEdgeInsets {
    
    var insets: EdgeInsets {
        EdgeInsets(top: top, leading: left, bottom: bottom, trailing: right)
    }
}

사용.

struct MyView: View {
    
    @Environment(\.safeAreaInsets) private var safeAreaInsets
    
    var body: some View {
        Text("Ciao")
            .padding(safeAreaInsets)
    }
}

또는 Swift 사용UI GeometryReader API.

struct V: View {
    var body: some View {
        GeometryReader { geometry in
            Text("\(geometry.safeAreaInsets.top)")
            Text("\(geometry.safeAreaInsets.bottom)")
        }
    }
}


코드가 작동하지 않을 수 있지만, 아이디어를 보여줍니다.

목표-C 키창0일 때 문제가 발생한 사용자위의 코드를 viewDidEar에 넣기만 하면 됩니다(viewDidLoad가 아님).

iOS 13+/Swift 5의 경우, 여기에서는 이것 말고는 아무것도 동작하지 않았습니다.

    if #available(iOS 13.0, *) {
        topPadding = UIApplication.shared.windows.first?.safeAreaInsets.top ?? 0
        bottomPadding = UIApplication.shared.windows.first?.safeAreaInsets.bottom ?? 0
    }

보다 포괄적인 어프로치

  import SnapKit

  let containerView = UIView()
  containerView.backgroundColor = .red
  self.view.addSubview(containerView)
  containerView.snp.remakeConstraints { (make) -> Void in
        make.width.top.equalToSuperView()
        make.top.equalTo(self.view.safeArea.top)
        make.bottom.equalTo(self.view.safeArea.bottom)
  }




extension UIView {
    var safeArea: ConstraintBasicAttributesDSL {
        if #available(iOS 11.0, *) {
            return self.safeAreaLayoutGuide.snp
        }
        return self.snp
    }


    var isIphoneX: Bool {

        if #available(iOS 11.0, *) {
            if topSafeAreaInset > CGFloat(0) {
                return true
            } else {
                return false
            }
        } else {
            return false
        }

    }

    var topSafeAreaInset: CGFloat {
        let window = UIApplication.shared.keyWindow
        var topPadding: CGFloat = 0
        if #available(iOS 11.0, *) {
            topPadding = window?.safeAreaInsets.top ?? 0
        }

        return topPadding
    }

    var bottomSafeAreaInset: CGFloat {
        let window = UIApplication.shared.keyWindow
        var bottomPadding: CGFloat = 0
        if #available(iOS 11.0, *) {
            bottomPadding = window?.safeAreaInsets.bottom ?? 0
        }

        return bottomPadding
    }
}

가로 모드로 변경하는 사용자는 회전 후에 반드시 viewSafeAreaInsetsDidChange를 사용하여 최신 값을 얻어야 합니다.

private var safeAreaInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)

override func viewSafeAreaInsetsDidChange() {
        if #available(iOS 11.0, *) {
            safeAreaInsets = UIApplication.shared.keyWindow!.safeAreaInsets
        }
}

스위프트 4

if let window = UIApplication.shared.windows.first {
    
    let topPadding = window.safeAreaInsets.top
    let bottomPadding = window.safeAreaInsets.bottom
    
}

수업에서 사용

class fitToTopInsetConstraint: NSLayoutConstraint {
    
    override func awakeFromNib() {
        
        if let window = UIApplication.shared.windows.first {
            
            let topPadding = window.safeAreaInsets.top
            
            self.constant += topPadding
            
        }
        
    }
}

class fitToBottomInsetConstraint: NSLayoutConstraint {
    
    override func awakeFromNib() {
        
        if let window = UIApplication.shared.windows.first {
            
            let bottomPadding = window.safeAreaInsets.bottom
            
            self.constant += bottomPadding
            
        }
        
    }
}

여기에 이미지 설명 입력

여기에 이미지 설명 입력

애플리케이션을 빌드할 때 안전 영역 패딩을 볼 수 있습니다.

extension UIViewController {
    var topbarHeight: CGFloat {
        return
            (view.window?.safeAreaInsets.top ?? 0) +
            (view.window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0.0) +
            (self.navigationController?.navigationBar.frame.height ?? 0.0)
    }
}

다음은 rootController를 배치한 후 호출할 수 있는 다른 응답에 기초한 무료 함수입니다.프리 스탠딩 기능으로 사용할 수 있습니다.

    func safeAreaInsets() -> UIEdgeInsets? {
    (UIApplication
        .shared
        .keyWindow?
        .rootViewController)
        .flatMap {
            if #available(iOS 11.0, *) {
                return $0.view.safeAreaInsets
            } else {
                return .init(
                    top: $0.topLayoutGuide.length,
                    left: .zero,
                    bottom: $0.bottomLayoutGuide.length,
                    right: .zero
                )
            }
        }
}

iPhone 14 디바이스의 경우 다음과 같이 사용합니다.

let app = UIApplication.shared
var statusBarHeight: CGFloat = 0.0
let window = app.windows.filter {$0.isKeyWindow}.first
statusBarHeight = window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0
let topPadding = window?.safeAreaInsets.top ?? 0.0
statusBarHeight = statusBarHeight >= topPadding ? statusBarHeight:topPadding

여기 모든 아이폰의 안전 영역 높이를 찾는 간단한 답이 있습니다.

let window = UIApplication.shared.windows[0]

let SafeAreaHeight = window.safeAreaLayoutGuide.layoutFrame.size.height

언급URL : https://stackoverflow.com/questions/46829840/get-safe-area-inset-top-and-bottom-heights

반응형