この記事はNikkei Advent Calendar 2022の 8 日目の記事です。
こんにちは。iOS チームの佐藤です。iOS 16 からロック画面にウィジェットを設置できるようになりました。この機能について日経電子版アプリで対応を行ったので、その詳細について紹介していきます。
ロック画面ウィジェットとは
iOS 16 から登場した機能で、ロック画面にウィジェットを設置できるようになりました。iOS 14 からホーム画面にウィジェットを設置できるようになっていますが、ロック画面に設置することでアプリの情報をより手軽に確認することが可能となります。日経電子版は既にホーム画面ウィジェットに対応済みです。開発の裏側に興味のある方は日経電子版を Widget で読む [プロダクト編]をご覧ください。
ロック画面に設置できるウィジェットの種類は accessoryInline
, accessoryRectangular
, accessoryCircular
の 3 つです。
accessoryInline
- 時刻の上に設置可能です。表示領域は 1 行で直線のような見た目です(↓の画像では日付・曜日を表示しているウィジェット)。
accessoryRectangular
- 時刻の下に設置可能で、長方形のような見た目です。ロック画面ウィジェットの中では一番サイズが大きいものになります(↓画像では時計左下のウィジェット)。
accessoryCircular
- 時刻の下に設置可能で、円形のような見た目です。表示領域が一番狭いため直感的で分かりやすいデザインが理想だと思います(↓画像では時計右下のウィジェット)。

日経電子版のロック画面ウィジェット
日経電子版のロック画面ウィジェットでは記事の見出しを表示しています。見出しの表示領域を十分に確保するため accessoryRectangular
のウィジェットを採用しました。ロック画面にウィジェットを設置することで、アプリを開かなくても最新の記事を一目で確認できます。
表示する記事のカテゴリーはデフォルトでは「速報」を表示しています。ロック画面はユーザーが目にする機会が多いため、ずっと同じ記事が表示され続けるのは避けたいです。そのため、比較的更新頻度の高い「速報」を表示しています。また、「経済」「政治」など自身に興味のあるカテゴリーを選択することができます。
実装で工夫した点
見出しが短い場合はスニペットを表示するようにした点です[1]。元々は見出しのみを表示する予定でしたが、見出しが短い場合では以下のようにスペースが余ってしまう状態でした。
そこで、見出しが短い場合はスニペットを表示することにしました。ただ、以下のように実装してしまうと見出しが長い場合、見出しが見切れてしまいます。見出しはスニペットよりも優先的に表示し、見出しは見切れないようにしたいです。
var body: some View {
VStack(alignment: .leading) {
Text(articleHeadline.displayTime)
.font(.system(size: 10))
.lineLimit(1)
Text(articleHeadline.title)
.bold()
.font(.system(size: 12))
Text(articleHeadline.snippet)
.font(.system(size: 11))
}
}

今回の要件を整理すると以下です。
- 見出しが 2 行以内に収まる場合はスニペットを表示したい
- 見出しは見切れないようにする
- 見出しが 3 行以上となる場合はスニペットは表示しない
この要件を満たすにあたって障壁となったのはスニペットの出し分けロジックをどうするかです。見出しが 2 行に収まるかどうかを識別する必要がありますが、仮に文字数で判別しようとすると端末によって 1 行に何文字入るかは変わってくるため識別は容易ではありません。この問題を ViewThatFits
を使用して解決しました。
ViewThatFits
とは iOS 16 から登場した機能です。ViewThatFits
のイニシャライザで表示したいビューのパターンをいくつか定義することで、スペースに最もフィットするビューが自動的に選択・表示されます。詳細については2022年のWWDCで触れられているので興味のある方はぜひ試聴してみてください。
今回は以下のように実装しました。ViewThatFits
内に「見出しが 2 行 & スニペット」、「見出しが 1 行 & スニペット」、「見出しのみ(スニペットなし)」のビューを定義することで、見出しの長さに応じて表示するビューを切り替えることが可能となりました。また、 ViewThatFits
内に定義されているビューは上から順に評価されるため、どういった順番でビューを定義するかも重要となります。
var body: some View {
ViewThatFits(in: .vertical) {
// 見出し2行 & スニペット
VStack(alignment: .leading) {
self.makeViewWithSnippet(lineLimit: 2)
}
// 見出し1行 & スニペット
VStack(alignment: .leading) {
self.makeViewWithSnippet(lineLimit: 1)
}
// 見出しのみ(スニペットなし)
VStack(alignment: .leading) {
RequiredBodyView(articleHeadline: articleHeadline)
}
}
}
private struct RequiredBodyView: View {
var body: some View {
Text(articleHeadline.displayTime)
.font(.system(size: 10))
.lineLimit(1)
Text(articleHeadline.title)
.bold()
.font(.system(size: 12))
}
}
@ViewBuilder private func makeViewWithSnippet(lineLimit: Int) -> some View {
RequiredBodyView(articleHeadline: articleHeadline)
Text(articleHeadline.snippet)
.font(.system(size: 11))
.lineLimit(lineLimit)
}
上記実装の結果、以下のように見出しの長さに応じてスニペットの出し分けを実現できました。
左から順に「見出しが 2 行 & スニペット」、「見出しが 1 行 & スニペット」、「見出しのみ(スニペットなし)」のパターンです。
おわりに
今回は iOS 16 から登場したロック画面ウィジェットへの対応についてご紹介しました。今後実装される際の参考になれば幸いです。ぜひ皆さんもウィジェットを使用してみてください!
アプリチームでは iOS の新機能を素早くキャッチアップし、ユーザーの皆様により良い体験をしていただけるよう日々開発に取り組んでいます。日経での仕事に興味を持っていただけた方は、ぜひお気軽にご連絡ください。
明日は同じくアプリチームの室谷さんによる「日経電子版の watchOS 対応について」です。お楽しみに!
注釈
[1]: スニペットとは記事先頭部分のことを指します。