Skip to content

Commit

Permalink
Make off-screen pinning much more precise.
Browse files Browse the repository at this point in the history
This fixes issues with various system fixed headers (search bar) and when dynamic text is used.
  • Loading branch information
gh123man committed May 31, 2022
1 parent 3c35feb commit db4ae16
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 5 deletions.
35 changes: 35 additions & 0 deletions Examples/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,15 @@ import Refresher
struct ContentView: View {

@State var refreshed = 0
@State var searchText = ""
var body: some View {
NavigationView {
ScrollView {
if #available(iOS 15.0, *) {
Text("Searching for \(searchText)")
.searchable(text: $searchText)
.navigationTitle("Searchable")
}
VStack {
Text("Hello, world!")
Text("Refreshed: \(refreshed)")
Expand All @@ -34,6 +40,10 @@ struct ContentView: View {
Text("Go to details with system style - no image")
.padding()
}
NavigationLink(destination: DetailsSearch()) {
Text("Go to details with system style and search bar in header")
.padding()
}
ForEach((1...100), id: \.self) { _ in
Text("asdf")
}
Expand All @@ -49,6 +59,31 @@ struct ContentView: View {
}
}

struct DetailsSearch: View {
@State var refreshed = 0
@State var searchText = ""
var body: some View {
ScrollView {
VStack {
if #available(iOS 15.0, *) {
Text("Searching for \(searchText)")
.searchable(text: $searchText)
.navigationTitle("Searchable")
}
Text("Details!")
Text("Refreshed: \(refreshed)")
}
}
.refresher(style: .system) { done in
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2)) {
refreshed += 1
done()
}
}
.navigationBarTitle("", displayMode: .inline)
}
}

struct DetailsView: View {
@State var refreshed = 0
var style: Style
Expand Down
8 changes: 7 additions & 1 deletion Sources/Refresher/RefreshSpinner.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,13 @@ public struct RefreshSpinnerView<RefreshView: View>: View {
if case .refreshing = mode {
return lerp(from: refreshHoldPoint, to: stopPoint, by: percent)
}
return lerp(from: offScreenPoint, to: stopPoint, by: normalize(from: pullClipPoint, to: 1, by: percent))
let normalizedPercent = normalize(from: pullClipPoint, to: 1, by: percent)
if normalizedPercent == 0 {
// Since the spinner view moves with the scrollview, move it
// backwards until we are ready to start the refreshing animation
return -headerInset + offScreenPoint * (1 + percent)
}
return lerp(from: -headerInset + offScreenPoint, to: stopPoint, by: normalizedPercent)
}

public var body: some View {
Expand Down
9 changes: 5 additions & 4 deletions Sources/Refresher/Refresher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ public struct Config {
/// Offset where the spinner stops moving after draging
public var defaultSpinnerSpinnerStopPoint: CGFloat

/// Off screen start point for the spinner
/// Off screen start point for the spinner (relative to the top of the screen)
/// TIP: set this to the max height of your spinner view if using a custom spinner.
public var defaultSpinnerOffScreenPoint: CGFloat

/// How far you have to pull (from 0 - 1) for the spinner to start moving
Expand All @@ -33,7 +34,7 @@ public struct Config {
refreshAt: CGFloat = 120,
headerShimMaxHeight: CGFloat = 75,
defaultSpinnerSpinnerStopPoint: CGFloat = -50,
defaultSpinnerOffScreenPoint: CGFloat = -150,
defaultSpinnerOffScreenPoint: CGFloat = -50,
defaultSpinnerPullClipPoint: CGFloat = 0.1,
systemSpinnerOpacityClipPoint: CGFloat = 0.2,
holdTime: DispatchTimeInterval = .milliseconds(300),
Expand Down Expand Up @@ -145,7 +146,7 @@ public struct RefreshableScrollView<Content: View, RefreshView: View>: View {
@ViewBuilder
private var refershSpinner: some View {
if showRefreshControls && (state.style == .default || state.style == .overlay) {
RefreshSpinnerView(offScreenPoint: config.defaultSpinnerOffScreenPoint,
RefreshSpinnerView(offScreenPoint: config.defaultSpinnerOffScreenPoint,
pullClipPoint: config.defaultSpinnerPullClipPoint,
mode: state.modeAnimated,
stopPoint: config.defaultSpinnerSpinnerStopPoint,
Expand Down Expand Up @@ -208,7 +209,7 @@ public struct RefreshableScrollView<Content: View, RefreshView: View>: View {
state.dragPosition = normalize(from: 0, to: config.refreshAt, by: distance)

guard canRefresh else {
canRefresh = distance <= config.resetPoint && state.mode == .notRefreshing && !isFingerDown
canRefresh = distance <= config.resetPoint && state.mode == .notRefreshing
return
}
guard distance > 0, showRefreshControls else {
Expand Down

0 comments on commit db4ae16

Please sign in to comment.