Skip to content

Commit 01a645b

Browse files
authored
PullingControl (#71)
1 parent 71341c2 commit 01a645b

File tree

5 files changed

+450
-59
lines changed

5 files changed

+450
-59
lines changed

Development/Development.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ let package = Package(
2828
targets: ["StickyHeader"]
2929
),
3030
.library(
31-
name: "RefreshControl",
32-
targets: ["RefreshControl"]
31+
name: "PullingControl",
32+
targets: ["PullingControl"]
3333
),
3434
.library(
3535
name: "SelectableForEach",
@@ -66,8 +66,9 @@ let package = Package(
6666
]
6767
),
6868
.target(
69-
name: "RefreshControl",
69+
name: "PullingControl",
7070
dependencies: [
71+
.product(name: "SwiftUIIntrospect", package: "swiftui-introspect")
7172
]
7273
),
7374
.target(

README.md

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ struct AdvancedCollectionView: View {
206206
spacing: 8
207207
)
208208
) {
209-
// Header with refresh control
209+
// Header with refresh control (from PullingControl module)
210210
RefreshControl(
211211
threshold: 60,
212212
action: {
@@ -502,12 +502,64 @@ StickyHeader(sizing: .fixed(250)) { context in
502502
}
503503
```
504504

505-
### 6. RefreshControl
505+
### 6. PullingControl
506506

507-
Custom pull-to-refresh control for ScrollView with customizable appearance.
507+
A two-layered pull gesture detection system for ScrollView. Provides both low-level pull detection (`PullingControl`) and high-level pull-to-refresh functionality (`RefreshControl`).
508+
509+
#### Low-Level: PullingControl
510+
511+
Detects pull gestures and provides pull distance, progress, and threshold state. Use this when you need custom pull-based interactions beyond refresh.
508512

509513
```swift
510-
import RefreshControl
514+
import PullingControl
515+
516+
struct CustomPullView: View {
517+
@State private var log: [String] = []
518+
519+
var body: some View {
520+
ScrollView {
521+
VStack(spacing: 0) {
522+
PullingControl(
523+
threshold: 80,
524+
onChange: { context in
525+
// Called when pull state changes
526+
if context.isThresholdReached {
527+
log.append("Threshold reached!")
528+
}
529+
}
530+
) { context in
531+
if context.isPulling {
532+
VStack {
533+
Text("Pull progress: \(Int(context.progress * 100))%")
534+
Text(context.isThresholdReached ? "Release!" : "Keep pulling")
535+
}
536+
.padding()
537+
}
538+
}
539+
540+
LazyVStack {
541+
ForEach(log, id: \.self) { message in
542+
Text(message)
543+
}
544+
}
545+
}
546+
}
547+
}
548+
}
549+
```
550+
551+
**PullingContext Properties:**
552+
- `pullDistance: CGFloat` - Current pull distance in points
553+
- `progress: Double` - Normalized progress (0.0 to 1.0)
554+
- `isThresholdReached: Bool` - Whether threshold is reached
555+
- `isPulling: Bool` - Whether currently pulling
556+
557+
#### High-Level: RefreshControl
558+
559+
Built on top of `PullingControl` with async action execution, refreshing state management, and haptic feedback.
560+
561+
```swift
562+
import PullingControl
511563

512564
struct RefreshableList: View {
513565
@State private var items: [Item] = []
@@ -556,13 +608,26 @@ struct RefreshableList: View {
556608
}
557609
```
558610

611+
**RefreshControlContext States:**
612+
- `.idle` - Not pulling
613+
- `.pulling(progress: Double)` - User is pulling
614+
- `.refreshing` - Refresh action is executing
615+
- `.finishing` - Refresh completed (optional for animations)
616+
617+
**When to Use Which:**
618+
- **PullingControl**: Custom pull-based interactions, analytics, custom state management
619+
- **RefreshControl**: Standard pull-to-refresh functionality
620+
559621
## Architecture Comparison
560622

561623
| Module | Implementation | Use Case |
562624
|--------|---------------|----------|
563625
| **DynamicList** | UIKit UICollectionView with SwiftUI hosting | Maximum performance, large datasets, complex layouts |
564626
| **CollectionView** | Pure SwiftUI (ScrollView + Lazy stacks) | Simple layouts, moderate datasets, pure SwiftUI apps |
565627
| **SelectableForEach** | Pure SwiftUI with environment values | Add selection to any container view |
628+
| **ScrollTracking** | SwiftUI with introspection | Infinite scrolling, additional content loading |
629+
| **StickyHeader** | Pure SwiftUI with geometry tracking | Sticky headers with stretching effects |
630+
| **PullingControl** | Pure SwiftUI with geometry tracking | Pull-to-refresh and custom pull gestures |
566631

567632

568633

0 commit comments

Comments
 (0)