Post

Replies

Boosts

Views

Activity

How to transition views in a List View when it appears (SwiftUI)
There are views in a ListView. The views have the transition modifiers on them but no transition occurs. The List is made to appear first before its chid views are rendered. Here's some code to illustrate the problem: The StateObject: class TripsStore: ObservableObject { @Published private(set) var trips: [Trip] = [] @MainActor func getTrips() async throws { ... } } The View struct TripsStore: View { @StateObject private var tripsStore: TripsStore = TripsStore() @State private var progress: RequestStatus = .idle @State private var availableTrips: Set<UUID?> = [] var body: some View { NavigationStack { Group { if progress == .loading { ProgressView() } else { List(tripsStore.trips) { trip in if availableTrips.contains(trip.id) { TripCard(trip: trip) .transition(.asymmetric(insertion: .opacity, removal: .scale).animation(.easeInOut(duration: 3.5))) } } .onAppear { withAnimation { tripsStore.trips.forEach { trip in availableTrips.insert(trip.id) } } } } } .task { progress = .loading do { try await tripsStore.getTrips() } catch { print(error) } progress = .idle } } } } By using a GroupView, trip data is fetched and List is only rendered when that data is available. The appearing of each trip card is animated when the list is about to appear using the .onAppear modifier. Checking if a trip is available, should "insert" the trip's card into the already appeared ListView. During insertion, the transition ought to occur. Unfortunately, it's not happening. Does anyone know why? How can it be fixed?
0
0
286
May ’23
Async task cancelled in Refreshable Modifier on Scrollview on iOS 16
I'm trying to use the refreshable modifier on a Scrollview in an app that targets iOS 16. But the asynchronus task gets cancelled during the pull to refresh gesture. It was tested on a physical device. Here is some code that demonstrates the problem and an image with the error printed: ExploreViewModel.swift class ExploreViewModel: ObservableObject { @Published var randomQuotes: [Quote] = [] init() { Task { await loadQuotes() } } @MainActor func loadQuotes() async { let quotesURL = URL(string: "https://type.fit/api/quotes")! do { let (data, urlResponse) = try await URLSession.shared.data(from: quotesURL) guard let response = urlResponse as? HTTPURLResponse else { print("no response"); return} if response.statusCode == 200 { let quotes = try JSONDecoder().decode([Quote].self, from: data) randomQuotes.append(contentsOf: quotes) } } catch { debugPrint(error) debugPrint(error.localizedDescription) } } func clearQuotes() { randomQuotes.removeAll() } } Content.swift import SwiftUI struct ContentView: View { @StateObject private var exploreVM = ExploreViewModel() var body: some View { NavigationStack { ExploreView() .environmentObject(exploreVM) .refreshable { exploreVM.clearQuotes() await exploreVM.loadQuotes() } } } } ExploreView.swift import SwiftUI struct ExploreView: View { @EnvironmentObject var exploreVM: ExploreViewModel var body: some View { ScrollView { VStack { LazyVGrid(columns: [GridItem(.adaptive(minimum: 140.0), spacing: 24.0)], spacing: 24.0) { ForEach(exploreVM.randomQuotes) { quote in VStack(alignment: .leading) { Text("\(quote.text ?? "No Text")") .font(.headline) Text("\(quote.author ?? "No Author")") .font(.caption) } .frame(minWidth: 0, maxWidth: .infinity) .frame(height: 144.0) .border(Color.red, width: 2.0) } } } .padding() .navigationTitle("Explore") } } } Printed Error
2
3
1.9k
Jan ’23