안전 영역 레이아웃을 프로그래밍 방식으로 사용하려면 어떻게합니까?


100

내 뷰를 만드는 데 스토리 보드를 사용하지 않기 때문에 프로그래밍 방식으로 "안전 영역 가이드 사용"옵션이 있는지 또는 그와 비슷한 것이 있는지 궁금합니다.

나는 내 견해를

view.safeAreaLayoutGuide

그러나 그들은 iPhone X 시뮬레이터의 최고 노치를 계속 겹칩니다.


1
:에 따라 이에 대한 문서화 부울 재산권 developer.apple.com/documentation/uikit/uiview/...
dvp.petrov

어때요 view.safeAreaInsets? 이거 해봤 어?
Karthikeyan Bose

@KarthikeyanBose 예, 불행히도 운이 없었습니다.
Phillip

나를 위해 작동합니다. 코드는 어떻게 생겼습니까
Daniel Springer

답변:


157

다음은 샘플 코드입니다 (참조 출처 : Safe Area Layout Guide ) :
코드에서 제약 조건을 생성하는 경우 UIView의 safeAreaLayoutGuide 속성을 사용하여 관련 레이아웃 앵커를 가져옵니다. 위의 인터페이스 빌더 예제를 코드로 다시 만들어서 어떻게 보이는지 살펴 보겠습니다.

뷰 컨트롤러의 속성으로 녹색 뷰가 있다고 가정합니다.

private let greenView = UIView()

viewDidLoad에서 호출되는 뷰와 제약 조건을 설정하는 함수가있을 수 있습니다.

private func setupView() {
  greenView.translatesAutoresizingMaskIntoConstraints = false
  greenView.backgroundColor = .green
  view.addSubview(greenView)
}

항상 루트 뷰의 layoutMarginsGuide를 사용하여 선행 및 후행 여백 제약 조건을 만듭니다.

 let margins = view.layoutMarginsGuide
 NSLayoutConstraint.activate([
    greenView.leadingAnchor.constraint(equalTo: margins.leadingAnchor),
    greenView.trailingAnchor.constraint(equalTo: margins.trailingAnchor)
 ])

이제 iOS 11 이상을 대상으로하지 않는 한 안전 영역 레이아웃 가이드 제약 조건을 #available으로 래핑하고 이전 iOS 버전의 경우 상단 및 하단 레이아웃 가이드로 대체해야합니다.

if #available(iOS 11, *) {
  let guide = view.safeAreaLayoutGuide
  NSLayoutConstraint.activate([
   greenView.topAnchor.constraintEqualToSystemSpacingBelow(guide.topAnchor, multiplier: 1.0),
   guide.bottomAnchor.constraintEqualToSystemSpacingBelow(greenView.bottomAnchor, multiplier: 1.0)
   ])
} else {
   let standardSpacing: CGFloat = 8.0
   NSLayoutConstraint.activate([
   greenView.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor, constant: standardSpacing),
   bottomLayoutGuide.topAnchor.constraint(equalTo: greenView.bottomAnchor, constant: standardSpacing)
   ])
}

결과:

여기에 이미지 설명 입력

여기에 이미지 설명 입력


다음은 안전 영역 레이아웃 가이드에 대한 Apple 개발자 공식 문서입니다.


iPhone-X의 사용자 인터페이스 디자인을 처리하려면 Safe Area가 필요합니다. 다음은 안전 영역 레이아웃을 사용하여 iPhone-X 용 사용자 인터페이스를 디자인하는 방법에 대한 기본 지침입니다.


2
객관적인 C에서도 이것을 줄 수 있습니까? 내가 필요한 것처럼 보이는
톰 해먼드

6
@TomHammond 여기에 Objective-C가 있습니다. stackoverflow.com/a/47076040/5638630
Krunal

2
@ZonilyJame 이제 쿼리에 대해-SaFeAreaLayout은 iOS 전용 프레임 워크 (기기 iPhoneX 전용 아님)이며 iOS 11의 Top-Bottom Layout 가이드를 대체하므로 기기가 아닌 iOS에 대한 조건을 사용 / 설정해야합니다. SafeAreaLayout은 모든 유형의 장치 (iPhone-X 및 기타)에 대한 디자인을 처리합니다. 여전히 질문 / 혼란이 있으면 저에게 더 자세한 정보를 요청할 수 있습니다.
Krunal

3
대박. 감사합니다 :)
Rajamohan S

1
정답으로 인정되는 이유는 무엇입니까? 저는 구체적인 위치를 설정하려고했습니다. 결과는 완전히 무작위입니다. 컨트롤은 예측할 수없는 위치에 배치됩니다!
Vyachaslav Gerchicov

83

실제로 확장 프로그램을 사용하고 있으며 iOS 11인지 여부를 제어하고 있습니다.

extension UIView {

  var safeTopAnchor: NSLayoutYAxisAnchor {
    if #available(iOS 11.0, *) {
      return self.safeAreaLayoutGuide.topAnchor
    }
    return self.topAnchor
  }

  var safeLeftAnchor: NSLayoutXAxisAnchor {
    if #available(iOS 11.0, *){
      return self.safeAreaLayoutGuide.leftAnchor
    }
    return self.leftAnchor
  }

  var safeRightAnchor: NSLayoutXAxisAnchor {
    if #available(iOS 11.0, *){
      return self.safeAreaLayoutGuide.rightAnchor
    }
    return self.rightAnchor
  }

  var safeBottomAnchor: NSLayoutYAxisAnchor {
    if #available(iOS 11.0, *) {
      return self.safeAreaLayoutGuide.bottomAnchor
    }
    return self.bottomAnchor
  }
}

아주 간단한 방법이며 트릭을 수행합니다. 아이디어 주셔서 감사합니다.
alper_k

이것은 간단하지만 좋은 방법입니다! 사용 주 self.safeAreaLayoutGuide대신을 self.layoutMarginsGuide. 이 답변에 사용 된 안전한 것은 안전 영역에 머물 수 있도록 올바르게 작동했습니다! 내가 변경 제안 한 가지 사용하는 것 leadingAnchortrailingAnchor대신 leftAnchorrightAnchor. 브라보!
Pranoy C

22

SafeAreaLayoutGuideUIView속성은,

safeAreaLayoutGuide의 상단은 뷰의 가려지지 않은 상단 가장자리를 나타냅니다 (예 : 상태 표시 줄 또는 탐색 표시 줄 (있는 경우) 뒤가 아님). 다른 모서리도 비슷합니다.

safeAreaLayoutGuide둥근 모서리, 탐색 모음, 탭 모음, 도구 모음 및 기타 조상보기에서 개체 클리핑 / 겹침을 방지하는 데 사용 합니다.

safeAreaLayoutGuide객체 를 생성하고 객체 제약을 설정할 수 있습니다 .

세로 + 가로의 제약 조건은-

세로 이미지

풍경 이미지

        self.edgesForExtendedLayout = []//Optional our as per your view ladder

        let newView = UIView()
        newView.backgroundColor = .red
        self.view.addSubview(newView)
        newView.translatesAutoresizingMaskIntoConstraints = false
        if #available(iOS 11.0, *) {
            let guide = self.view.safeAreaLayoutGuide
            newView.trailingAnchor.constraint(equalTo: guide.trailingAnchor).isActive = true
            newView.leadingAnchor.constraint(equalTo: guide.leadingAnchor).isActive = true
            newView.topAnchor.constraint(equalTo: guide.topAnchor).isActive = true
            newView.heightAnchor.constraint(equalToConstant: 100).isActive = true

        }
        else {
            NSLayoutConstraint(item: newView, attribute: .top, relatedBy: .equal, toItem: view, attribute: .top, multiplier: 1.0, constant: 0).isActive = true
            NSLayoutConstraint(item: newView, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1.0, constant: 0).isActive = true
            NSLayoutConstraint(item: newView, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1.0, constant: 0).isActive = true

            newView.heightAnchor.constraint(equalToConstant: 100).isActive = true
        }

UILayoutGuide

safeAreaLayoutGuide


2
viewDidAppear수행중인 작업을 절대적으로 알지 않는 한 에서 설정 제약 조건을 절대 수행하지 마십시오 . viewDidAppear여러 번 호출되므로 호출 될 때마다 제약 조건이 복제됩니다.
Yevhen Dubinin

예! , 수정 된 답변, 사용 사례로 사용할 수 있습니다.
Jack

14

나처럼 SnapKit 을 사용하는 사람들에게 솔루션은 제약 조건을 다음 view.safeAreaLayoutGuide과 같이 고정하는 것입니다.

yourView.snp.makeConstraints { (make) in
    if #available(iOS 11.0, *) {
        //Bottom guide
        make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottomMargin)
        //Top guide
        make.top.equalTo(view.safeAreaLayoutGuide.snp.topMargin)
        //Leading guide
        make.leading.equalTo(view.safeAreaLayoutGuide.snp.leadingMargin)
        //Trailing guide
        make.trailing.equalTo(view.safeAreaLayoutGuide.snp.trailingMargin)

     } else {
        make.edges.equalToSuperview()
     }
}

1
좋은 대답입니다. 좀 더 간결하게 만들려면 다음과 같이 말할 수 있습니다. if #available (iOS 11.0, *) {make.edges.equalTo (view.safeAreaLayoutGuide.snp.margins)}
Don Miguel

7

layoutMarginsGuide에 선행 및 후행 여백 제약 조건을 추가하는 대신 이것을 사용하고 있습니다.

UILayoutGuide *safe = self.view.safeAreaLayoutGuide;
yourView.translatesAutoresizingMaskIntoConstraints = NO;
[NSLayoutConstraint activateConstraints:@[
                                           [safe.trailingAnchor constraintEqualToAnchor:yourView.trailingAnchor],
                                           [yourView.leadingAnchor constraintEqualToAnchor:safe.leadingAnchor],
                                           [yourView.topAnchor constraintEqualToAnchor:safe.topAnchor],
                                           [safe.bottomAnchor constraintEqualToAnchor:yourView.bottomAnchor]
                                          ]];

Krunal의 답변에서 ios 11의 하위 버전에 대한 옵션도 확인하십시오.


이미 yourView를 superView에 추가했는지 확인하십시오. 그것은 self.view 내 코드에서 간단한 예입니다.
Tony TRAN

6

사용 UIWindow또는 UIViewsafeAreaInsets .bottom .top .left .right

// #available(iOS 11.0, *)
// height - UIApplication.shared.keyWindow!.safeAreaInsets.bottom

// On iPhoneX
// UIApplication.shared.keyWindow!.safeAreaInsets.top =  44
// UIApplication.shared.keyWindow!.safeAreaInsets.bottom = 34

// Other devices
// UIApplication.shared.keyWindow!.safeAreaInsets.top =  0
// UIApplication.shared.keyWindow!.safeAreaInsets.bottom = 0

// example
let window = UIApplication.shared.keyWindow!
let viewWidth = window.frame.size.width
let viewHeight = window.frame.size.height - window.safeAreaInsets.bottom
let viewFrame = CGRect(x: 0, y: 0, width: viewWidth, height: viewHeight)
let aView = UIView(frame: viewFrame)
aView.backgroundColor = .red
view.addSubview(aView)
aView.autoresizingMask = [.flexibleWidth, .flexibleHeight]

3
뷰가 AutoLayout을 사용하지 않는 경우 이것이 갈 방법입니다.
Jonathan Cabrera

4

시각적 형식에 제약 조건을 사용하면 무료로 안전 영역을 존중받을 수 있습니다.

class ViewController: UIViewController {

    var greenView = UIView()

    override func viewDidLoad() {
        super.viewDidLoad()
        greenView.backgroundColor = .green
        view.addSubview(greenView)
    }
    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()

        greenView.translatesAutoresizingMaskIntoConstraints = false
        let views : [String:Any] = ["greenView":greenView]
        view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-[greenView]-|", options: [], metrics: nil, views: views))
        view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-[greenView]-|", options: [], metrics: nil, views: views))
    }
}

결과


2
이 기술이 적용되지 않는 경우가 있는지 모두 알 수 있도록 하향 투표 할 때 의견을 제공하십시오. 감사!
AtomicBoolean

이것은 효과가 있으며 시각적 형식 솔루션도 좋아합니다! 감사! 그러나 이것은 모든 iOS 버전에서 작동합니까?
PaFi

4

Objective-C의 안전 영역 확장

@implementation UIView (SafeArea)

- (NSLayoutAnchor *)safeTopAnchor{

    if (@available(iOS 11.0, *)){
        return self.safeAreaLayoutGuide.topAnchor;
    } else {
        return self.topAnchor;
    }

}


- (NSLayoutAnchor *)safeBottomAnchor{

    if (@available(iOS 11.0, *)) {
        return self.safeAreaLayoutGuide.bottomAnchor;
    } else {
        return self.bottomAnchor;
    }

}

@end

작동하지 않습니다 (Swift 4.2, iOS 12). 결과 무시 상태 표시 줄
Vyachaslav Gerchicov

2

Swift 4.2 및 5.0. viewBg에 선행, 후행, 상단 및 하단 제약 조건을 추가한다고 가정합니다. 따라서 아래 코드를 사용할 수 있습니다.

let guide = self.view.safeAreaLayoutGuide
viewBg.trailingAnchor.constraint(equalTo: guide.trailingAnchor).isActive = true
viewBg.leadingAnchor.constraint(equalTo: guide.leadingAnchor).isActive = true
viewBg.topAnchor.constraint(equalTo: guide.topAnchor).isActive = true
viewBg.bottomAnchor.constraint(equalTo: guide.bottomAnchor).isActive = true

1

이 확장은 UIVIew를 superview 및 superview + safeArea로 제한하는 데 도움이됩니다.

extension UIView {

    ///Constraints a view to its superview
    func constraintToSuperView() {
        guard let superview = superview else { return }
        translatesAutoresizingMaskIntoConstraints = false

        topAnchor.constraint(equalTo: superview.topAnchor).isActive = true
        leftAnchor.constraint(equalTo: superview.leftAnchor).isActive = true
        bottomAnchor.constraint(equalTo: superview.bottomAnchor).isActive = true
        rightAnchor.constraint(equalTo: superview.rightAnchor).isActive = true
    }

    ///Constraints a view to its superview safe area
    func constraintToSafeArea() {
        guard let superview = superview else { return }
        translatesAutoresizingMaskIntoConstraints = false

        topAnchor.constraint(equalTo: superview.safeAreaLayoutGuide.topAnchor).isActive = true
        leftAnchor.constraint(equalTo: superview.safeAreaLayoutGuide.leftAnchor).isActive = true
        bottomAnchor.constraint(equalTo: superview.safeAreaLayoutGuide.bottomAnchor).isActive = true
        rightAnchor.constraint(equalTo: superview.safeAreaLayoutGuide.rightAnchor).isActive = true
    }

}

0

https://www.raywenderlich.com/174078/auto-layout-visual-format-language-tutorial-2에 설명 된대로 view.safeAreaInsets 를 사용할 수 있습니다.

코드 샘플 (raywenderlich.com에서 가져옴) :

override func viewSafeAreaInsetsDidChange() {
  super.viewSafeAreaInsetsDidChange()

  if !allConstraints.isEmpty {
    NSLayoutConstraint.deactivate(allConstraints)
    allConstraints.removeAll()
  }

  let newInsets = view.safeAreaInsets
  let leftMargin = newInsets.left > 0 ? newInsets.left : Metrics.padding
  let rightMargin = newInsets.right > 0 ? newInsets.right : Metrics.padding
  let topMargin = newInsets.top > 0 ? newInsets.top : Metrics.padding
  let bottomMargin = newInsets.bottom > 0 ? newInsets.bottom : Metrics.padding

  let metrics = [
    "horizontalPadding": Metrics.padding,
    "iconImageViewWidth": Metrics.iconImageViewWidth,
    "topMargin": topMargin,
    "bottomMargin": bottomMargin,
    "leftMargin": leftMargin,
    "rightMargin": rightMargin]
}


let views: [String: Any] = [
  "iconImageView": iconImageView,
  "appNameLabel": appNameLabel,
  "skipButton": skipButton,
  "appImageView": appImageView,
  "welcomeLabel": welcomeLabel,
  "summaryLabel": summaryLabel,
  "pageControl": pageControl]

let iconVerticalConstraints = NSLayoutConstraint.constraints(
  withVisualFormat: "V:|-topMargin-[iconImageView(30)]",
  metrics: metrics,
  views: views)
allConstraints += iconVerticalConstraints

let topRowHorizontalFormat = """
  H:|-leftMargin-[iconImageView(iconImageViewWidth)]-[appNameLabel]-[skipButton]-rightMargin-|
  """
...
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.