SwiftUI のアニメーション実装は、UIKit 時代に比べて宣言的で簡潔に書けるようになりました。けれど「思った通りに動かない」ときの沼は相変わらず深いです。.animation() を何重にも重ねてみたり、withAnimation のスコープを少しずつ変えてみたり、気づいたら1時間が過ぎている——そういった経験は今でもあります。
私が2013年から個人で運営しているiOSアプリ「Beautiful HD Wallpapers」は、累計5,000万ダウンロードを超えました。壁紙アプリというカテゴリは、スクロール・ズーム・ページング切り替えのアニメーションがユーザー体験の核になります。長年この開発を一人で続ける中で、Claude Code を使ったアニメーション実装の進め方が少しずつ変わりました。
今回は、私が実際に使っているプロンプトパターンを中心に、Claude Code で SwiftUI アニメーションの迷いを減らす具体的な方法を書きます。
「直して」と渡すだけではうまくいかない理由
Claude Code にコードを渡して「このアニメーションを改善して」と聞くだけでは、期待通りの答えが返ってこないことがあります。アニメーションの問題は、コードそのものより「何が問題で、どうなってほしいのか」が不明確なことが根本原因です。コードが技術的に正しくても、伝えたいことをユーザーに届けられていなければ間違っているのと同じです。
たとえば「タップするとカードがフリップする」という要件があるとします。Card.swift を丸ごと渡して「アニメーションを改善して」と聞いても、Claude Code は何を改善すればいいのか判断できません。フリップの速さが問題なのか、イージングが不自然なのか、フリップ中に裏面が一瞬ちらつくのか——そのどれかによって、最適な解決策がまったく異なります。
この状況で私がとるようになったアプローチは、「意図を3つの要素で言語化してから渡す」という方法です。これを始めてから、Claude Code から返ってくるコードの質が体感で大きく変わりました。
意図を伝える3要素の型
Beautiful HD Wallpapers の開発で定着したプロンプトの型があります。
[現状] タップするとカードが .rotation3DEffect で反転する。duration: 0.3 で一定速度。
[期待] 最初は速く、終わりに向かってゆっくりになる。裏面が見えてから少し「間」が欲しい。
[制約] iOS 16以上。Xcode 16.x。他の View には影響させない。
この3要素(現状・期待・制約)を揃えると、Claude Code が提案するコードの質が明らかに変わります。特に「制約」は重要で、対象の iOS バージョンや既存コードへの影響範囲を伝えることで、使えない提案がぐっと減ります。API の availability guard が必要なコードや、関係のない箇所のリファクタリングが必要なコードが返ってこなくなるからです。
「期待」の記述も、「もっと自然に」のような抽象的な表現ではなく、「最初は速く、終わりにかけて遅くなります。0.35秒程度」のように具体的に書くことで、Claude Code が最適化の方向性を正確に把握できます。
2013年にアプリ開発を始めた当初は、こういった情報を整理することなく「エラーを直して」という聞き方しかできていませんでした。Claude Code との対話を重ねるうちに、「問いの質が答えの質を決める」という感覚が自然に身につきました。この考え方は、PR の説明文やコードコメントにも良い影響をもたらしています。
壁紙アプリで使ったアニメーション実装パターン
ページング切り替えのカスタムアニメーション
Beautiful HD Wallpapers では、壁紙のページング時に現在の壁紙がスライドアウトしながら、次の壁紙がフェードしながら入ってくる演出を採用しています。当初は TabView のデフォルト動作を使っていましたが、「もう少しなめらかにしてほしい」というユーザーの声をもとに独自実装に切り替えました。
Claude Code に渡したプロンプト(要約):
[現状] TabView.tabViewStyle(.page) でページング。スワイプ時の切り替えが唐突に見える。
[期待] 現在の壁紙が左にスライドアウト、次の壁紙が右からフェードしながら入る。easeInOut で 0.35s 程度。
[制約] iOS 16+。壁紙は AsyncImage でロード中。ロード前はプレースホルダーを表示。
返ってきた提案をベースに整理したコード:
struct PageTransitionModifier: ViewModifier {
let offset: CGFloat
let opacity: Double
func body(content: Content) -> some View {
content
.offset(x: offset)
.opacity(opacity)
.animation(.easeInOut(duration: 0.35), value: offset)
}
}
// 使い側
WallpaperView(wallpaper: current)
.modifier(PageTransitionModifier(
offset: isTransitioning ? -UIScreen.main.bounds.width : 0,
opacity: isTransitioning ? 0 : 1
))Claude Code が最初から完璧な答えを出すことは少ないです。AsyncImage のロード状態との組み合わせは2〜3回のやり取りで調整しました。それでも「ゼロから考える」より「提案を磨く」方が、実装の迷走時間は大幅に短くなります。
タップ時のフィードバックアニメーション
壁紙サムネイルをタップして詳細ビューに遷移するとき、「選択されている」感を伝えるための小さなスケールアップが必要でした。最初は .spring() をパラメータなしで使っていましたが、終わりに小さなバウンスが残り、物理的な「押した感」が出ませんでした。
[現状] scaleEffect に .spring() を使用。最後に小さなバウンスが残る。
[期待] 1.0 から 1.05 に素早くスケールアップ。バウンスなし。「押した感」を出したい。
[制約] iOS 16+。直後に画面遷移が始まる——タイミングの連動が必要。
Claude Code が提案した調整:
withAnimation(.spring(response: 0.2, dampingFraction: 0.9)) {
isSelected = true
}dampingFraction を 1.0 に近づけるとバウンスが消え、response で速さを制御できます。この2つのパラメータの関係はドキュメントに書いてあることですが、実装中に忘れがちです。Claude Code がレビュー時に指摘してくれることで、ドキュメントに戻る手間が省けました。
コードレビューとしての使い方 — Before/After
Claude Code をコードレビュアーとして使う方法も効果的です。コードを生成してもらうより、既存のコードを渡して指摘を受ける——この使い方は、長くコードベースにいると気づかなくなった問題を発見するのに役立ちます。
Before(初期実装):
Button(action: { showDetail = true }) {
Image(uiImage: wallpaper.thumbnail)
.resizable()
.scaledToFill()
}
.animation(.spring(), value: showDetail)「アニメーション周りで改善できる箇所を指摘してください」と聞いた結果、3点の指摘が返ってきました。まず、.animation() をボタン自体に付けているため内部の全要素に影響が伝播すること。次に、showDetail の変化に対してどの View プロパティをアニメーションさせたいのかが不明確なこと。そして、.spring() のパラメータなしは iOS バージョンによって挙動が変わりうること、の3点です。
After(指摘をもとに修正):
Button(action: {
withAnimation(.spring(response: 0.35, dampingFraction: 0.7)) {
showDetail = true
}
}) {
Image(uiImage: wallpaper.thumbnail)
.resizable()
.scaledToFill()
.scaleEffect(showDetail ? 1.05 : 1.0)
}scaleEffect によってアニメーション対象のプロパティが明示され、withAnimation のスコープが状態変化に限定されました。廣川政樹として複数のアプリを個人で維持している状況では、コードレビューを他の開発者に依頼する機会が自然と少なくなります。Claude Code によるレビューが、その代替として機能しています。
パフォーマンス診断の初手として
壁紙アプリはメモリを多く使います。アニメーションとメモリ問題が重なると、低スペックデバイスでフレームレートが顕著に落ちます。こうした問題の原因は、アニメーション自体というより onAppear 内の重い処理や、ForEach 内で毎回 Image をデコードしているケースであることが多いです。特に5,000万DL超のアプリになると、ユーザーの端末バリエーションが広く、開発機では再現しない問題も少なくありません。
Instruments でプロファイリングする前に、Claude Code に「このアニメーション実装でパフォーマンスに問題が出そうな箇所を探してください」と依頼することを習慣にしています。静的解析として典型的な問題を検出してくれるため、Instruments を開いてから探す範囲を事前に絞り込めます。すべてを発見できるわけではありませんが、「探す」から「確認する」へのシフトが起きることで、プロファイリングにかける時間が短くなっています。
次のステップ
手元のプロジェクトで「アニメーションが曖昧なまま放置されている場所」を一つ選んでみてください。現状・期待・制約の3要素で言語化してから Claude Code に渡すと、具体的なフィードバックが返ってくるはずです。
この3要素を書く習慣は、Claude Code との対話を超えて、PR の説明やチームへの技術共有にも転用できます。私自身、まだ模索中ですが、共に学んでいけたら嬉しいです。