web-dev-qa-db-ja.com

iOS 11セーフエリアレイアウトガイド後方互換性

セーフエリアレイアウトガイドを有効にすると、11以下のiOSと互換性がありますか?

enter image description here

58
Ted

私はどうにかして新しいセーフエリアのレイアウトガイドを扱い、iOS 9とiOS 10との後方互換性を維持しています。(編集:@NickEntinによるコメントで指摘されているように、この実装はステータスバーが表示されますが、これはiPhone Xの横長の風景には当てはまりませんが、上部のスペースを最大にすると(20ポイント)、問題なく実行できます

例えば。ステータスバーの10ポイント下(およびiPhone Xのセンサーハウジングの10ポイント下)に表示する場合は、次のようにします。

  1. XIBで、File Inspectorに移動し、Use Safe Area Layout Guidesをチェックして金庫を有効にします。
  2. >=(以上)制約、定数30(高さ20ポイントのステータスバーに対して10ポイントの間隔が必要であるため)、および優先順位High(750)を使用して、ビューの上からメインビューの上への制約を作成します。
  3. =(equal)制約、定数10およびpriority Low(250)を使用して、ビューの上からセーフエリアの上までの制約を作成します。

下部のビュー(およびセーフエリアの先頭/末尾または左/右)でも同じことができます。

  1. XIBで、File Inspectorに移動し、Use Safe Area Layout Guidesをチェックして金庫を有効にします。
  2. >=(以上)制約、定数10および優先度High(750)を使用して、ビューの下からメインビューの下までの制約を作成します。
  3. =(equal)制約、定数10およびpriority Low(250)を使用して、ビューの下からセーフエリアの下までの制約を作成します。
52
thijsonline

IOS 9およびiOS 10用のSafe Areasの下位互換性は、ストーリーボードを使用している場合にのみ機能します。 xibを使用している場合は、使用するレイアウトガイドはありません。 https://forums.developer.Apple.com/thread/87329

回避策はどちらかと思われます

(a)xibをストーリーボードに移行する。

(b)プログラム的にいくつかの制約を追加する。

(a)が本当に選択肢ではない場合、手動のアプローチは次のようになります。

あなたの安全な領域内(つまりステータスバーやナビゲーションバーの下)に表示したいビューがxibにあるとします。

  1. ビューとiOS 11の安全な領域の間にxibで制約を追加します。一番上の制約を優先度750に割り当てます。

    add a top constraint

  2. View Controllerで、プロパティを追加します。

    @property (nonatomic, strong) NSLayoutConstraint *topLayoutConstraint;
    

    そしてviewDidLayoutSubviewsで:

    - (void)viewDidLayoutSubviews {
        [super viewDidLayoutSubviews];
    
        if (@available(iOS 11, *)) {
            // safe area constraints already set
        }
        else {
            if (!self.topLayoutConstraint) {
                self.topLayoutConstraint = [self.<yourview>.topAnchor constraintEqualToAnchor:self.topLayoutGuide.bottomAnchor];
                [self.topLayoutConstraint setActive:YES];
            }
        }
    }
    

    新しい制約はiOS 9とiOS 10に対してのみ作成され、デフォルトの優先順位は1000で、xibのものより優先されます。

  3. ホーム指標を回避する必要がある場合は、下側の拘束に対して繰り返します。

Swift 4バージョン:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    if #available(iOS 11, *) {
        // safe area constraints already set
    } else {
        if topLayoutConstraint == nil {
            topLayoutConstraint = <yourview>.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor)
            topLayoutConstraint?.isActive = true
        }
    }
}
44
Dobster

私がXcode 9 GMで観察したiOS 11の安全領域制限との少なくとも1つの後方互換性の問題があります - 安全な領域制限のあるView Controller。

ナビゲーションバーが非表示になっているときにセーフエリアの上部が制限されたビューをプッシュすると、プッシュされたビューはiOS 9および10のステータスバーと重なります。

ナビゲーションバーが表示されていて、「トップバーの下」が無効になっている場合でも、プッシュされたビューはナビゲーションバーの下にスライドして画面の一番上に移動します。ナビゲーションバーは正しく配置されています。

IOS 11では、どちらの場合もレイアウトは正しくなります。

これは簡単な例です: http://www.filedropper.com/foobar

そして、これはnavバーを隠した状態のビデオです(左側のiOS 10.3、右側のiOS 11): https://vimeo.com/234174841/1e27a96a87

ナビゲーションバーが表示されるバージョンは次のとおりです(ペン先で有効)。 https://vimeo.com/234316256/f022132d57

私はこれをレーダーとして登録しました#34477706。

ナビゲーションバーの表示例を指摘してくれた @ Sander に感謝します。

18
clarus

ストーリーボードなしでxibを使用する場合、それらはios 10に関するレイアウトガイドを持っていません。後方互換性を持たせるためにxibをストーリーボードに移動してください。

7
ihar

はい、あなたのプロジェクト/アプリは問題なくiOS 11より前のiOSバージョンで動作します。 11より前のiOSバージョンでは、Safe Area Layoutを通常のAutoLayoutに置き換えたり考慮したりして、Rules of TopとBottomのレイアウトガイドに従っています。

私は既存のプロジェクトを 'SafeAreaLayout'の有無にかかわらず両方のプラットフォーム(iOS 11と後方iOS 10)でテストしました。それはうまくいっています。

確認してください。

  • プロジェクト/ユーザーインターフェースをオートレイアウトで設計した場合あなたのUIElementの制約は、(スーパービューではなく)トップとボトムのレイアウトガイドに従います。だからSafeAreaLayoutオプションをシングルクリック(有効にする)することで、あなたのストーリーボードのすべてのInterface BuildersファイルにSafeAreaレイアウトを自動的に正しく実装するでしょう。

  • SafeAreaLayoutでプロジェクト/ユーザーインターフェースを設計した場合それからそれは自動的に後方iOSの上と下のレイアウトガイドに従います。

これが結果のサンプルスナップショットです。セーフエリアレイアウトを有効または無効にしても、既存のデザインには影響しません。

セーフエリアレイアウト:enter image description here

自動レイアウト

enter image description here

簡単に言うと、あなたの質問に対する答えは、「11より前のiOSと互換性のあるセーフエリアレイアウトガイドの有効化」です。

プロジェクト/アプリにセーフエリアレイアウトを実装できます。セーフエリアレイアウトを上部レイアウトおよび下部レイアウトに変換することで、以前のiOSバージョンで正常に機能します。

7
Krunal

Objective-Cでこれを使用していましたが、iOS 10で良い結果が得られました。xibでSafeAreaを使用する場合は、viewDidLoadを追加します。

if (@available(iOS 11.0, *)) {}
else {
    self.edgesForExtendedLayout = UIRectEdgeNone;
}
4
Dmitry A.

私はあなたがあなたのNSLayoutConstraintに固定されているsafeAreaをサブクラス化するだけでよいもっと便利な方法を見つけました。

あなたはUIViewからViewControllerを入手しなければならないのでちょっと厄介ですが、私の意見では、それはAppleがXibsのsafeAreaのための下位互換性を最終的に修正するまでは簡単で良い方法です。

サブクラス:

class SafeAreaBackwardsCompatabilityConstraint: NSLayoutConstraint {
private weak var newConstraint: NSLayoutConstraint?

override var secondItem: AnyObject? {
    get {
        if #available(iOS 11.0, *) {}
        else {
            if let vc = (super.secondItem as? UIView)?.parentViewController, newConstraint == nil {
                newConstraint = (self.firstItem as? UIView)?.topAnchor.constraint(equalTo: vc.topLayoutGuide.bottomAnchor)
                newConstraint?.isActive = true
                newConstraint?.constant = self.constant
            }
        }
        return super.secondItem
    }
}

override var priority: UILayoutPriority {
    get {
        if #available(iOS 11.0, *) { return super.priority }
        else { return 750 }
    }
    set { super.priority = newValue }
}
}

private extension UIView {
var parentViewController: UIViewController? {
    var parentResponder: UIResponder? = self
    while parentResponder != nil {
        parentResponder = parentResponder!.next
        if let viewController = parentResponder as? UIViewController {
            return viewController
        }
    }
    return nil
}
}

Xib:

enter image description here

3
iVentis

「セーフエリアレイアウトガイド」は後方互換性があります。まあ、あなたがxibでそれを使わない限り。ストーリーボードでは大丈夫そうです。

私は自分のビューの一番上にある最初のオブジェクトから "Top layout constraint"にアクセスすることで問題を解決しました。

@property (weak, nonatomic) IBOutlet NSLayoutConstraint *topLayoutConstraint;

それから、Constant値をその制約に変更してビューを更新します。たとえば、ナビゲーションバー(高さ44)とステータスバー(高さ20)を使用すると、次のようになります。

if (SYSTEM_VERSION_LESS_THAN(@"11.0")) {
    _topLayoutConstraint.constant = 64;
    [self.view layoutIfNeeded];
}

そのように定義されているSYSTEM_VERSION_LESS_THANの場合:

#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
3
gduh

IOS 9上のWKWebView&Safe Areaとの下位互換性の問題があります。何らかの理由で、WKWebViewは単にセーフエリアレイアウト設定を無視します。

2
Nik

Objective-Cでは、iPhone-Xの場合、上下の余白が表示されます。

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

    NSLayoutConstraint *bottomConstraint   = [NSLayoutConstraint constraintWithItem:self.childView
                                                                              attribute:NSLayoutAttributeBottom
                                                                              relatedBy:NSLayoutRelationEqual
                                                                                 toItem:self.parentView.safeAreaLayoutGuide
                                                                              attribute:NSLayoutAttributeBottom
                                                                             multiplier:1.0
                                                                               constant:0];


    NSLayoutConstraint *topConstraint   = [NSLayoutConstraint constraintWithItem:self.childView
                                                                       attribute:NSLayoutAttributeTop
                                                                       relatedBy:NSLayoutRelationEqual
                                                                          toItem:self.parentView.safeAreaLayoutGuide
                                                                       attribute:NSLayoutAttributeTop
                                                                      multiplier:1.0
                                                                        constant:0];


} else {

    NSLayoutConstraint *bottomConstraint   = [NSLayoutConstraint constraintWithItem:self.childView
                                                                          attribute:NSLayoutAttributeBottom
                                                                          relatedBy:NSLayoutRelationEqual
                                                                             toItem:self.parentView
                                                                          attribute:NSLayoutAttributeBottom
                                                                         multiplier:1.0
                                                                           constant:0];


    NSLayoutConstraint *topConstraint   = [NSLayoutConstraint constraintWithItem:self.childView
                                                                       attribute:NSLayoutAttributeTop
                                                                       relatedBy:NSLayoutRelationEqual
                                                                          toItem:self.parentView
                                                                       attribute:NSLayoutAttributeTop
                                                                      multiplier:1.0
                                                                        constant:0];

}
2
Chandan

すべてのViewControllerが拡張する汎用ViewControllerがある場合、別の解決策は調整する項目をIBOutletCollectionに配置し、そのGenericViewControllerでプログラム的に調整することです。これが私のコードです:

@IBOutlet var adjustTopSpaceViews: [UIView]?

override func viewDidLoad() {
    super.viewDidLoad()
    adjustViews()
    ....
}

func adjustViews() {
    guard let views = adjustTopSpaceViews,
        ProcessInfo.processInfo.operatingSystemVersion.majorVersion < 11 else {
            return
    }
    let statusBarHeight = UIApplication.shared.statusBarFrame.height
    for subview in views {
        subview.superview?.constraints.filter({ (constraint) -> Bool in
            return constraint.firstAttribute == .top
                && constraint.secondAttribute == .top
                && (constraint.firstItem as? UIView == subview || constraint.secondItem as? UIView == subview)
        }).forEach({ (constraint) in
            constraint.constant += (constraint.firstItem as? UIView == subview) ? statusBarHeight : -statusBarHeight
        })
    }
}
2
Youssef MAHERZI

これが私のプロジェクトでやったことです

私の場合、私のtopConstraintbottomConstraintsは両方とも@IBOutletsです。これはiOS 8とも互換性があります。

上と下の制約に対する私の初期設定は通常のiPhone用で、これが私がiPhone Xのための制約を編集するだけの理由です

    // iOS 11 Layout Fix. (For iPhone X)
    if #available(iOS 11, *) {
        self.topConstraint.constant = self.topConstraint.constant + self.view.safeAreaInsets.top

        self.bottomConstraint.constant = self.bottomConstraint.constant + self.view.safeAreaInsets.bottom
    }

注:self.viewがあなたのsuperViewなので、私はsafeAreaInsetsに使っています。

2
Zonily Jame

これが私のiOS 9からiOS 11+へのSwift 4 +でのソリューションラッパーです

    let safeAreaTopAnchor:NSLayoutYAxisAnchor?
    if #available(iOS 11.0, *) {
        safeAreaTopAnchor = contentView.safeAreaLayoutGuide.topAnchor
    } else {
        // Fallback on earlier versions

        var parentViewController: UIViewController? {
            var parentVCResponder: UIResponder? = self
            while parentVCResponder != nil {
                parentVCResponder = parentVCResponder!.next
                if let viewController = parentVCResponder as? UIViewController {
                    return viewController
                }
            }
            return nil
        }

        safeAreaTopAnchor = parentViewController?.topLayoutGuide.bottomAnchor

    }
1