[Ionic] Android DesignでもCollapsible Large Titlesを使いたい!
Ionic5から、Ionicで「Collapsible Large Titles」が実装されました。未スクロールの状態ではLerge Titleを表示して、スクロールするとheader部分に小さなタイトルを表示させる見せ方です。
なのですが、この表示はiOSモード( ios
)のみで有効で、Androidモード( md
)では利用することができません。
しかしながら、Androidも近年はCollapsible Large Titlesを採用しています。例えば、以下はPixel5a / Android12での設定画面です。
これによってAndroid DesignでCollapsible Large Titlesを使う!というのはアンチパターンでなくなりました(iOSにしかない挙動をクロスプラットフォームにするためだけに無理やりAndroidに実装するのはアンチパターンだと思っています)。
では、Android DesignでCollapsible Large Titlesを使うためにはどうすればいいでしょうか。
何も考えない場合
AndroidでもiOSデザインを強制してしまえば、AndroidでもCollapsible Large Titlesを使うことができます。
<ion-header [translucent]="true" mode='ios'>
<ion-toolbar>
<ion-title>{{ title }}</ion-title>
</ion-toolbar>
</ion-header>
<ion-content [fullscreen]="true">
<ion-header collapse="condense" mode='ios'>
<ion-toolbar>
<ion-title size="large">{{ title }}</ion-title>
</ion-toolbar>
</ion-header>
Ionicのコンポーネントは mode=ios
でiOSデザインに固定することができます(Androidデザインに固定したい場合は、 mode=md
)。また、指定がない限り入れ子になっているコンポーネントは親コンポーネントのデザインを受け継ぐので、これで実現することができます。
けど、タイトルがiOS表示に固定されてしまいます。
(左がiOSデザイン、右がAndroidデザイン)
Androidデザインでは、ページのタイトルは左寄りで比較的細文字、iOSデザインは中央寄せで太文字です。他に「戻る」ボタンの形状であったり、それぞれプラットフォーム毎に設定されているものがiOSに固定化されてしまいます。これは嫌だ。
そもそもなぜAndroidで使うことができないのかを整理する
https://forum.ionicframework.com/t/is-there-anyway-to-have-collapsable-title-on-android-too/219791 でMikeが「iOSのためにハードコーディングされてるからAndroidで使えないよ」と返事しています。ハードコーディングしているところを探してみましょう。
まず、デザインをあててるCSS。
ion-headerにがっつりハードコーディングされていますね。Androidで無効化しているのは以下のコードです。
display: none
してるだけならCSSあてればどうにかなるかなと思ったんですが、続いて以下のハードコーディングが立ち上はだかります。
checkCollapsibleHeader
メソッドは簡単にいうと、Collapsible Large Titlesが設定されているかを確認して、スクロール量を計算して、うまく表示表示アニメーションを制御しているメソッドです。これが mode=ios
でないと動かない・・・!!!!
なのですが、 ion-header
コンポーネントがiOS/Androidで異なる処理・デザインをしているのはCollapsible Large Titlesのための分岐だけなんですよね。iOS/Androidで高さを分岐させてるのは ion-toolbar
だし、もしかしてこれはワンチャンある??
iOSモードの問題点を考える
Androidデザインでは、ページのタイトルは左寄りで比較的細文字、iOSデザインは中央寄せで太文字です。他に「戻る」ボタンの形状であったり、それぞれプラットフォーム毎に設定されているものがiOSに固定化されてしまいます。これは嫌だ。
と述べましたが、これは ion-header
で設定されているものではありません。ion-header
から入れ子になっており、modeを継承している ion-toolbar
による問題です。では、 ion-toolbar
でもmodeを指定してしまったらどうなる??
<ion-header [translucent]="true" mode='ios'>
<ion-toolbar mode="md">
<ion-title>{{ title }}</ion-title>
</ion-toolbar>
</ion-header>
<ion-content [fullscreen]="true">
<ion-header collapse="condense" mode='ios'>
<ion-toolbar mode="md">
<ion-title size="large">{{ title }}</ion-title>
</ion-toolbar>
</ion-header>
お、結構理想に近づいてきました。よく考えるとAndroidデザインにはLarge Titleがないので、それは別途設定しないといけませんね。グローバルCSSに以下を追加します。(日本語だと上が少し切れるので30px程度の方が使いやすいです)。
ion-title[size="large"] {
font-size: 34px;
}
/* display:noneが先に読み込まれることがあるので詳細度をあげて上書き */
ion-app.md .header-collapse-condense {
display: block;
}
これで大体挙動は大丈夫ですね。ただ、これだとiOSの時もAndroidデザインになってしまうので、 @ionic/angular
にある Platform APIを使って実行端末を判定しましょう。 ついでに、私の手元のAndroidではブラー効果はなかったので、その効果も切ります。
<ion-header [translucent]="platform.is('ios')" mode="ios">
<ion-toolbar [mode]="!platform.is('ios') ? 'md': undefined">
<ion-title>Tab One</ion-title>
</ion-toolbar>
</ion-header>
<ion-content [fullscreen]="true">
<ion-header collapse="condense" mode="ios">
<ion-toolbar [mode]="!platform.is('ios') ? 'md': undefined">
<ion-title size="large">Tab One</ion-title>
</ion-toolbar>
</ion-header>
左がiOS、右がAndroidです。大体再現できました。
まとめ
https://github.com/ionic-team/ionic-framework/issues/25157 で、Issueはあげておいたのですが、実装・リリースはまだ先になると思います。それでもAndroidでもCollapsible Large Titlesを使いたいという方はぜひご参考にしていただければ幸いです。
実プロダクトで実装する場合は、全ページにmodeやplatformを指定するのはしんどいので、Directiveを使ってDOMの操作でこれらを行うとスマートでいいかなと思います。
それでは、また。
Discussion