解こうとしたこと
単語アプリが続かない理由は、覚えられないからではなく「開かなくなるから」です。学習の質より前に、接触回数のところで詰まっている。
そこで、アプリを開かせることを目標にするのをやめました。ユーザーが他のことをしている時間に、視界の端へ単語を差し出す方向に振っています。
PiP を学習面として使う
ピクチャインピクチャは本来、動画を小窓で見続けるための仕組みです。これを単語の表示面として使っています。他のアプリを触っている間も小窓が残るので、行き場のない待ち時間がそのまま学習時間になります。
PiP は映像レイヤーを前提にしているため、テキストをそのまま流し込むことはできません。表示したい内容を毎回フレームとして描き起こし、それを映像として流す作りにしています。描画を担う部分を独立させてあるのは、単語の切り替えを「映像の更新」として一本化するためです。
用途としては外れた使い方なので、素直には動きません。他アプリへ移ったとき、通話が入ったとき、画面が消えたときに小窓がどう振る舞うか。この状態の管理が実装のほとんどを占めました。
ロック画面で完結させる
ロック画面にはライブアクティビティで単語を出しています。ここで止めずに、答えを表示する・覚えたことにする、という操作までロック画面上で完結できるようにしました。
App Intents を使い、ボタンそのものに操作を紐づけています。アプリを開かせない、という方針を徹底するなら、表示だけ出して操作のためにアプリへ戻らせるのは筋が通りません。
ウィジェットの更新制約と付き合う
ウィジェットとロック画面は、アプリ側が好きなタイミングで書き換えられません。OS が更新の回数を握っていて、頻度を上げようとしても通らない。
そのため「更新のたびに次の単語を決める」のではなく、あらかじめ一定期間ぶんの表示内容を積んでおく作りにしています。更新が絞られても表示が固まらず、かつ電池を無駄に使わない落とし所を探した結果です。
1 つのソースから、別のアプリを出す
英単語版と同じ仕組みで、漢字版と年号版を出しています。学習する対象が違うだけで、覚える体験の骨格は変わらないためです。
分岐だらけの 1 つのアプリにはしませんでした。代わりに、派生ごとの差分を定義ファイルに持たせています。ディレクトリ名や型名の対応関係をそこに書いておき、本体の変更を機械的に写し取る運用です。単語を扱う型は漢字を扱う型へ、という具合に名前まで置き換わります。
この形にしたのは、片方だけで通用する妥協が入り込む余地を無くしたかったからです。本体に加えた改善は、そのまま全部の派生に届きます。
見た目の決まりを先に固める
色・字送り・余白・角丸・アニメーションをトークンとして定義し、画面側での直接指定を禁じています。表示面が複数あるアプリで各画面が自由に値を書くと、本体とウィジェットで微妙に違う、という状態がすぐに生まれます。
配色はライトモードに固定し、紙の質感を変える形でテーマを 5 種類用意しました。ダークモードを両方作ると、紙らしさの調整がどっちつかずになるためです。動きを減らす設定にも対応しており、アニメーションは専用の入口を通してのみ書けるようにしています。
