// Authoer: The SwiftUI Lab // Full article: https://swiftui-lab.com/scrollview-pull-to-refresh/ import SwiftUI struct ContentView: View { @ObservedObject var model = MyModel() @State private var alternate: Bool = true let array = Array(repeating: "Hello", count: 100) let transaction = Transaction(animation: .easeInOut(duration: 2.0)) var body: some View { return VStack(spacing: 0) { HeaderView(title: "Dog Roulette") RefreshableScrollView(height: 70, refreshing: self.$model.loading) { DogView(dog: self.model.dog).padding(30).background(Color(UIColor.systemBackground)) }.background(Color(UIColor.secondarySystemBackground)) } } struct HeaderView: View { var title = "" var body: some View { VStack { Color(UIColor.systemBackground).frame(height: 30).overlay(Text(self.title)) Color(white: 0.5).frame(height: 3) } } } struct DogView: View { let dog: Dog var body: some View { VStack { Image(dog.picture, defaultSystemImage: "questionmark.circle.fill") .resizable() .aspectRatio(contentMode: .fit) .frame(height: 160) .clipShape(Circle()) .overlay(Circle().stroke(Color.white, lineWidth: 2)) .padding(2) .overlay(Circle().strokeBorder(Color.black.opacity(0.1))) .shadow(radius: 3) .padding(4) Text(dog.name).font(.largeTitle).fontWeight(.bold) Text(dog.origin).font(.headline).foregroundColor(.blue) Text(dog.description) .lineLimit(nil) .frame(height: 1000, alignment: .top) .padding(.top, 20) } } } } extension Image { init(_ name: String, defaultImage: String) { if let img = UIImage(named: name) { self.init(uiImage: img) } else { self.init(defaultImage) } } init(_ name: String, defaultSystemImage: String) { if let img = UIImage(named: name) { self.init(uiImage: img) } else { self.init(systemName: defaultSystemImage) } } }