zoukankan      html  css  js  c++  java
  • SwiftUI 下拉刷新

    import SwiftUI

    struct RefreshScrollView<Content: View>: View {

        @State private var preOffset: CGFloat = 0

        @State private var offset: CGFloat = 0

        @State private var frozen = false

        @State private var rotation: Angle = .degrees(0)

        @State private var updateTime: Date = Date()

        

        var threshold: CGFloat = 70

        @Binding var refreshing: Bool

        let content: Content

        

        init(_ threshold: CGFloat = 70, refreshing: Binding<Bool>, @ViewBuilder content: () -> Content) {

            self.threshold = threshold

            self._refreshing = refreshing

            self.content = content()

        }

        

        var body: some View {

            VStack {

                ScrollView {

                    ZStack(alignment: .top) {

                        MovingPositionView()

                        

                        VStack {

                            self.content

                                .alignmentGuide(.top, computeValue: { _ in

                                    (self.refreshing && self.frozen) ? -self.threshold : 0

                                })

                        }

                        

                        RefreshHeader(height: self.threshold,

                                      loading: self.refreshing,

                                      frozen: self.frozen,

                                      rotation: self.rotation,

                                      updateTime: self.updateTime)

                    }

                }

                .background(FixedPositionView())

                

                .onPreferenceChange(RefreshPreferenceTypes.RefreshPreferenceKey.self) { values in

                    self.calculate(values)

                }

                .onChange(of: refreshing) { refreshing in

                    DispatchQueue.main.async {

                        if !refreshing {

                            self.updateTime = Date()

                        }

                    }

                }

            }

        }

        

        func calculate(_ values: [RefreshPreferenceTypes.RefreshPreferenceData]) {

            DispatchQueue.main.async {

                /// 计算croll offset

                let movingBounds = values.first(where: { $0.viewType == .movingPositionView })?.bounds ?? .zero

                let fixedBounds = values.first(where: { $0.viewType == .fixedPositionView })?.bounds ?? .zero

                

                self.offset = movingBounds.minY - fixedBounds.minY

                

                self.rotation = self.headerRotation(self.offset)

                /// 触发刷新

                if !self.refreshing, self.offset > self.threshold, self.preOffset <= self.threshold {

                    self.refreshing = true

                }

                

                if self.refreshing {

                    if self.preOffset > self.threshold, self.offset <= self.threshold {

                        self.frozen = true

                    }

                } else {

                    self.frozen = false

                }

                

                self.preOffset = self.offset

            }

        }

        

        func headerRotation(_ scrollOffset: CGFloat) -> Angle {

            if scrollOffset < self.threshold * 0.60 {

                return .degrees(0)

            } else {

                let h = Double(self.threshold)

                let d = Double(scrollOffset)

                let v = max(min(d - (h * 0.6), h * 0.4), 0)

                return .degrees(180 * v / (h * 0.4))

            }

        }

        

    //     位置固定不变的view

        struct FixedPositionView: View {

            var body: some View {

                GeometryReader { proxy in

                    Color

                        .clear

                        .preference(key: RefreshPreferenceTypes.RefreshPreferenceKey.self,

                                    value: [RefreshPreferenceTypes.RefreshPreferenceData(viewType: .fixedPositionView, bounds: proxy.frame(in: .global))])

                }

            }

        }

        

    //     位置随着滑动变化的view,高度为0

        struct MovingPositionView: View {

            var body: some View {

                GeometryReader { proxy in

                    Color

                        .clear

                        .preference(key: RefreshPreferenceTypes.RefreshPreferenceKey.self,

                                    value: [RefreshPreferenceTypes.RefreshPreferenceData(viewType: .movingPositionView, bounds: proxy.frame(in: .global))])

                }

                .frame(height: 0)

            }

        }

        

        struct RefreshHeader: View {

            var height: CGFloat

            var loading: Bool

            var frozen: Bool

            var rotation: Angle

            var updateTime: Date

            

            let dateFormatter: DateFormatter = {

                let df = DateFormatter()

                df.dateFormat = "MM月dd日 HH时mm分ss秒"

                return df

            }()

            

            var body: some View {

                HStack(spacing: 20) {

                    Spacer()

                    

                    Group {

                        if self.loading {

                            VStack {

                                Spacer()

                                ActivityRep()

                                Spacer()

                            }

                        } else {

                            Image(systemName: "arrow.down")

                                .resizable()

                                .aspectRatio(contentMode: .fit)

                                .rotationEffect(rotation)

                        }

                    }

                    .frame( height * 0.25, height: height * 0.8)

                    .fixedSize()

                    .offset(y: (loading && frozen) ? 0 : -height)

                    

                    VStack(spacing: 5) {

                        Text("(self.loading ? "正在刷新数据" : "下拉刷新数据")")

                            .foregroundColor(.secondary)

                            .font(.subheadline)

                        

                        Text("(self.dateFormatter.string(from: updateTime))")

                            .foregroundColor(.secondary)

                            .font(.subheadline)

                    }

                    .offset(y: -height + (loading && frozen ? +height : 0.0))

                    

                    Spacer()

                }

                .frame(height: height)

            }

        }

    }

    struct RefreshPreferenceTypes {

        enum ViewType: Int {

            case fixedPositionView

            case movingPositionView

        }

        

        struct RefreshPreferenceData: Equatable {

            let viewType: ViewType

            let bounds: CGRect

        }

        

        struct RefreshPreferenceKey: PreferenceKey {

            static var defaultValue: [RefreshPreferenceData] = []

            

            static func reduce(value: inout [RefreshPreferenceData],

                               nextValue: () -> [RefreshPreferenceData]) {

                value.append(contentsOf: nextValue())

            }

        }

    }

    struct ActivityRep: UIViewRepresentable {

        func makeUIView(context: UIViewRepresentableContext<ActivityRep>) -> UIActivityIndicatorView {

            return UIActivityIndicatorView()

        }

        

        func updateUIView(_ uiView: UIActivityIndicatorView, context: UIViewRepresentableContext<ActivityRep>) {

            uiView.startAnimating()

        }

    }

    群号:186052819
  • 相关阅读:
    169. Majority Element
    283. Move Zeroes
    1331. Rank Transform of an Array
    566. Reshape the Matrix
    985. Sum of Even Numbers After Queries
    1185. Day of the Week
    867. Transpose Matrix
    1217. Play with Chips
    766. Toeplitz Matrix
    1413. Minimum Value to Get Positive Step by Step Sum
  • 原文地址:https://www.cnblogs.com/zuidap/p/15014786.html
Copyright © 2011-2022 走看看