プログラムでセーフエリアレイアウトを使用するにはどうすればよいですか?


99

私はストーリーボードを使用してビューを作成していないので、プログラムで[セーフエリアガイドを使用する]オプションがあるのか​​、またはそのようなものがあるのか​​と思いました。

私は自分の意見を

view.safeAreaLayoutGuide

しかし、それらはiPhone Xシミュレーターのトップノッチと重複し続けます。



いかがview.safeAreaInsetsですか?やってみましたか?
Karthikeyan Bose

@KarthikeyanBoseはい、残念ながら運がありませんでした。
Phillip

私のために働く。コードはどのように見えるか
Daniel Springer

回答:


155

次にサンプルコードを示します(参照:セーフエリアレイアウトガイド):
コードで制約を作成する場合は、UIViewのsafeAreaLayoutGuideプロパティを使用して、関連するレイアウトアンカーを取得します。上記のInterface Builderの例をコードで再作成して、どのように見えるかを見てみましょう。

ビューコントローラーのプロパティとして緑のビューがあると仮定します。

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 Developer公式ドキュメントはこちらです


iPhone-Xのユーザーインターフェイス設計を処理するには、セーフエリアが必要です。セーフエリアレイアウトを使用してiPhone-Xのユーザーインターフェイスを設計する方法の基本的なガイドラインは次のとおりです


2
これをobjective-Cでも与えることは可能でしょうか?それは私が必要としているもののように見えます
トムハモンド

6
@TomHammondこれがObjective-Cの例ですstackoverflow.com/a/47076040/5638630
Krunal

2
@ZonilyJameクエリについて-SaFeAreaLayoutはiOS固有のフレームワーク(デバイスiPhoneX固有ではありません)です。これはiOS 11のトップ-ボトムレイアウトガイドに代わるものであるため、デバイスではなくiOSの条件を使用/設定する必要があります。SafeAreaLayoutは、あらゆるタイプのデバイス(iPhone-Xなど)の設計を処理します。それでもクエリ/混乱がある場合は、詳細を尋ねることができます。
Krunal 2017

3
驚くばかり。ありがとうございます:)
ラジャモハンS

1
なぜそれが正解として受け入れられるのですか?具体的な位置を設定しようとしました-結果は完全にランダムです-コントロールが予測できない位置に配置されています!
Vyachaslav Gerchicov

82

私は実際に拡張機能を使用していて、それが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。この回答で使用された安全なものは、私が安全な領域内に留まるために正しく機能しました!変更を提案する1つのことはleadingAnchor、およびのtrailingAnchor代わりにleftAnchorおよびを使用することrightAnchorです。ブラボー!
Pranoy C、

22

SafeAreaLayoutGuideあるUIViewプロパティは、

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 2017年

はい!、編集された回答、あなたのユースケースとして使用できます。
ジャック

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
すばらしい答えです。それはもう少しコンパクトにあなたが言うことができるようにするには:#available場合(iOSの11.0、*){make.edges.equalTo(view.safeAreaLayoutGuide.snp.margins)}
ドン・ミゲル

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の下位バージョンのオプションも確認してください。


superViewにyourViewがすでに追加されていることを確認してください。簡単な例として、私のコードではself.viewです。
Tony TRAN

6

UIWindowまたはUIViewの使用safeAreaInsets .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
これは、ビューがオートレイアウトを使用していない場合の方法です。
ジョナサンカブレラ

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 2018

これは機能します。ビジュアルフォーマットソリューションも好きです。ありがとう!しかし、これはすべての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にLeading、Trailing、Top、Bottomの制約を追加したいとします。したがって、以下のコードを使用できます。

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 + 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

ここで説明されているように、view.safeAreaInsetsを使用できますhttps://www.raywenderlich.com/174078/auto-layout-visual-format-language-tutorial-2

コードサンプル(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.