iPhoneXのレイアウトで気をつけた３つのこと

雑です。具体的な対応とかはもっといいやり方があったら教えたいただけると助かります :bow_tone1:

# 目次

- 最初に
- LaunchImageにiPhoneX用の画像が追加された
- StatusBarの高さが変わった
- 画面下部にSafeAreaInsetが追加された
- おまけ

※上記以外にもいろいろありますが、僕は上記さえわかればひとまず大丈夫でした。

# 最初に

Storyboard上のBottomLayoutGuideとTopLayoutGuideはUIView.safeAreaLayoutGuideだからdeprecatedじゃないらしい(あってる？）
https://forums.developer.apple.com/thread/79400

正直、Storyboard上のTopLayoutGuide、BottomLayoutGuideとSuperView.top,SuperView.bottomを使えるようになればiPhoneX対応は楽です。めっちゃいい記事がQiitaにあったのですが、探せないので見つけたら貼ります...

# LaunchImageにiPhoneX用の画像が追加された

<img width="908" alt="スクリーンショット 2017-10-23 19.54.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/70276/31e97dd5-bc39-dbca-e6ca-84ba40a54648.png">

iPhoneX用の画像を設定すると、全画面表示になるので、iPhoneXに対応したっぽくなります。
iPhoneX用のLaunchImageを用意しないと上下に黒い余白ができ、今までの端末と同じエリアしか使われないです。
ただ、StoryboardでLaunchScreenを設定している場合は気にしなくて大丈夫だと思います(自動的にAutoLayoutが良い感じにしてくれます)

# StatusBarの高さが変わった

|before|after|
|---|---|
|<img width="235" alt="スクリーンショット 2017-10-23 20.56.58.png" src="https://qiita-image-store.s3.amazonaws.com/0/70276/9b813a4e-a91d-7fe7-d3e0-ca94872ba238.png">|<img width="229" alt="スクリーンショット 2017-10-23 20.57.22_2.png" src="https://qiita-image-store.s3.amazonaws.com/0/70276/cc66f2b6-22b2-d280-b3b0-02a389a905fc.png">|

今までは基本的に20ptだったStatusBarが〇〇ptになりました。
そのため、固定で20ptを使っていた場合や、NavigationBarと合わせて64ptを固定値として使っていた場合には表示が崩れます。(NavigationBarの高さは44ptで変わっていないようです)
コードの場合は固定値ではなく、下記のPropertyを参照するように修正します。

```Swift
UIApplication.shared.statusBarFrame.height
```

Storyboard(IB)の場合は下記のように、StatusBarの高さの調整はコード上で行ったらいいと思います。
ただし、今までStatusbar+NavigationBarの高さ分の64ptで高さを指定していた場合は、StatusBar分の高さを引いて、44ptに指定し直さないといけません。(Storyboard上の見た目は崩れますがしょうがないです)

```Swift
@IBOutlet weak var NavigationBarViewHeightConstraint: NSLayoutConstraint! {
    willSet {
        newValue.constant += UIApplication.shared.statusBarFrame.height
        //      44        +=     20  or 44
    }
}
```

上記の方法で自作NavigationBarに適用する場合はConstraintを下記のようにして、NavigationBarのHeightConstraintのConstantを変化させることで対応するといいと思います。
NavigationBar上の要素は下からの位置で制約をつけてください。

<img width="1024" alt="スクリーンショット 2017-10-23 20.34.33.png" src="https://qiita-image-store.s3.amazonaws.com/0/70276/31e4beee-d0d7-b774-cc1e-8161e10ea87a.png">

# 画面下部にSafeAreaInsetが追加された

|before|after|
|---|---|
|<img width="235" alt="スクリーンショット 2017-10-23 21.04.29.png" src="https://qiita-image-store.s3.amazonaws.com/0/70276/9fde161d-cb32-9960-2596-d761f27a6e37.png">|<img width="229" alt="スクリーンショット 2017-10-23 20.57.22.png" src="https://qiita-image-store.s3.amazonaws.com/0/70276/bb12cde2-d71b-0eb7-b3a9-7d65a30c07b0.png">|

iOS11から、SafeAreaInsetというものが登場します。SafeAreaの周りの余白です。この部分ではGestureはできないものと思った方がいいです。ただし、この部分を隠したりするのはだめで、あくまで全画面に見えるようにしろとのことです。
iPhoneXの場合はSafeAreaInsets.bottomが34ptあり、既存端末では0ptです。
そのため、下記のようなメソッドを準備すると便利です。

```Swift
static let safeAreaBottomInset: CGFloat = {
    if #available(iOS 11.0, *) {
        return UIApplication.shared.keyWindow?.rootViewController?.view.safeAreaInsets.bottom ?? 0
    } else {
        return 0
    }
}()
```

下記、上記のメソッドを使用した具体的な対応方法になります。

## 例えば画面下部までTableViewの場合

下記のようにtableFooterViewにsafeAreaInsets.bottom分だけの余白Viewを入れることで、最後のセルがSafeAreaInsetにかぶらないようにします。

<img width="300" alt="スクリーンショット 2017-10-23 21.43.03.png" src="https://qiita-image-store.s3.amazonaws.com/0/70276/6848b834-7a3d-746c-6899-5b7169438399.png">

```Swift
class TableViewRespondIphoneX: UITableView {
    
    override init(frame: CGRect, style: UITableViewStyle) {
        super.init(frame: frame, style: style)<img width="545" alt="スクリーンショット 2017-10-23 21.51.41.png" src="https://qiita-image-store.s3.amazonaws.com/0/70276/2e7d0ef9-353b-c5fe-f0c2-bf3548479da3.png">

        
        self.commonInit()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        
        self.commonInit()
    }
    
    private func commonInit() {
        // １回しか呼ばれない&viewDidLoadの後に実行したいのでasyncしてます
        DispatchQueue.main.async {
            self.tableFooterView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: safeAreaBottomInset))
        }
    }
}
```

## 画面下部にボタンとか置く場合

<img width="300" alt="スクリーンショット 2017-10-23 22.23.50.png" src="https://qiita-image-store.s3.amazonaws.com/0/70276/cf5ede11-4940-be99-b7f6-6935d442826b.png">

Storyboard上で、SuperView.Bottomに紐付けるのでなく、BottomLayoutGuide.Topに紐付けるようにします。
そうすると、SafeAreaのBottomからの距離でLayoutできます。

<img width="1032" alt="スクリーンショット 2017-10-23 22.27.43.png" src="https://qiita-image-store.s3.amazonaws.com/0/70276/c3183636-cb76-44fb-9ac1-95a95cd288db.png">


# おまけ(iPhoneXの判定)

>
>```Swift
>    static let isIphoneX: Bool = {
>        // iPhoneXはiOS11からなのでそれ以外の端末は除外します
>        guard #available(iOS 11.0, *),
>            UIDevice.current.userInterfaceIdiom == .phone else {
>                return false
>        }
>        let nativeSize = UIScreen.main.nativeBounds.size
>        let (w, h) = (nativeSize.width, nativeSize.height)
>        let (d1, d2): (CGFloat, CGFloat) = (1125.0, 2436.0)
>        
>        return (w == d1 && h == d2) || (w == d2 && h == d1)
>    }()
>```
参考：iPhone Xをネイティブ解像度から判定する
https://qiita.com/ShingoFukuyama/items/273ae989442f3d1d11b2