-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathView+.swift
More file actions
115 lines (102 loc) · 3.37 KB
/
Copy pathView+.swift
File metadata and controls
115 lines (102 loc) · 3.37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
//
// View+.swift
// DevLog
//
// Created by 최윤진 on 11/22/25.
//
import SwiftUI
extension View {
@ViewBuilder
func onScrollOffsetChange(action: @escaping (CGFloat) -> Void) -> some View {
if #available(iOS 18, *) {
self.onScrollGeometryChange(for: CGFloat.self) { geo in
geo.contentOffset.y + geo.contentInsets.top
} action: { _, newOffset in
action(newOffset)
}
} else {
self.background(ScrollViewOffsetTracker(onChange: action))
}
}
}
private struct ScrollViewOffsetTracker: UIViewRepresentable {
var onChange: (CGFloat) -> Void
func makeCoordinator() -> Coordinator {
Coordinator(onChange: onChange)
}
func makeUIView(context: Context) -> UIView {
let view = UIView()
view.isHidden = true
view.isUserInteractionEnabled = false
DispatchQueue.main.async {
guard let scrollView = Self.findScrollView(from: view) else { return }
context.coordinator.observe(scrollView)
}
return view
}
func updateUIView(_ uiView: UIView, context: Context) {}
private static func findScrollView(from view: UIView) -> UIScrollView? {
var current = view.superview
while let superview = current {
if let scrollView = superview as? UIScrollView {
return scrollView
}
for sibling in superview.subviews where sibling !== view {
if let scrollView = findScrollViewInSubviews(of: sibling) {
return scrollView
}
}
current = superview.superview
}
return nil
}
private static func findScrollViewInSubviews(of view: UIView) -> UIScrollView? {
if let scrollView = view as? UIScrollView {
return scrollView
}
for subview in view.subviews {
if let scrollView = findScrollViewInSubviews(of: subview) {
return scrollView
}
}
return nil
}
class Coordinator: NSObject {
private var onChange: (CGFloat) -> Void
private var observation: NSKeyValueObservation?
init(onChange: @escaping (CGFloat) -> Void) {
self.onChange = onChange
}
func observe(_ scrollView: UIScrollView) {
observation = scrollView.observe(\.contentOffset, options: [.new]) { [weak self] scrollView, _ in
let offset = scrollView.contentOffset.y + scrollView.adjustedContentInset.top
self?.onChange(offset)
}
}
deinit {
observation?.invalidate()
}
}
}
extension View {
@ViewBuilder
func adaptiveButtonStyle<S: InsettableShape>(
shape: S = Capsule(),
color: Color = .clear
) -> some View {
if #available(iOS 26.0, *) {
self.foregroundStyle(Color(.label))
.padding(8)
.glassEffect(.regular.tint(color), in: shape)
.clipShape(shape)
} else {
self.foregroundStyle(Color(.label))
.padding(8)
.background {
shape
.fill(color == .clear ? Color(.systemGray5) : color)
.strokeBorder(Color.white.opacity(0.2), lineWidth: 1)
}
}
}
}