UIScrollViewで、読みやすいコンテンツに対応する

# 概要
読みやすいコンテンツを実現するガイド`Readable Content Guide` で、スクロールビューを使う場合の対応方法の説明になります。

# Readable Content Guideについて
iOSには、Readable Content Guideというレイアウトガイドがあります。

例えば、テキストなどを表示する場合、iPhoneの場合は画面幅いっぱいにテキストを表示でいいけれど、iPadなどの大きい画面だと、左画面端にちょっとだけテキストが寄ってしまう場合があるかと思います。（Left To Rightの場合）

Readable Content Guideを使うと、デバイスや向きに応じて読むための最適化された領域でコンテンツを表示することができます。

iPadの横向きが特に顕著で、Readable Content Guideの有無で左右の隙間が変わり、文章が中央に寄って読みやすくなることがわかります。
デバイスや向きごとの隙間の調整もReadable Content Guideがやってくれます。

|Readable Content Guideなし|Readable Content Guideあり|
|---|---|
|![Simulator Screen Shot - iPad Air (4th generation) - 2021-04-22 at 15.33.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687960/efda358b-0ba0-6c30-177b-94423a1af864.png)|![Simulator Screen Shot - iPad Air (4th generation) - 2021-04-22 at 15.33.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687960/4f0629ee-5798-5bcf-a664-151ea3da5674.png)|

https://developer.apple.com/news/?id=nixcb564
の `Keep your content readable` の項目も参考にしてください。

## Readable Content Guideの実装方法

### Interface Builder
Interface Builderで対応する場合の手順は以下です。

- Readable Content Guideに対応させたいビューの`Superview`に対してFollow Readable Widthのチェックを入れる
- Readable Content Guideに対応させたいビューの制約 leading, trailingを `Safe AreaではなくSuperviewのmarginに対してequalに設定`し、Relative to marginにチェックを入れる

leadingの制約はこんな感じになります。
![スクリーンショット 2021-04-22 15.42.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687960/f60be593-d4c9-e4d4-7c02-633c8e4178db.png)

## Readable Content Guide + UIScrollView (本題)

上記の文章はiPadだとしても長すぎるので、縦スクロールできるようにUIScrollViewに内包します。
しかし、ここで問題が起こります。

画面いっぱいにUIScrollViewを表示してコンテンツを縦スクロールする場合、以下のような構成になるかと思います。

- 表示するコンテンツ（今回の場合、UILabel）を、Content Layout Guideに制約を合わせる
- Frame Layout Guideは、表示するコンテンツの横幅にする

しかし、この場合Frame Layout Guideの横幅は画面幅そのものなので、Readable Content Guideを参照したものではなく、画面幅いっぱいにコンテンツが表示されます。
中のコンテンツがUIScrollViewのReadable Content Guideを参照することができません。

### 対応する
UIScrollViewの中にまずはコンテンツを示すViewを置き、Content Layout Guideの４方向とFrame Layout Guideの両脇に制約を設定し、コンテンツViewの中に、スクロールしたいコンテンツ(今回の場合UILabel)を、コンテンツViewのReadable Content Guideに合わせればOKです。

#### Interface Builderで対応する
UIScrollView直下にContentViewを置き、Content Layout Guideの４方向とFrame Layout Guideの両脇に制約を設定し、Follow Readable Widthのチェックをして、中のUILabelはSuperviewのmarginを参照しています。
![スクリーンショット 2021-04-22 16.48.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687960/4c6c308c-1c40-3a0a-162c-5b2120e6ae04.png)

#### コードで対応する
UIScrollViewには、コンテンツを示す`contentLayoutGuide`、スクロールの枠を示す`frameLayoutGuide`、そして`readableContentGuide`のガイドがあるので、まずはコンテンツを示すビューをcontentLayoutGuideの４方向とframeLayoutGuideの両脇に設定し、コンテンツビューの中に、スクロールしたいコンテンツ(今回の場合UILabel)をreadableContentGuideに合わせればOKです。

```swift
        let scrollView = UIScrollView()
        let contentView = UIView()
        
        scrollView.addSubview(contentView)
        contentView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            contentView.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor),
            contentView.bottomAnchor.constraint(equalTo: scrollView.contentLayoutGuide.bottomAnchor),
            contentView.leadingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.leadingAnchor),
            contentView.trailingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.trailingAnchor),
            contentView.leadingAnchor.constraint(equalTo: scrollView.frameLayoutGuide.leadingAnchor),
            contentView.trailingAnchor.constraint(equalTo: scrollView.frameLayoutGuide.trailingAnchor),
        ])
        
        let label = UILabel()
        label.text = text
        label.numberOfLines = 0
        contentView.addSubview(label)
        label.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            label.topAnchor.constraint(equalTo: contentView.topAnchor),
            label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
            label.leadingAnchor.constraint(equalTo: contentView.readableContentGuide.leadingAnchor),
            label.trailingAnchor.constraint(equalTo: contentView.readableContentGuide.trailingAnchor),
        ])
```

# 表示
こんな感じで表示できます。

![Apr-22-2021 16-30-52.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687960/d15156ea-fbc2-f8df-fb8a-b5fe109659d6.gif)

# 最後に
自動でデバイスや画面の向きに合わせてスペースを空けてくれる便利なReadable Content Guideですが、SwiftUIにはiOS 14.4の時点では対応されていないっぽいので、SwiftUIの場合はSize Classesに応じたマージンをとる対応が必要そうです。