AppleのUIクローンを作ってその先を学ぶ

# はじめに

写経をすると、最初は文字の練習のつもりがだんだんと文字のディティールやバックグラウンドに対して興味が湧くことがあります。
UIに関しても同様で、既存のUIを真似ていく上で表面上の情報から徐々に本質的に解決しようとしている課題に気が付くことがあります。
これらの経験は普段の開発でも流用することができるため、UIコンポーネント開発の練習として普段の生活に取り入れてみましょう。

この記事では、AppleのUIクローンを作りそのディティールに迫ります。

# 何を手本にするか

お手本にするUIがお粗末なものであれば、それ以上を学ぶことは出来ません。
なるべく自分がリスペクトできるものを選択しましょう。
iOSの場合は、Appleプラットフォームに沿ったUIを選択すると良いでしょう。
今回は[UIColorPickerViewController](https://developer.apple.com/documentation/uikit/uicolorpickerviewcontroller)に取り組みます。
他のデベロッパーが取り組んだプロジェクトに関しては、この記事の終盤でいくつか紹介しています。

![CleanShot 2022-03-19 at 00.00.16@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24979/4128b563-38c4-1e96-5515-4b482a64322d.png)

# 基本理念を理解する

そのUIがどんな目的のものなのかは、HIGを参照すると確認できます。
ここで、どんなユーザーがどんな時に利用するのかを理解しておくことで、理解不能な挙動や表示が発生したときにそれを考察するヒントになります。

https://developer.apple.com/design/human-interface-guidelines/ios/controls/color-wells/

# 構成要素を捉える

UIは、グラフィカルな部分、アニメーション、Hapticなど多くの要素で構成されています。
まずはこれらを洗い出して、何に注目するかを決めます。
今回のUIColorPickerViewControllerでは、次のようなものが挙げられます。

## UIコンポーネント

一般的なUIは、複数の小さなUIコンポーネントの集合で構成されています。

![CleanShot 2022-03-19 at 00.07.58@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24979/cf264f7c-09ea-1c93-0fcf-3f0320d7af17.png)

例えば①は、スポイト・タイトル・Xボタンの３つの要素が横並びになっている箇所です。
ここはUINavigationBarが使われていそうだなぁなどと、標準的なUIで使われていそうなものを考えます。
また、②はUISegmentControlのように見えます。なぜUITabBarではなくUISegmentControlを使ったのかなどと自分の常識と照らしてみます。
そして、③は明らかにオリジナルのUIに見えます。
この色はどのようなロジックで選ばれたのでしょうか。実際にUIColorを取り出して、hueの変化量をマッピングしてみるのも良いでしょう。
よく観察してみると、選択している場所によってコーナーの丸みが変わっていることに気がつきました。
このような細かい丁寧さは込み上げてくるものがあります。

![CleanShot 2022-03-19 at 00.18.06@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24979/e9e3ecb6-944e-9578-6a92-09e3e08d6b8f.png)

![CleanShot 2022-03-19 at 00.18.20@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24979/3fdb75ba-b21e-17d7-9fdb-2bb0e4d9dfc2.png)

④は色のプレビューを表示する箇所です。
ただの四角なので見逃しがちですが、角丸のサイズを測ってみましょう。
角丸や線の太さといった要素は、OSやアプリ全体で統一されていることが多いです。
もし異なる太さの線があったら、なぜそうなのかも気にしてみましょう。
コード上は@x1のスケールになるので、実寸の1/3（デバイスによりますが）で計算します。

![CleanShot 2022-03-19 at 00.23.18@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24979/6b4629cc-fda3-5c62-6bec-fa141c575774.png)

⑤はUICollectionViewを使っているように見えます。
32x32のセルが5x2で並んでいます。
UICollectionViewといえば、画面のサイズに対応しやすいコンポーネントでもあります。
このUIが別のデバイスではどうなるのか、次はレイアウトを見てみましょう。

![CleanShot 2022-03-19 at 00.31.27@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24979/7f9916dc-c0d5-7667-734f-886361cb2cb4.png)


## レイアウト

UIとは、決してスタティックなものではありません。ユーザーやデバイス、プラットフォームに応じて適切な姿に変化します。
その一番身近な例がレイアウトです。
次の画像は、iPhone, iPad, iPhone(横向き)を並べた画像です。
これらは、同じAppleのデバイス上で動作しているカラーピッカーですが、どれも微妙にレイアウトが異なっています。

![CleanShot 2022-03-19 at 00.37.32@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24979/795ddafe-30e5-ecb0-89e4-0f4098a3afe8.png)

例えば、iPhoneでは5x2だった画面下部のカラーパレットは、iPadでは8x2に増量しています。
もっと増やせそうにも見えますが、もしかしたらApple社内では[ヒックの法則](https://uxdaystokyo.com/articles/glossary/hicks-hymans-law/)のような実験の末に決まった数なのかもしれません。そんな妄想も膨らみます。

![CleanShot 2022-03-19 at 00.39.25@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24979/addca4cc-62f8-58ea-f3f4-af2eb597585f.png)

次に横向きのiPhoneを見てみましょう。
今度はレイアウトが大きく変わります。セグメントが上部、グリッドとカラーパレットが左右に分かれました。
この画面はカラーを選択することに重点が置かれていますが、主に公式アプリではメモ帳やスクリーンショットのペンなどに利用されています。
そう考えると、実は細かな色の指定よりもそれっぽい色をすぐに選べることに主眼を当てているのではないでしょうか？そうであれば、右利きの人が届きやすい場所にカラーパレットを置くのも納得できます。
左利き向けのアクセシビリティが登場したらもう一度見直したいですね。

![CleanShot 2022-03-19 at 00.44.08@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24979/342c6048-e116-1a39-96b2-572a501053e8.png)

このようにユーザーの指が届く距離に応じてコンポーネントの重要度を整理する手法は一般的ですが、細かな動作を要求するにはどうすれば良いのでしょうか。
次はジェスチャーに関して見てみます。

## ジェスチャー

ジェスチャーは、不可視トリガーと呼ばれるUIの一種で目で見ることができません。
そのため、代替手段を用意することが一般的になります。

これらの代替手段も、ユーザーのリテラシと共に不要になるケースがあります。
iOSがスキューモーフィズムからフラットデザインに転換出来たのも、ユーザーがPullToRefreshなどのスマホネイティブのUIを発明できるほど適応したからという背景もあります。
今日ではホーム画面に戻る動作を全員が理解しているので、ホームに戻るための代替機能はありません。

最近投稿されたゲームさんぽで、この辺りの話をしている回があったので興味のある人は見てみると良いと思います。
https://www.youtube.com/watch?v=uTNLr4AEmZ8

さて、ちょっと寄り道してしまいましたが、ジェスチャーを見ていきます。
カラーピッカーに限ったことではないですが、汎用的なモーダルのジェスチャーを見てみましょう。

![CleanShot 2022-03-19 at 01.08.45.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24979/74030f7a-9f4f-63f1-8a87-62f0ad86bba5.gif)

カラーピッカーに限ったことではないですが、モーダルはこのように大きく下にスワイプすることで閉じることができます。
「閉じる」という大きな動作に対して、大雑把なジェスチャーを当てるのはOS全体で利用するジェスチャーに向いていそうです。
一方で実はこのジェスチャーは横向きだと次のような挙動になります。

![CleanShot 2022-03-19 at 01.11.42.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24979/532e75cb-672e-9243-fb7d-32a123a6988e.gif)

これは縦に十分な距離がないため、大雑把なジェスチャーが出来ないからだと思われます。
モーダルのタスクを中断するというのは、小さなジェスチャーですべきではないからです。
つまり、横向きのiPadではこのスワイプで閉じる動作を使うことができます。
このように自分の考察が反例によって証明される気持ちよさはUIを観察する醍醐味です。

ジェスチャーを見るときは、ジェスチャーの難易度や一般性、ジェスチャーによって行われるタスクの重要度などを見ていくと関係性が見えてきます。

## アクセシビリティ

Xcodeに付属しているAccessibility Inspectorを使うことで、アクセシビリティの設定が有効になった時の見え方が分かります。

![CleanShot 2022-03-19 at 01.18.07@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24979/fab7f1e8-c7ca-bfe9-3054-dc4c30f23c2e.png)

ここではInvertColorを有効にしてみましょう。すると、アプリの色が反転します。

![CleanShot 2022-03-19 at 01.20.47.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24979/61d226e8-6ef6-54dd-7330-f69f334ccc97.gif)

色情報はメディアではないため、Smart Invert modeを利用していても反転します。
このことから、もし色の部分を実装する場合はUIImageViewを使わないか、`accessibilityIgnoresInvertColors`を有効にするべきではないということがわかります。

https://developer.apple.com/design/human-interface-guidelines/accessibility/overview/color-and-contrast/


## プラットフォーム

最後にMacでカラーピッカーを表示してみましょう。
すると以下のようなMac標準のカラーピッカーが表示されます。
ここで、グリッド表示はこのMacのカラーピッカーを模したものであることに気づきます。

![CleanShot 2022-03-19 at 01.28.30@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24979/635cc04a-d31a-bd8e-5996-a283ab29d12d.png)

デバイスが異なれば、このように大きくコンポーネントが変わることもあります。

# 実際に作ってみる

このような構成要素の分析をしながら、自分でも実装してみましょう。
もちろん、全部を作る必要はありません。気になったアニメーションを模写しても良いですし、角丸を真似ても良いでしょう。
その中で、ビューの命名に苦しんだり、標準的なAPIの存在に気付かされる場面が大きな経験値になります。

## ズルをしてみる

実装上の命名規則や、ビューの構造を知るためにJailbreakされたデバイスを使って中を直接覗くこともできます。
いろいろな事情からやってみようとは言えないものですが、趣味の範囲で覗いてみると実装に困った時の助けになるかもしれません。
特にGUIは、表面上グレーに見えても実はUIVisualEffectViewだったなんてこともあります。

https://frida.re

https://revealapp.com

https://developer.limneos.net

## 完成したら

フルスクラッチでUIを書いたということは、そこからは自由にあなたがカスタマイズ出来るという意味でもあります。
ユーザーに使いやすい基盤の上で、足りない部分を自分で拡張できます。
ライブラリとして提供することで、プログラミング的なインターフェイスの難しさや美しさに気がつくかもしれません。
そういったことに挑戦したいくつかのプロジェクトを紹介します。

https://github.com/scenee/FloatingPanel

https://github.com/LeoNatan/LNPopupUI

https://github.com/efremidze/Shiny

https://github.com/ivanvorobei/SPIndicator

# UIやUXにパクリの概念はあるのか

UIのクローンを作る上での倫理的な観点にも触れておきます。
これに関してはbtraxが興味深い記事を書いています。
一般的に言えることですが、最終的には自分や弁護士の判断の上で自己責任で行動することになります。

https://blog.btrax.com/jp/ui-ux-copy/


# さいごに

いかがだったでしょうか、カラーピッカー一つ取っても奥深さが分かったと思います。
一般的なデザインカンプは表面上の情報しかないため、この記事を参考にインタラクションやUIの意味を考えるきっかけを作ってもらえればと思います。
また、今回の記事を書くにあたって、カラーピッカーのクローンをOSSにて公開することにしました。
把握は出来ていても実装が追いついていない部分がありますが、ぜひスターをして参考にしてみてください。

https://github.com/henzai-apps/ColorPicker