@@ -25,8 +25,8 @@ struct FloatingPanel<Content>: View where Content: View {
25
25
let attributionBarHeight : CGFloat
26
26
/// The background color of the floating panel.
27
27
let backgroundColor : Color ?
28
- /// A binding to the currently selected detent.
29
- @Binding var selectedDetent : FloatingPanelDetent
28
+ /// A binding to the current active detent.
29
+ @Binding var activeDetent : FloatingPanelDetent
30
30
/// A binding to a Boolean value that determines whether the view is presented.
31
31
@Binding var isPresented : Bool
32
32
/// The content shown in the floating panel.
@@ -52,6 +52,11 @@ struct FloatingPanel<Content>: View where Content: View {
52
52
/// The maximum allowed height of the content.
53
53
@State private var maximumHeight : CGFloat = . zero
54
54
55
+ /// The detent that was the active detent until a FloatingPanelDetentPreference was set.
56
+ ///
57
+ /// When the FloatingPanelDetentPreference is unset, this detent should be restored to the active detent..
58
+ @State private var overriddenDetent : FloatingPanelDetent ?
59
+
55
60
var body : some View {
56
61
GeometryReader { geometryProxy in
57
62
VStack ( spacing: 0 ) {
@@ -64,6 +69,24 @@ struct FloatingPanel<Content>: View where Content: View {
64
69
. padding ( . bottom, isPortraitOrientation ? keyboardHeight - geometryProxy. safeAreaInsets. bottom : . zero)
65
70
. frame ( height: height)
66
71
. clipped ( )
72
+ . onPreferenceChange ( FloatingPanelDetent . Preference. self) { preference in
73
+ if let preference {
74
+ // Only update the overridden detent if one
75
+ // wasn't already saved. This prevents a
76
+ // FloatingPanelDetentPreference from being
77
+ // saved as the overridden detent.
78
+ if overriddenDetent == nil {
79
+ overriddenDetent = activeDetent
80
+ }
81
+ activeDetent = preference
82
+ } else if let overriddenDetent {
83
+ // When the FloatingPanelDetentPreference is
84
+ // unset, restore the overridden detent as the
85
+ // active detent.
86
+ activeDetent = overriddenDetent
87
+ self . overriddenDetent = nil
88
+ }
89
+ }
67
90
if !isPortraitOrientation {
68
91
Divider ( )
69
92
makeHandleView ( )
@@ -98,7 +121,7 @@ struct FloatingPanel<Content>: View where Content: View {
98
121
. onChange ( of: isPresented) {
99
122
updateHeight ( )
100
123
}
101
- . onChange ( of: selectedDetent ) {
124
+ . onChange ( of: activeDetent ) {
102
125
updateHeight ( )
103
126
}
104
127
. onKeyboardStateChanged { state, height in
@@ -138,11 +161,18 @@ struct FloatingPanel<Content>: View where Content: View {
138
161
let predictedEndLocation = $0. predictedEndLocation. y
139
162
let inferredHeight = isPortraitOrientation ? maximumHeight - predictedEndLocation : predictedEndLocation
140
163
141
- selectedDetent = [ . summary, . half, . full]
164
+ activeDetent = [ . summary, . half, . full]
142
165
. map { ( detent: $0, height: heightFor ( detent: $0) ) }
143
166
. min { abs ( inferredHeight - $0. height) < abs ( inferredHeight - $1. height) } !
144
167
. detent
145
168
169
+ if overriddenDetent != nil {
170
+ // Update the overridden detent with the user's choice to
171
+ // prevent the user's choice from being unset when the
172
+ // FloatingPanelDetentPreference is unset.
173
+ overriddenDetent = activeDetent
174
+ }
175
+
146
176
if $0. translation. height. magnitude > 100 {
147
177
UIApplication . shared. sendAction ( #selector( UIResponder . resignFirstResponder) , to: nil , from: nil , for: nil )
148
178
}
@@ -180,7 +210,7 @@ struct FloatingPanel<Content>: View where Content: View {
180
210
} else if keyboardState == . opening || keyboardState == . open {
181
211
return heightFor ( detent: . full)
182
212
} else {
183
- return heightFor ( detent: selectedDetent )
213
+ return heightFor ( detent: activeDetent )
184
214
}
185
215
} ( )
186
216
withAnimation { height = max ( 0 , ( newHeight - . handleFrameHeight) ) }
0 commit comments