iOS11 / iPhone X 対応をした話

この記事は[NIFTY Advent Calendar 2017](https://qiita.com/advent-calendar/2017/nifty)の5日目の記事です。
4日目は@kanishionoriさんの「[CSS3 animationで絵文字をよりエモくする方法](https://qiita.com/kanishionori/items/4283b6b5bd60525b1e68)」という記事でした。

# はじめに

この記事は、iOS11 / iPhone X 対応をするためにこんなことをしましたというメモです。
ちなみにわたしはiOSアプリ開発を始めたばかりの初心者です。そのため記事中「は？？？？」となる部分があるかもしれません。ぜひアドバイスください。
よろしくお願いします。

# iOS11 に対応する

## 余白を最適化

### 状況

iOS11では[`UIScrollViewContentInsetAdjustmentBehavior`が追加され、Navigation bar / Tool bar分の余白が自動でとられる](https://qiita.com/peka2/items/b6301a0c06cc13286296)ようになりました。
これまでcontentInsetで余白を指定していた場合には、余計に広く表示されてしまいます。

### 対応

iOS11のみ余白をいれないようにしました。

```swift
if (UIDevice.current.systemVersion as NSString).floatValue < 11.0 {
    self.view.contentInset = UIEdgeInsets(top: self.topLayoutGuide.length, left: 0, bottom: 0, right: 0)
}
```

## テーブルヘッダー/フッターの高さを最適化

### 状況

[UITableViewのSelf-Sizingがデフォルトになった](https://dev.classmethod.jp/smartphone/iphone/xcode-9-uitableview-self-sizing-by-default/)ことにより、高さが規定より小さくならなくなりました。
これにより高さを0にしていたフッターの幅がおおきくなり、表示が崩れてしまいました。

### 対応

下のように指定するとこれまで通りの表示となります。

```swift
self.tableView.estimatedSectionHeaderHeight = 0;
self.tableView.estimatedSectionFooterHeight = 0;
```

## サーチバーの高さを最適化

### 状況

サーチバーの高さが高くなったせいで、アニメーションやら表示やらに様々な影響がでてしまいました。

### 対応

ゴリゴリ高さ指定しました。

```swift
if #available(iOS 11.0, *) {
    searchBar.heightAnchor.constraint(equalToConstant: 44.0).isActive = true
}
```

# iPhone X に対応する

## iPhone X の縦長画面に最適化

### 状況

iPhone Xに最適化されていない場合、上下に黒帯が表示されてしまいます。

<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">Apps not optimised for iOS 11 will run on an iPhone X letterboxed at 16:9, with a blank status bar, and slightly rounded corners. <a href="https://t.co/t3JRaogPZC">pic.twitter.com/t3JRaogPZC</a></p>&mdash; James Thomson (@jamesthomson) <a href="https://twitter.com/jamesthomson/status/909519985743196160?ref_src=twsrc%5Etfw">September 17, 2017</a></blockquote>

### 対応

iPhone X用の1125px×2436pxのスプラッシュ画像を設定しました。
これだけでいいの…？うそでしょ…？感すごかったです。

## SafeAreaに対応する

### 状況

画面最下部に要素を設置していると、ホームインジケーターにかぶってしまいます。
触るアクションのある要素は[SafeArea](https://qiita.com/eimei4coding/items/5a0794cf7cd13c82b2b5#safe-areaについて)内におさめましょう。

<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">The Google Maps iPhone X update is almost a month late, and even then it’s wrong. Clipped corners and too close to the home indicator. 🙄 <a href="https://t.co/o9TeWi1vjt">pic.twitter.com/o9TeWi1vjt</a></p>&mdash; Adam Swinden (@AdamSwinden) <a href="https://twitter.com/AdamSwinden/status/936331258237538314?ref_src=twsrc%5Etfw">November 30, 2017</a></blockquote>

### 対応その1：[safeAreaInsets](https://developer.apple.com/documentation/uikit/uiview/2891103-safeareainsets)を使う

`self.view.safeAreaInsets`でSafeAreaの広さを取得できます！
[`viewWillLayoutSubviews`以降のタイミングだと計算済みで使える](https://qiita.com/hituziando/items/e5873b5bfa42247071e6)そうです。

### 対応その2：[safeAreaLayoutGuide](https://developer.apple.com/documentation/uikit/uiview/2891102-safearealayoutguide)を使う

`self.view.safeAreaInsets`は`viewWillLayoutSubviews`の時点でまだ0だったりすることもあり、扱いがむずかしいです。対してこちらは[LayoutGuide](https://developer.apple.com/documentation/uikit/uilayoutguide)なのでタイミング関係ありません。心強い味方です（AutoLayoutになっているor簡単に移行できるなら）。

```swift
if (@available(iOS 11.0, *)) {
    self.view.addConstraints([
        subview.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor, constant: -44.0),
        subview.heightAnchor.constraint(equalToConstant: 44.0)
    ])
}
```

# まとめ

iOS11/iPhone Xのために対応したのは以下の4点でした。

- UITableViewのSelf-Sizingがデフォルトになった
- contentInsetの調整がいらなくなった
- サーチバーの高さが高くなった
- iPhone Xの縦長画面
- SafeAreaという概念が出てきた

悲しいことに、謎アニメーションなどはまだ問題として残っていますが、見つけて直すことができたのは上の４点起因のものくらいです。
もっと精進したいとおもいます。

明日は@tsubasaogawaさんの記事です。よろしくお願いします！！