今回は情報カードのデザインを3回作り直した話と、SwiftUIのハマりポイントをいくつか。
情報カードを3回作り直した
アプリの主要な画面に、ユーザーの活動状況をまとめて表示する情報カードを作りました。ステータスバッジ、相手の情報、最新メッセージのプレビュー、未読マークなど、1枚のカードに必要な情報を詰め込みます。
v1は「情報が並んでるだけ」。最低限の要素はあるけど、SNSっぽさが足りない。
v2でSNS風レイアウトに全面リライト。左にアバター、右にコンテンツという典型的なSNS投稿の形に。各行にアイコンを配置して視認性を上げました。
v3で安全装備バッジの追加、アイコンサイズの統一、メニューの全状態対応など細部を詰めました。

1回で完成させようとせず、実際に触ってフィードバックを重ねながら育てていくのが結局一番良い仕上がりになる気がします。
「引っ張って更新」のUXをどうするか
リアルタイムでデータが自動更新されるアプリで、引っ張って更新(pull-to-refresh)は必要なのか?という問題。技術的には不要です。データは勝手に最新になるので。
でも結論としては残すことにしました。人間の心理として「引っ張ったら最新になる」という安心感は大事です。
ただし実際にデータを取り直す必要はないので、スピナーだけ回して何もしない「ダミーリフレッシュ」という仕組みにしました。0.5〜2秒のランダム遅延でくるくる回すだけ。これをアプリ全体の共通パターンとして切り出しています。
これはこのブログを読んでいる人だけに教える秘密です。
最初はデータの再取得をしていたんですが、引っ張るたびに画面がチラついてしまい、「あれ、そもそも再取得しなくてよくない?」という結論に至りました。遠回りしましたが、シンプルに収まりました。
タップが透明領域を突き抜ける
カードの右上に「…」メニューボタンを置いたんですが、タップ領域が小さすぎて押しにくい。しかもカード全体にタップ判定があるので、メニューを狙ったつもりが別の画面に飛んでしまう。
タップ領域を広げるテクニックをいろいろ試しましたが、なぜか成功しない。ところがデバッグ用に背景を黄色に塗ったら、急にタップが成功するようになりました。
原因は、SwiftUIでは透明な領域はタップイベントを通過させるという仕様。見えない部分を広げてもタップ判定はすり抜けて、下のカード全体に届いてしまう。色を塗ると「実体」ができるのでタップが成功する、というオチでした。
最終的には、カードと同じ背景色で塗ることで見た目は変わらないけどタップ判定は効くという解決策に。地味ですが、知らないとハマるポイントです。
ナビゲーションタイトルの罠
2つの画面をタブで切り替えるラッパー画面を作ったとき、タイトルが表示されない問題にハマりました。
ラッパー側でタイトルを設定しているのに、子画面の中で空文字のタイトルが設定されていて、それが親の設定を上書きしてしまう。SwiftUIの内部的な仕組みで、子の設定が親より優先されるためです。
ポイントは「空文字のタイトルを設定する」のと「タイトルを設定しない」は全く違うということ。前者は空文字が伝播して上書きし、後者は何もしないので親の設定がそのまま使われます。
子画面にフラグを追加して「タイトル設定をスキップするモード」を持たせることで解決しました。
相対時刻の表示を共通化
「3分前」「2時間前」のような相対時刻表示が、アプリの3箇所にコピペで散らばっていました。しかもフォーマットが微妙に違う。
共通のヘルパーに切り出して統一。地味ですが、フォーマットを変更するときに1箇所だけ直せば済むようになりました。
次のステップ
カードの作り直しを通じて、「とりあえず動くものを作る → 触ってみる → 直す」のサイクルの大事さを実感しました。次は画面遷移まわりの改善を進めていきます。


コメント