[Xcode/SwiftUI] ローディング中のプレースホルダーを表示する (.redacted)

実装

import SwiftUI

struct Tweet: Identifiable {
    let id = UUID()
    let username: String
    let handle: String
    let time: String
    let content: String
}

struct TweetRow: View {
    let tweet: Tweet

    var body: some View {
        HStack(alignment: .top, spacing: 12) {
            Circle()
                .fill(Color.gray.opacity(0.3))
                .frame(width: 48, height: 48)

            VStack(alignment: .leading, spacing: 4) {
                HStack {
                    Text(tweet.username)
                        .font(.headline)
                    Text(tweet.handle)
                        .foregroundColor(.gray)
                    Text("· \(tweet.time)")
                        .foregroundColor(.gray)
                        .font(.subheadline)
                }
                Text(tweet.content)
                    .font(.body)
            }
        }
        .padding(.vertical, 8)
    }
}

struct HomeView: View {
    @State private var isLoading = true
    @State private var tweets: [Tweet] = []

    var body: some View {
        NavigationView {
            List {
                ForEach(isLoading ? Array(repeating: Tweet(username: "", handle: "", time: "", content: ""), count: 6) : tweets) { tweet in
                    TweetRow(tweet: tweet)
                        .redacted(reason: isLoading ? .placeholder : []) // ローディング中はplaceholder表示
                }
            }
            .navigationTitle("Home")
        }
        .onAppear {
            // Simulate data loading
            DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
                tweets = [
                    Tweet(username: "Elon Musk", handle: "@elonmusk", time: "1h", content: "Just landed Starship on Mars 🚀"),
                    Tweet(username: "Taylor Swift", handle: "@taylorswift13", time: "2h", content: "Lover is out now 💕 #TS"),
                    Tweet(username: "Tim Cook", handle: "@tim_cook", time: "3h", content: "Excited for WWDC! See you all there."),
                    Tweet(username: "Craig Federighi", handle: "@hairforceone", time: "5h", content: "Working on some spicy SwiftUI updates 🔥"),
                    Tweet(username: "Neil deGrasse Tyson", handle: "@neiltyson", time: "6h", content: "The universe is vast and wonderful."),
                    Tweet(username: "Bill Gates", handle: "@BillGates", time: "7h", content: "Working on eradicating polio. Progress is being made."),
                    Tweet(username: "Lady Gaga", handle: "@ladygaga", time: "8h", content: "Love to all my little monsters! 💖"),
                    Tweet(username: "Dwayne Johnson", handle: "@TheRock", time: "9h", content: "Just finished a killer workout! #IronParadise"),
                    Tweet(username: "Gordon Ramsay", handle: "@GordonRamsay", time: "10h", content: "This lamb is raw! Absolutely shocking."),
                    Tweet(username: "Emma Watson", handle: "@EmmaWatson", time: "11h", content: "Books are magical portals to new worlds."),
                    Tweet(username: "Stephen Curry", handle: "@StephenCurry30", time: "12h", content: "Game day! Let's go Warriors!"),
                    Tweet(username: "Beyoncé", handle: "@Beyonce", time: "13h", content: "Feeling the love from all my fans. You are my everything."),
                    Tweet(username: "Leonardo DiCaprio", handle: "@LeoDiCaprio", time: "14h", content: "Climate change is real. We need action now."),
                    Tweet(username: "Ariana Grande", handle: "@ArianaGrande", time: "15h", content: "Thank you for all the love and support. I adore you all.")
                ]
                isLoading = false
            }
        }
    }
}