iPhone
 Computer >> コンピューター >  >> スマートフォン >> iPhone

SwiftUIでデザインシステムを構築する方法:実践ガイドとベストプラクティス

1つのプロダクトを支えるデザインシステムを構築することは決して簡単ではありません。スケーラビリティを確保しながら、堅牢性と柔軟性の両方を兼ね備える必要があるからです。難しい課題ではありますが、これまで多くの優れたリソースが、ビジュアル面とプログラム面の両方で良いシステムを構築するための有用な原則やアプローチを共有してきました。それらの知見の上に立ち、本記事ではまだあまり語られていない領域であるSwiftUIでのデザインシステム構築に焦点を当てて解説します。

なぜこの記事を書いたのか

ニューヨークのITP(Interactive Telecommunications Program)での最初の夏、私は幸運にもLine Break StudioでiOS開発インターンとして働く機会を得ました。その中で任されたタスクの一つが、デザインシステムを2段階で構築することでした。まずSketchで視覚的に設計し、次にSwiftUIでプログラムとして実装するという流れです。

新しいフレームワークで実験しながらデザインシステムを構築した経験は素晴らしいものでしたが、その一方でバグにも悩まされました。だからこそ、私たちの経験をコミュニティに共有し、皆さんの開発プロセスを少しでも楽にできればと考えています。

SwiftUIとは何か

AppleはWWDC 2019でこの画期的な新フレームワークを発表しました。これは近年最高の発表の一つと言えるでしょう。Web開発者の視点から見ると、SwiftUIでのプロジェクト開発体験は、従来のフロントエンドのスタックやフレームワークでの開発体験にかなり近いものです。

インターフェースのプログラミングと状態管理が劇的に容易になったのは間違いなく大きな進歩です。さらに嬉しいことに、UIKitとSwiftUIをスムーズに統合できる点も魅力です。SwiftUIの基礎を学ぶには、Appleが提供する公式チュートリアルが非常に役立ちます。

WWDCにおけるSwiftUIの紹介

デモプロジェクトについて

説明のため、Line Break Studioで構築したデザインシステムの簡易版を用意しました。これはボタンコンポーネントのセットで、さまざまな形式のボタンが含まれており、より低レベルの2つのパーツ、すなわちタイポグラフィカラーパレットの上に構築されています。

SwiftUIでデザインシステムを構築する方法:実践ガイドとベストプラクティス
デモプロジェクトの動的レンダリング表示

プロジェクトはGitHubで公開しており、開発にはXcode 11 Beta 5を使用しています。また、デザインシステム管理ハブとしてのAirtableベース(ワークフロー管理については別記事参照)も参考として公開しています。

デザインシステム構築の原則

コードとしてのデザインシステムは、デザイナーと開発者をつなぐミドルウェアです。システムの開発者は視覚的な形のデザインシステムから入力を受け取り、その後の開発で使われるAPIを生成します。このシステムをコードで完成させるために、次の2つの原則を認識しておくべきです。

1. トークンによるコミュニケーション

根本的に言えば、デザインシステムをプログラムに組み込む目的は、コード管理の改善や開発効率の向上ではなく、ビューがデザインファイルと一貫していることを保証することです。その目標を達成するには、特定の色、フォント、サイズなどの視覚要素をトークンで表現することが重要です。これにより、チーム内の開発者・デザイナー・マネージャー間のコミュニケーション品質が維持されます。

SwiftUIでデザインシステムを構築する方法:実践ガイドとベストプラクティス
Salesforceが構築したLightning Design Systemのトークン

2. 階層レベルの設計

EightShapesの記事では、「まず選択肢を示し、その後に意思決定を行う」という考え方が提唱されています。「選択肢なしに意思決定はできない」からです。

SwiftUIでデザインシステムを構築する方法:実践ガイドとベストプラクティス
EightShapesのデザイントークンに関する記事

このような順序立てたアーキテクチャは、各レベル間の結合度を緩め、将来の改訂に対してより高い柔軟性と動的性を提供します。私が採用した階層構造は、下から上へ向かって「material → base → token」という順序ですが、チームにとって扱いやすい形であればどのような構成でも問題ありません。

コードを詳しく見る

以下では、私たちの経験に基づくポイントを紹介します。完全なコードはGitHubリポジトリをご覧ください。改善のためのフィードバックやご指摘も歓迎します。

1. 階層レベルのアーキテクチャ設計

低レベルのマテリアルを積み重ねて最上位のトークンを構築する方法は2つあります。

  • 型安全性と可読性のためにenumを使う

コード内でenumをグループ化ラッパーや関数のパラメータとして使う利点はすでに広く認識されています。ここで触れたいのは、階層レベルの実装方法です。

私たちは、フォントサイズ(CGFloat)やフォント名(String)といった生の値を常に最下層に保存します。これらを直接扱いたくないからです。しかし、enumのrawValueはリテラルでなければならないため、他のenumの値をcaseに割り当てることはできません。

この問題を回避するため、必要に応じてswitch文でrawValueを返すgetValue関数を実装しました。

  • シンプルな構造のためにstructを使う

enumは優れていますが、すべての場面でその固有機能が必要なわけではありません。例えば、動的カラーの処理という重い作業はXcodeが担ってくれるうえ、APIエンドポイントでパラメータオプションが不要な場合、カラーパレットはシンプルな2階層のstructで設定できます。

2. APIエンドポイントの明快で分かりやすい命名

命名規則は議論の余地が多いテーマです。基本的なSwiftの規約に加えて、私たちが守っているルールは「略語を使わない」「シンプルにする」の2つだけです。例えば、タイポグラフィとカラーシステムを使う際、新しいエンドポイントを作る代わりに、Font構造体とColor構造体のextensionとして実装しています。このアプローチにより、開発者が馴染みのないAPI名を覚える負担が軽減されます。

3. ライト/ダーク2モードでのカラーセットの動的管理

ダークモードは業界標準となり、iOSとAndroidの両方でこの機能が実装されています。ユーザーにとって良いトレンドですが、デザイナーや開発者には課題をもたらします。特にグレースケールのカラーセットの管理と命名が難しい点です。

SwiftUIでデザインシステムを構築する方法:実践ガイドとベストプラクティス
Material Designのダークテーマガイド

グレースケールの色を動的に考えたり伝えたりする場合、「white」「light」「black」「dark」といった言葉では通用しません。仮にライトカラースキームでHEX値#000000(黒)の動的カラーを「black」や「dark」と呼んだとしましょう。ダークカラースキームではこの色が#FFFFFF(白)に変わるはずです。このとき、この特定の色をどう呼べばよいのでしょうか?「defaultDark」?それとも「lightDark」?

SwiftUIでデザインシステムを構築する方法:実践ガイドとベストプラクティス
混乱を招きやすいカラーセットの切り替え

従来のアプローチでグレースケールの動的カラーセットに名前を付けるのは非常に紛らわしいものです。この混乱を避けるため、私たちはthemecontrastという概念を使って、ライトとダーク両スキームの1組のカラーを管理しています。

SwiftUIでデザインシステムを構築する方法:実践ガイドとベストプラクティス
デモAirtableベースでのカラー命名例

なお、グレースケールの色が必ずしも反対のカラーモードで反転するとは限りません。ライトのままライト、ダークのままダークであるような場合は、単にlightまたはdarkと名付けます。

この命名方法に慣れてしまえば、Xcodeでのカラーパレット管理は簡単です。カラーセットを作成するには、新しいAsset Catalogファイルを作成 → 新しいColor Setを追加 → AppearancesAny, Light, Darkに変更するだけで完了です。

SwiftUIでデザインシステムを構築する方法:実践ガイドとベストプラクティス
Xcodeでのカラーアセット追加方法

4. environment設定の活用

SwiftUIフレームワークの素晴らしい機能の一つがenvironmentモディファイアです。対象のビューの環境値を制御できます。デザインシステム構築の観点では、この機能によりアプリ全体のフォントをルートレベルで一括変更できます。また、environmentValueを使うもう一つの利点は、開発中にライトとダークのカラースキームを切り替えてテストできることです。

5. buttonStyleとボタンラベル

UIKitの時代と比べて、SwiftUIで再利用可能なボタンを構築するのは格段に簡単になりました。Buttonビューは2つの部分、つまりactionクロージャ(ボタン押下時に発火するイベント)とlabel(ボタンの本体)で構成されます。そして、このビューにはbuttonStyleモディファイアをチェーンできます。再利用可能なボタンの構築について詳しく学びたい方は、Alejandroのチュートリアルをおすすめします。包括的で非常に有用です。

カスタムボタンコンポーネントでは、まずTokenButtonLabelTokenButtonStyleの2つのstructを作成します。これらのstructは、デザインファイルにあるボタンの種類に応じて実装します。例えば、ラベルにはアイコンとテキストの2種類しかなく、それぞれのタイプに対応するinit関数を異なるパラメータで設計しています。

一方、ボタンスタイルには主に4種類あります。サークルアイコン、アイコン、カプセル、テキストです。ButtonStyleプロトコルに準拠するには、makeBody関数を実装する必要があります。この関数はconfigurationプロパティを提供し、ボタンが押されているかどうかを監視するネイティブのisPressed値を利用できます。

最後に、TokenButtonLabelTokenButtonStyleの上に積み上げる形で、ボタンコンポーネントAPIのエンドポイントとなるのがTokenButtonです。これはボタンのコンテンツとスタイルをまとめてラップするグループであり、ビジュアルデザインシステムのボタンタイプに準拠しています。

6. AnyViewをラッパーとして使う

ButtonStyleプロトコルがもたらすmakeBody関数を扱う中で、Viewを扱うための便利なテクニックを見つけました。ビューを変数に保存する際、型アノテーションをAnyViewと指定できます。これはSwiftUIにおける汎用的なビューのコンテナとして機能します。

私たちの場合、すべてのタイプのボタンに対してconfiguration.labelにopacityモディファイアを適用したかったのですが、各switchケースで繰り返し記述する代わりに、最後にまとめてモディファイアをチェーンする方が合理的です。AnyViewの利点を活かせば、このパターンを以下のように実現できます。

7. mutating関数でビューモディファイアを構築する

ボタンのスタイルを動的に更新するには、独自のモディファイアを構築できます。まずビュー内にカスタマイズされた可変状態プロパティをインスタンス化し、次にターゲットの状態プロパティを更新した後にSelf型を返すmutating関数を作成します。

8. 注意が必要なボーダースタイル

SwiftUIの弱点の一つは、円形シェイプに円形のボーダーを付けるスタイリングが決して直感的ではないことです。私はしばらく苦戦しましたが、最終的にStackOverflowで解決策を見つけました。これを実現するには、clipShapeoverlayモディファイアの併用が必要です。

まとめ

SwiftUIはAppleが成し遂げた驚くべき進歩です。まだ不完全な部分はあるものの、堅牢で柔軟なデザインシステムの構築、さらにはiOSの複雑なUIの実装において、以前よりもはるかに効率的になっています。この記事が、UIを構築しようとしているiOSチームの皆さんのお役に立てれば幸いです。フィードバックはいつでも歓迎します!

? 私のその他の作品はvinceshao.comで読めます / TwitterやLinkedInでもフォローできます

  1. AutoLayoutとSwiftで構築するiOS向けSpotifyクローンの作り方

    この記事では、Swiftを使ってSpotifyのホーム画面レイアウトをプログラムで再現する方法を解説します。なぜストーリーボードではなくプログラムで構築するのでしょうか?それは、複数のアプローチでUIを構築できるスキルは常に価値があり、コードで実装するスタイルが好きだからです。特にチーム開発やバージョン管理システムを使用している場合、このスキルは大いに役立ちます。 以下はSpotifyモバイルアプリの実際のホーム画面です。このようなレイアウトを実現するためにUICollectionViewを使用し、タブナビゲーションの作成にはTabBarControllerも活用します。 基本要件:まず、

  2. iPhoneのFace IDに別の顔を登録する方法【iOS 12以降の「代替の外観」設定】

    iPhone Xとともに登場したFace IDは、多くの人を魅了しました。ティム・クックCEOが「スマートフォンの未来」とまで語ったこの生体認証システムにより、ユーザーはパスコードを入力することなく、自分の顔だけでiPhoneのロックを解除できるようになりました。 しかし当初のFace IDには一つ大きな制約がありました。それは、ロック解除用として登録できる顔が「1人分だけ」という点です。セキュリティの観点からは理にかなっていますが、緊急時に家族や信頼できる人にスマホを使ってもらいたい場面では、かえって不便に感じることもありました。 そんな悩みはiOS 12で解決されました。「代替の外観(Al