Ionicでカスタムアイコンを使う

Ionic Advent Calendar 2019
4日目の記事です。

Ionicon にちょうどいいアイコンが見つからない、そんなときにカスタムアイコンを使用する方法です。
日本語の記事がなかったので。

参考にしたサイト（というかIssue）
https://github.com/ionic-team/ionicons/issues/589

### 1. アイコンに使用するSVG画像を用意する
アイコンにはSVG画像を使用します。
SVG画像は、JPGやPNGといったドットで描くラスター画像と異なり、線（path）で描画するベクター画像です。拡大縮小に強く、大きくしてもジャギったりしません。そして軽量。

Illustratorの他、InkscapeなどのフリーソフトでSVG画像を自作してもよいですが、フリーで使えるアイコンがダウンロードできるサイトもたくさんあります。
今回は[こちら](https://iconmonstr.com/)からこのSVGファイルをダウンロードして使用することにします。
![SnapCrab_NoName_2019-11-6_23-38-58_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/220796/8b26ccf7-de91-4031-c9d5-e371a6959da0.png)
ちなみに [Ionicon のページ](https://ionicons.com/) でもアイコンのSVGファイルはダウンロードできます。
![SnapCrab_NoName_2019-11-6_21-13-25_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/220796/563c3221-cc80-b3b3-3b1a-83739a382415.png)

### 2. assetsにフォルダを追加して配置
プロジェクトの assets フォルダ内にフォルダを追加して、ダウンロードしたSVGファイルを置きます。（ファイル名はダウンロード時から変更してあります）
![SnapCrab_NoName_2019-11-6_23-41-38_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/220796/0cb91589-8687-d61f-3983-bdc3d41bde7a.png)

### 3. ion-icon タグで使う
`ion-icon` タグの src 属性に先ほど配置したファイルを指定するとアイコンとして利用することができます。
![SnapCrab_NoName_2019-11-6_23-44-18_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/220796/a9d2f710-a2fe-53d1-aca3-6970a82255d7.png)
![SnapCrab_NoName_2019-11-6_23-44-35_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/220796/24862656-33b0-27a7-1bd2-88d6fe094e6d.png)

### 4. うまく表示できないんだけど？
アイコンによってはうまく表示できない場合があります。
例）
![SnapCrab_NoName_2019-11-6_23-58-27_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/220796/495c1591-5173-2828-a099-13b705b8fc61.png)
普通のボタンとクリアボタンで色が変わっていません。
`ion-icon` タグで使用して自動的にスタイルを変更してくれるのは、path のみで構成されたSVGファイルだけです。塗りつぶし（fill) や縁取り（stroke）が使用されたSVGファイルではうまく表示できません。
ちなみにこの葉っぱのSVGファイルはこんな感じ。fill や stroke が使われています。
![SnapCrab_NoName_2019-11-7_0-3-36_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/220796/0ddbbaf3-c006-6a20-fb3f-30514796b43d.png)
うまく表示できるSVGファイルはこんな感じ。path だけで構成されています。（IoniconのページでダウンロードできるSVGファイルも同様です）
![SnapCrab_NoName_2019-11-7_0-6-45_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/220796/a818de66-7879-c614-c766-cdad43eea4ce.png)
うまく表示できなかったファイルから fill や stroke を除いて、いい感じになることもあります。編集可のフリー素材だったら試してみてもいいかもしれません。

ちなみに葉っぱアイコンは path だけにしてみましたがイマイチでした。
![SnapCrab_NoName_2019-11-7_0-12-59_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/220796/c95e0c69-7a42-4a4f-cfc6-cecd78878e9d.png)
![SnapCrab_NoName_2019-11-7_0-13-7_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/220796/0306b1da-0f41-db54-aeac-6fa25bc48d7a.png)
Illustratorなどで自作のアイコンを作る場合、自動で色が変更されるようにしたければ path だけで作成するようにしましょう。

### 5. name属性で使いたい
`ion-button` に使えてめでたしめでたし、かと思いきや、このままでは困ったことがあります。ActionSheet などのボタンに使いたい場合です。
ActionSheet などボタンを配置できるコンポーネントの場合、ボタンにアイコンを表示する際 icon フィールドにアイコンの名前を設定します。
![SnapCrab_NoName_2019-11-7_23-20-44_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/220796/f42cf063-d8d7-f92f-0d0d-59606d73a31e.png)
![SnapCrab_NoName_2019-11-7_23-22-31_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/220796/fddde25e-061a-68be-9ae0-d1088deb0386.png)
追加したカスタムアイコンは src 属性にパスを渡すことで表示することができましたが、ActionSheet の buttons には src 属性がないため、ファイルパスを渡すことはできません。
そこで今度は、カスタムアイコンに名前をつけて、Ionicon と同様に name を指定して使用できるようにします。

### 6. name で指定できるようにする
今回追加したカスタムアイコンを `name="translate"` で使用できるようにします。name は標準の Ionicon と被らないようにしましょう。

まず assets/custom-icon に配置したSVGファイルをコピー＆ペーストして複製します。
そしてそれぞれ、以下のようにファイル名を変更します。
![SnapCrab_NoName_2019-11-7_23-28-50_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/220796/7367578c-2334-3778-7836-68c727f7ec33.png)
使用したい name の頭に `ios-` と `md-` をつけました。
察しのいい方はお気づきかもしれませんが、 `ios-` がついている方のファイルが iOS 端末で、 `md-` がついている方のファイルが Android およびデスクトップ端末で表示されます。
今回はどちらも同じ画像ですが、iOS と Android/PC で異なる画像を表示したい場合は、iOS 用の画像を `ios-xxxx.svg` 、Android/PC 用の画像を `md-xxxx.svg` という名前にします。

次に Angular のビルド設定を変更します。
angular.json の projects/app/architect/build/options/assets に以下の記述を追加します。

```
{
  "glob": "**/*.svg",
  "input": "src/assets/custom-icon",
  "output": "./svg"
}
```

![SnapCrab_NoName_2019-11-7_23-36-55_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/220796/c6066683-652e-1464-680b-4b89418c6248.png)

これで準備が整いました。
`ion-icon` に src 属性でファイルパスを指定していた部分を `name="translate"` に変更してみましょう。
![SnapCrab_NoName_2019-11-7_23-38-56_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/220796/07961cb2-6e15-c23a-5b18-ee5064abd289.png)
![SnapCrab_NoName_2019-11-7_23-39-19_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/220796/802dd3f9-c9df-5913-1648-ed525c6fe8d4.png)
ちゃんと表示できていますね。
ActionSheet でも `icon: 'translate'` を指定してみましょう。
![SnapCrab_NoName_2019-11-7_23-40-36_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/220796/abfaacc3-3895-8377-4848-6cdd8d388a4f.png)
![SnapCrab_NoName_2019-11-7_23-41-11_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/220796/640ff6e4-6aad-25b8-3d58-52eafe2c39cc.png)
やったぜ。

### 7. 特別な名前 logo-
これでカスタムアイコンに好きな名前をつけて Ionicon と同じように使えるようになったわけですが、logo- で始まる名前を付ける場合は注意が必要です。
前述の通り iOS では `ios-` で始まるファイル、Android/PC では `md-` で始まるファイルを取得しにいきます。

（Chrome Dev Tools の Networkログ）
iOS の場合
![SnapCrab_NoName_2019-11-7_23-51-49_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/220796/e6b9a1a6-72a6-a3f7-108a-074a81123e06.png)
Android/PC の場合
![SnapCrab_NoName_2019-11-7_23-52-1_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/220796/563decc9-f259-8310-8bdc-6fcca2258fba.png)

ではカスタムアイコンの名前を `translate` から `logo-translate` にしてみましょう。ファイル名も以下のように変更します。
![SnapCrab_NoName_2019-11-7_23-54-11_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/220796/59d9766f-dfdd-551a-300f-2ac2352d29c4.png)
![SnapCrab_NoName_2019-11-7_23-54-38_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/220796/9fec007d-6c26-08f4-17ec-e846777dc0a4.png)
![SnapCrab_NoName_2019-11-7_23-55-7_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/220796/17ad7ffe-465c-4e89-e3ba-da005a8e8ef9.png)
アイコンが表示されなくなってしまいました。
コンソールにはエラーが出力されています。
![SnapCrab_NoName_2019-11-7_23-55-42_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/220796/9f96a6da-ef88-12e8-4660-d0a7ca646524.png)
ネットワークログを見ると、どうやら `logo-translate.svg` というファイルを取得しにいっているようです。（そして404エラーで失敗している）
![SnapCrab_NoName_2019-11-7_23-56-20_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/220796/be1c995f-9776-a469-3439-4671da1bdf23.png)
`logo-` は特別な名前で、iOS と Android/PC で表示するファイルを **変えません** 。どちらの場合も `logo-translate.svg` を取得して表示します。
逆に言うと、iOS と Android/PC で表示するアイコンを変えない場合は、ファイルを2つ用意する必要はなく `logo-xxxx.svg` を1つ用意すればよいわけです。
その代わりアイコンの名前は必ず `logo-xxxx` となります。頭の `logo-` は固定です。
ファイル名を以下のように修正すればアイコンは表示されます。（そしてファイルは1つでよくなった）
![SnapCrab_NoName_2019-11-8_0-4-56_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/220796/a5d7b0b7-d3b5-5630-881a-6a96439855b4.png)
![SnapCrab_NoName_2019-11-8_0-5-15_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/220796/17a0a348-31d8-8f6f-7415-6ecc26e8de3e.png)

### 8. 余談(1)
アイコンを名前で指定できるように angular.json に記述を追加しましたが、追加した記述のすぐ上を見てみると、指定しているディレクトリパスが違うだけで他は全く同じです。
![SnapCrab_NoName_2019-11-8_0-8-1_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/220796/2f3f42f5-84be-7d40-5e91-0aeb850f1b10.png)
上の記述は Ionic が Ionicon を使うための記述です。上の記述にあるディレクトリパスを見てみましょう。
![SnapCrab_NoName_2019-11-8_0-9-45_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/220796/c03f6672-003f-ba72-2d04-57bad66f1d60.png)
ずらりとSVGファイルが並んでいます。そして（画像にはありませんが）ファイル名は `ios-` `logo-` `md-` で始まっています。

今回、 Ionic と同じ方法でカスタムアイコンを追加したのです。そのお陰で name を指定してアイコンを表示することができました。

### 9. 余談(2)
`ion-icon` タグは割と柔軟に CSS を適用することができます。
CSS を当てると、 `ion-button` タグ以外でも使いやすいアイコンになるのでオススメです。
![SnapCrab_NoName_2019-11-8_0-45-12_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/220796/aea7c176-d0c7-e06c-7371-c165e4f139f2.png)
![SnapCrab_NoName_2019-11-8_0-23-40_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/220796/6a5e7127-2368-99df-22df-ef06b9856ec4.png)
![SnapCrab_NoName_2019-11-8_0-30-48_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/220796/9da2d226-8cf6-fa10-7c14-4a47df111147.png)

アイコンの塗りつぶし色を `fill` で指定しているのがポイントです。
`fill` はSVGファイル内部に記述される属性でしたが（そして今回アイコンとして使うには存在が邪魔でしたが）、CSSで指定することができます。

### 10. 終わりに
カスタムアイコンを使用できるようになると、アプリのデザインの幅がぐんと広がります。
またカスタムアイコンを Ionicon と同じように使えるのもとても便利です。
私も冒頭の Issue を見つけるまでは、ActionSheet に cssClass を指定してグローバルCSS で ::before疑似要素をつっこんで画像表示、ああでも Android ではグレーだけど iOSでは primary color で表示されるからファイルを2つ用意してクラスも2つ記述して...という労力を費やしていました。

フリーのアイコンを使用する際は、許諾や利用条件、変更の可否などを調べて、著作権を侵さないよう注意しましょう。