Post

Replies

Boosts

Views

Activity

Reply to SwiftUI Pull to Refresh Support
I implemented a custom RefreshableScrollView using PreferenceKey import SwiftUI /// RefreshableScrollView public struct RefreshableScrollView<Content:View>: View {   @Binding private var isRefreshing: Bool   @State private var offset: CGFloat = 0   @State private var canRefresh: Bool = true   private var content: () -> Content   private let threshold: CGFloat = 50.0       public init(     isRefreshing: Binding<Bool>,     @ViewBuilder content: @escaping () -> Content   ) {     self._isRefreshing = isRefreshing     self.content = content   }       public var body: some View {     GeometryReader { geometry in       ScrollView {         VStack(spacing: 0) {           if isRefreshing || !(canRefresh) {             ProgressView()               .progressViewStyle(                 CircularProgressViewStyle(tint: Color.purple)               )           } else {             Image("arrowDown")               .resizable()               .frame(width: 22, height: 22, alignment: .center)               .foregroundColor(Color.purple)               .padding(.top, -21)               .rotationEffect(.degrees((offset < (threshold - 2)) ? 0 : 180))               .animation(.easeInOut(duration: 0.5))           }           content()             .anchorPreference(key: OffsetPreferenceKey.self, value: .top) {               geometry[$0].y             }         }       }       .onPreferenceChange(OffsetPreferenceKey.self) { offset in         DispatchQueue.main.async {           if canRefresh {             self.offset = offset             if offset > threshold && canRefresh {               withAnimation { /// In case u need haptic feel                 hapticSuccess()                 isRefreshing = true               }               canRefresh = false             }           } else {             if offset < 21 {               canRefresh = true             }           }         }       }       .animation(.easeInOut, value: isRefreshing)     }   } } fileprivate struct OffsetPreferenceKey: PreferenceKey {   static var defaultValue: CGFloat = 0       static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {     value = nextValue()   } } public extension View {   func hapticSuccess() {     let generator = UINotificationFeedbackGenerator()     generator.notificationOccurred(.success)   } /// In case u need a modifier func refreshable(isRefreshing: Binding<Bool>) -> some View {     modifier(RefreshableScrollViewModifier(isRefreshing: isRefreshing))   } }
Nov ’21