Sansan Tech Blog

Sansanのものづくりを支えるメンバーの技術やデザイン、プロダクトマネジメントの情報を発信

Sansan iOS アプリにおける iOS 15 対応

こんにちは、技術本部 Mobile Application グループの山名です。

来るべき iOS 16 に思いを馳せている今日この頃ですが、今回は Sansan iOS アプリにおける iOS 15 対応についてお話ししようと思います。

発生した問題

主に4つ発生したので、そちらを順に解説します。

iOS 14 と 15 での NavigationBar の表示の違い(背景をグレーにしています)

本題に入る前に、UINavigationBar の Appearance についてお話しします。

UINavigationBar はデバイスの向きとスクロールの有無によって適用される 4つの Appearance を持っています。

名前 デバイスの向き 適用されるタイミング
standardAppearance Portrait スクロール中
scrollEdgeAppearance Portrait リストの上端
compactAppearance Landscape スクロール中
compactScrollEdgeAppearance Landscape リストの上端

適用されるタイミングを実際の動きでお見せすると以下のような感じです。NavigationBar の背景色が薄いグレーの時が standard と compact、濃いグレーの時が scrollEdge と compactScrollEdge です。

standard と scrollEdge な Appearance が切り替わる様子

compact と compactScrollEdge な Appearance が切り替わる様子

本題に戻ると、今回の問題を引き起こしているのは scrollEdgeAppearancecompactScrollEdgeAppearance です。scrollEdgeAppearace は nil だと standardAppearance を引き継ぎつつ背景色を透明にするのですが、iOS 15 から Large Title でないものにも適用されるようになったため、今回の問題が発生しています。また compactScrollEdgeAppearance は nil だと scrollEdgeApeparance を引き継ぐようになっているため、同様に背景が透明になってしまいます。

この問題の解決策は Developer Forum で Apple のエンジニアが解説しており、Sansan もそれを参考にしました。具体的には AppDelegate.application(_:didFinishLaunchingWithOptions:) で UINavigationBarAppearance を生成し、各種 Appearance に設定しています。

let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = .white

UINavigationBar.appearance().standardAppearance = appearance

let standardAppearance = UINavigationBar.appearance().standardAppearance
UINavigationBar.appearance().scrollEdgeAppearance = standardAppearance
UINavigationBar.appearance().compactAppearance = standardAppearance
UINavigationBar.appearance().compactScrollEdgeAppearance = standardAppearance

Toolbar, TabBar の背景が透明になる

standard と scrollEdge な Appearance が切り替わる様子

NavigationBar と同様に scrollEdge 系が悪さをしています。Toolbar は NavigationBar と同じく4つ、TabBar は compact 系がないため standard と scrollEdge の2つの Appearance を設定して修正しました。

(余談ですが、NavigationBar の scrollEdge 系はリストの上端の時に適用されますが、Toolbar と TabBar はリストの下端の時に適用されます)

Plain Style な TableViewHeader のスタイルが異なる

iOS 14 と 15 での Plain Style な TableViewHeader の表示の違い

デフォルトのヘッダだと以下が異なるという中々謎な仕様変更が入っています...

  1. 上部にスペースができる
  2. 下部にセパレータが入る
  3. テキストのサイズが小さく、カラーが薄い

まず 1, 2 ですが、これらは iOS 15 から追加された sectionHeaderTopPadding にゼロを設定してやると治ります(スペースは分かるのですが、セパレータが消えるのがあまりにも直感的でなくて辛いです...)。Sansan では UIBarAppearance 系と同様に、 AppDelegate.application(_:didFinishLaunchingWithOptions:) で設定して修正しました。

UITableView.appearance().sectionHeaderTopPadding = .zero

次に 3 ですが、サイズは 17 → 15pt に、カラーは _plainTableHeaderFooterTextColorsecondaryLabelColor に変わっています。

iOS 14 と 15 でのテキストスタイルの違い

サイズに関しては Dynamic Type のスタイルでいうと iOS 14 が Headline , iOS 15 が Subhead みたいなので、統一したい場合は tableView(_:willDisplayHeaderView:forSection:) でどちらかに合わせる形になります。ただし iOS 15 はサイズは Subhead ですが、ウエイトが Regular ではなく Semi-Bold になっているため、そこは追加で設定してあげる必要があります。

カラーに関しては _plainTableHeaderFooterTextColor が公開されていないので、 secondaryLabelColor に合わせるのが簡単でよさそうです。どうしても iOS 14 の方に合わせたいのであれば Light / Dark Appearance 時のカラーを調べて、 UITraitCollection.userInterfaceStyle で switch する形になります。

また Sansan iOS では出くわしませんでしたが、この記事を執筆する過程で Plain Style な TableViewFooter で 3 がそのまま発生すること、Grouped Style な TableView で 3 のカラーのみ _groupTableHeaderFooterTextColor から secondaryLabelColor に変化していることを確認しました...

加えて下記参考記事によると 1 のスペース問題は Grouped でも発生するらしく、iOS 15 対応の TableViewHeader / Footer 周りは中々厄介な感じになっています...(まあデフォルトを使うならそもそも OS 毎の差異に抗うなという感じではありますが)。

moneyforward.com

IB 上で配置した UIButton のスタイルが異なる

IB 上から配置できる UIButton の一覧

こちらはどちらかというと対応後に発覚した問題です。

UIButton では iOS 15 から UIButton.Configuration を用いて Plain, Gray, Tinted, Filled のスタイルを適用できるようになりました。一見すると Plain がこれまでのスタイルに相当しそうですが微妙に挙動が異なるため、iOS 14 以前と合わせたい時は Default を設定する必要があります。

useyourloaf.com

しかし IB 上から配置できるのは新しく追加された4つのみとなっているため、毎度 Attributes Inspector で Default に変更しなければなりません。とはいえそれだとヒューマンエラーで抜け漏れたりする可能性があるので、暫定対応として CI 上でチェックして警告を出すようにしました。Sansan では Sider というサービスを使っており、goodcheck を用いて設定を書いているため、そこに追記しました。

  - id: com.sansan.interfaceBuilder.UIButton.style
    pattern:
      - regexp: buttonConfiguration key="configuration" style="(plain|gray|tinted|filled)"
    message: "Default 以外の Style を設定すると iOS 15 未満かどうかで表示が変わるため指定しないでください"

おわりに

Sansan アプリにおける iOS 15 対応は以上となります。

今年は軽微な UI 崩ればかりだったので、去年に比べるとかなり楽でした。 この流れを iOS 16 も引き継いでくれることを祈りつつ、WWDC を待とうと思います。

ここまで読んでいただきありがとうございました。

© Sansan, Inc.