Die List in Swift UI - Teil 10 - Pull to Refresh


Eine weitere Neuerung in iOS15 ist eine Funktion, um Listen durch ziehen vom oberen Bildschirmrand zu aktualisieren. Allerdings liefert Apple hier nicht wirklich den Mechanismus, um den Inhalt der Liste neu aufzubauen, sondern lediglich die passende Animation und eine Closure. Trotzdem ist es eine immense Arbeitserleichterung. In der Vergangenheit haben Entwickler diese Pull-to-Refresh-Funktion selbst implementiert. Jetzt genügt ein einzelner View-Modifier. Es ist refreshable, der an die List angehängt werden muss.

Im aktuellen Projekt gibt es keine Notwendigkeit, die List zu aktualisieren, denn der Inhalt ändert sich nicht. Um den View-Modifier auszuprobieren, soll deshalb ein Mechanismus implementiert werden, der bei Pull-to-Refresh eine weitere zufällige Person der Liste hinzufügt. Nur wenige Anweisungen sind nötig.

.refreshable {

    self.repo.addRandomPerson()

}

Das komplette Listing des ContentView

import SwiftUI


struct ContentViewView {

    

    @ObservedObject var repo = PersonsRepository(randomPersonsCount10)

    

    init() {

        let customAppearance = UINavigationBarAppearance()

        // Backgroundcolor

        customAppearance.backgroundColor = UIColor.lightGray

        // Font color for navigationBarTitleDisplayMode large

        customAppearance.largeTitleTextAttributes = [.foregroundColorUIColor.white]

        // Font color for navigationBarTitleDisplayMode inline

        customAppearance.titleTextAttributes = [.foregroundColor: UIColor.white]

        

        UINavigationBar.appearance().standardAppearance = customAppearance

        UINavigationBar.appearance().compactAppearance = customAppearance

        UINavigationBar.appearance().scrollEdgeAppearance = customAppearance

    }

    

    var body: some View {

        

        NavigationView {

            List {

                ForEach (self.repo.getSections(), id:\.self ) { section in

                    Section(header: SectionHeader(headlineText: section)) {

                        ForEach(self.repo.persons.filter {$0.company == section}  , id: \.id) { person in

                            NavigationLink (destination: PersonDetailView(person: person))

                            {

                                PersonListCell(person: person)

                                    .badge(Text(person.getAge())

                                            .foregroundColor(Color.blue)

                                            .font(.subheadline )

                                    )

                            }

                            .swipeActions(edge: .leading , allowsFullSwipe: true) {

                                Button {

                                    print("Sent Button")

                                } label: {

                                    Label("Send", systemImage: "paperplane.fill")

                                }

                                .tint(.indigo)

                                

                                Button {

                                    print("Bookmark Button")

                                } label: {

                                    Label("Bookmark", systemImage: "bookmark.circle")

                                }

                                .tint(.teal)

                            }

                            

                            .swipeActions(edge: .trailing , allowsFullSwipe: true) {

                                Button {

                                    withAnimation {

                                        self.repo.delete(person: person)

                                    }

                                } label: {

                                    Label("Delete", systemImage: "trash.fill")

                                }

                                .tint(.red)

                            }

                        }

                    }

                }

                .listRowSeparatorTint( Color(red: 0.2, green: 0, blue: 1.0, opacity: 0.5) )

                

            }.listStyle(PlainListStyle())

                .refreshable {

                    self.repo.addRandomPerson()

                }

                .navigationTitle("List and People")

                .navigationBarTitleDisplayMode(.large)

                .navigationBarItems(trailing:

                                        Button(action: {

                    self.repo.addRandomPerson()

                }) {

                    Image(systemName: "plus.circle.fill")

                } )

        }

    }

}

Stacks Image 198

Die Anweisungen, die bei einem Pull-to-Refresh ausgeführt werden, können durchaus etwas dauern. Werden beispielsweise Daten aus dem Internet nachgeladen, passiert das nicht umgehend. Es ist daher zu empfehlen, den Code dort asynchron auszuführen. Mit async und await ist es glücklicherweise nicht schwer. Leider ist es nicht möglich, die Funktion addRandomPerson in eine Funktion umzuwandeln, die asynchon ausgeführt wird. Weil sie ebenfalls durch den Button in der Naviagtionsleiste aufgerufen wird, muss sie synchron sein. Es spricht aber nichts dagegen, die Klasse PersonsRepository um eine weitere Methode zu erweitern, die dann addRandomPerson aufruft. So eine Methode könnte beispielsweise addRandomPersonAsync heißen.

func addRandomPersonAsync() async  {

        self.addRandomPerson()

}

    

func addRandomPerson() {

        self.persons.insert(RandomPersonGenerator.shared.generate(), at0)

}

In der View muss dann noch nur die asynchrone Methode aufgerufen werden.

.refreshable {

    await self.repo.addRandomPersonAsync()

}

Zugegeben, zur Demonstration der Befehle async und await ist es ein schlechtes Beispiel, weil die Ausführung nicht wirklich lange dauert. Aber so könnte es funktionieren.


Geschrieben am: 29.08.2021
Technologien: SwiftUI, List