Güvenli Alan Yerleşimini programlı olarak nasıl kullanırım?


104

Görünümlerimi oluşturmak için hikaye tahtaları kullanmadığım için, programlı olarak "Güvenli Alan Kılavuzlarını Kullan" seçeneğinin veya bunun gibi bir şeyin olup olmadığını merak ediyordum.

Görüşlerimi tutturmaya çalıştım

view.safeAreaLayoutGuide

ancak iPhone X simülatöründeki üst çentikle üst üste binmeye devam ediyorlar.


1
: Uygun bu konuda hiçbir belgelenmiş bool mülkiyet developer.apple.com/documentation/uikit/uiview/...
dvp.petrov

Nasıl olur view.safeAreaInsets? Bunu denedin mi
Karthikeyan Bose

@KarthikeyanBose evet maalesef şanssız yaptım.
Phillip

benim için çalışıyor. Kod neye benziyor
Daniel Springer

Yanıtlar:


160

Örnek kod (Referans: Güvenli Alan Yerleşimi Kılavuzu ):
Kodda kısıtlamalarınızı oluşturursanız, ilgili düzen bağlantılarını almak için UIView'ın safeAreaLayoutGuide özelliğini kullanın. Nasıl göründüğünü görmek için yukarıdaki Interface Builder örneğini kodda yeniden oluşturalım:

Görünüm denetleyicimizde bir özellik olarak yeşil görünüme sahip olduğumuzu varsayarsak:

private let greenView = UIView()

ViewDidLoad'dan çağrılan görünümleri ve kısıtlamaları ayarlamak için bir fonksiyonumuz olabilir:

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

Baştaki ve sondaki kenar boşluğu sınırlamalarını her zaman olduğu gibi kök görünümün layoutMarginsGuide kullanarak oluşturun:

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

Şimdi, iOS 11 ve sonraki sürümleri hedeflemiyorsanız, güvenli alan yerleşim kılavuzu kısıtlamalarını #available ile sarmalamanız ve önceki iOS sürümleri için üst ve alt düzen kılavuzlarına geri dönmeniz gerekecektir:

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)
   ])
}

Sonuç:

görüntü açıklamasını buraya girin

görüntü açıklamasını buraya girin


Güvenli Alan Yerleşimi Kılavuzu için Apple Geliştirici Resmi Belgeleri burada.


İPhone-X için kullanıcı arayüzü tasarımını işlemek için Güvenli Alan gereklidir. Güvenli Alan Yerleşimi kullanılarak iPhone-X için kullanıcı arabiriminin nasıl tasarlanacağına ilişkin temel yönergeyi burada bulabilirsiniz.


2
Bunu hedef-C'de de vermek mümkün müdür? Tam ihtiyacım olan şey gibi görünüyor
Tom Hammond

6
@TomHammond İşte sizin için Objective-C'de stackoverflow.com/a/47076040/5638630
Krunal

2
@ZonilyJame Şimdi sorgunuz hakkında - SaFeAreaLayout, iOS'a özgü bir çerçevedir (iPhoneX cihazına özgü değildir), iOS 11'deki Üst-Alt Düzen kılavuzunun yerini alıyor, bu nedenle iOS için değil, cihaz için koşul kullanmalı / ayarlamalıyız. SafeAreaLayout, tüm cihaz türleri (iPhone-X ve diğerleri) için tasarımlarla ilgilenir. Hala herhangi bir sorunuz / karışıklığınız varsa daha fazla ayrıntı isteyebilirsiniz.
Krunal

3
Harika. Teşekkür ederim :)
Rajamohan S

1
neden doğru cevap olarak kabul ediliyor? Somut bir konum kurmaya çalıştım - sonuç tamamen rastgele - kontrol tahmin edilemeyen bir konuma yerleştirildi!
Vyachaslav Gerchicov

86

Aslında bunun için bir uzantı kullanıyorum ve ios 11 olup olmadığını kontrol ediyorum.

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

Bu çok basit bir yol ve hile yapıyor. Fikir için teşekkürler.
alper_k

1
Bu, bunu yapmanın çok basit ama güzel bir yolu! Yerine kullanımına self.safeAreaLayoutGuidedikkat edin self.layoutMarginsGuide. Bu cevapta kullanılan güvenli olan, güvenli alanda kalmam için doğru çalıştı! Ben değiştirmeyi öneririm bir şey kullanmak olacaktır leadingAnchorve trailingAnchoryerine leftAnchorve rightAnchor. Bravo!
Pranoy C

22

SafeAreaLayoutGuideolduğu UIViewmülkiyet,

SafeAreaLayoutGuide'ın üst kısmı, görünümün engellenmemiş üst kenarını gösterir (örneğin, varsa durum çubuğunun veya gezinme çubuğunun arkasında değil). Diğer kenarlar için de benzer.

safeAreaLayoutGuideNesnelerimizin yuvarlatılmış köşelerden, gezinme çubuklarından, sekme çubuklarından, araç çubuklarından ve diğer ata görünümlerinden kırpılmasını / üst üste binmesini önlemek için kullanın .

safeAreaLayoutGuideSırasıyla nesne oluşturabilir ve nesne kısıtlamaları belirleyebiliriz.

Dikey + Yatay için Kısıtlamalar -

Dikey resim

Yatay resim

        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
viewDidAppearNe yaptığınızı kesinlikle bilmiyorsanız, içinde asla kurulum kısıtlamaları yapmayın . viewDidAppearbirden çok kez çağrılır ve bu nedenle, kısıtlamalarınız her çağrıldığında kopyalanır.
Yevhen Dubinin

Evet! , Düzenlenmiş cevap, kullanım durumunuz olarak kullanabilirsiniz.
Jack

14

SnapKit kullananlarınız için , tıpkı benim gibi, çözüm, kısıtlamalarınızı view.safeAreaLayoutGuideböyle bir yere sabitlemektir :

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
Mükemmel cevap. Biraz daha kompakt hale getirmek için şunu söyleyebilirsiniz: if #available (iOS 11.0, *) {make.edges.equalTo (view.safeAreaLayoutGuide.snp.margins)}
Don Miguel,

7

LayoutMarginsGuide'a baştaki ve sondaki kenar boşluğu kısıtlamaları eklemek yerine bunu kullanıyorum:

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]
                                          ]];

Lütfen Krunal'ın cevabına göre daha düşük ios 11 sürümü seçeneğini de kontrol edin.


Görünümünüzü zaten superView'e eklediğinizden emin olun. Kendi kodumda basit bir örnek olarak.
Tony TRAN

6

Kullanım UIWindowveya UIView'lersafeAreaInsets .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
Görünümünüz Otomatik Yerleşimi kullanmıyorsa gitmenin yolu budur.
Jonathan Cabrera

4

Görsel formatta kısıtlamalar kullanın ve güvenli alana ücretsiz olarak saygı duyun.

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))
    }
}

sonuç


2
Lütfen aşağı oylama sırasında bir yorum yapın, böylece bu tekniğin geçerli olmadığı bir durum olup olmadığını hepimiz öğrenebiliriz. Teşekkürler!
AtomicBoolean

Bu işe yarıyor, görsel format çözümlerini de seviyorum! Teşekkürler! Ancak bu, tüm ios sürümleri için çalışıyor mu?
PaFi

4

Objective-C için güvenli alan uzantısı

@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

çalışmıyor (Swift 4.2, iOS 12). Sonuç durum çubuğunu görmezden geliyor
Vyachaslav Gerchicov

2

Swift 4.2 ve 5.0. ViewBg'ye Önde Gelen, Sondaki, Üst ve Alt kısıtlamaları eklemek istediğinizi varsayalım. Yani aşağıdaki kodu kullanabilirsiniz.

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

Bu uzantı, bir UIVIew'i gözetim ve denetleme + güvenli alanıyla sınırlamanıza yardımcı olur:

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'i burada açıklandığı gibi kullanabilirsiniz https://www.raywenderlich.com/174078/auto-layout-visual-format-language-tutorial-2

kod örneği (raywenderlich.com'dan alınmıştır):

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-|
  """
...
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.