Skip to content

Commit d9ac916

Browse files
committed
Support watchOS to use digital crown for the zooming image
1 parent 5ca4965 commit d9ac916

File tree

1 file changed

+32
-13
lines changed

1 file changed

+32
-13
lines changed

Example/SDWebImageSwiftUIDemo/DetailView.swift

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,34 +15,62 @@ struct DetailView: View {
1515
@State var isAnimating: Bool = true
1616
@State var lastScaleValue: CGFloat = 1.0
1717
@State var scale: CGFloat = 1.0
18+
@Environment(\.presentationMode) var presentationMode
1819

1920
var body: some View {
2021
VStack {
2122
#if os(iOS) || os(tvOS)
2223
if animated {
23-
contentView()
24+
zoomView()
2425
.navigationBarItems(trailing: Button(isAnimating ? "Stop" : "Start") {
2526
self.isAnimating.toggle()
2627
})
2728
} else {
28-
contentView()
29+
zoomView()
2930
}
3031
#endif
3132
#if os(macOS) || os(watchOS)
3233
if animated {
33-
contentView()
34+
zoomView()
3435
.contextMenu {
3536
Button(isAnimating ? "Stop" : "Start") {
3637
self.isAnimating.toggle()
3738
}
3839
}
3940
} else {
40-
contentView()
41+
zoomView()
4142
}
4243
#endif
4344
}
4445
}
4546

47+
func zoomView() -> some View {
48+
#if os(macOS) || os(iOS) || os(tvOS)
49+
return contentView()
50+
.scaleEffect(self.scale)
51+
.gesture(MagnificationGesture(minimumScaleDelta: 0.1).onChanged { value in
52+
let delta = value / self.lastScaleValue
53+
self.lastScaleValue = value
54+
let newScale = self.scale * delta
55+
self.scale = min(max(newScale, 0.5), 2)
56+
}.onEnded { value in
57+
self.lastScaleValue = 1.0
58+
})
59+
#else
60+
return contentView()
61+
// SwiftUI's bug workaround (watchOS 6.1)
62+
// If use `.focusable(true)` here, after pop the Detail view, the Content view's List does not get focus again
63+
// After some debug, I found that the pipeline to change focus becomes:
64+
// Detail Pop (resign focus) -> Content Appear (List view become focus) -> Detail Disappear (become focus again) -> End
65+
// Even you use `onDisappear`, it's too late because `.focusable` is called firstly
66+
// Sadly, Content view's List focus is managed by SwiftUI (a UICollectionView actually), call `focusable` on Content view does nothing as well
67+
// So, here we must use environment or binding, to not become focus during pop :)
68+
.focusable(self.presentationMode.wrappedValue.isPresented)
69+
.scaleEffect(self.scale)
70+
.digitalCrownRotation($scale, from: 0.5, through: 2, by: 0.1, sensitivity: .low, isHapticFeedbackEnabled: false)
71+
#endif
72+
}
73+
4674
func contentView() -> some View {
4775
HStack {
4876
if animated {
@@ -74,15 +102,6 @@ struct DetailView: View {
74102
#endif
75103
}
76104
}
77-
.scaleEffect(self.scale)
78-
.gesture(MagnificationGesture().onChanged { value in
79-
let delta = value / self.lastScaleValue
80-
self.lastScaleValue = value
81-
let newScale = self.scale * delta
82-
self.scale = min(max(newScale, 0.5), 2)
83-
}.onEnded { value in
84-
self.lastScaleValue = 1.0
85-
})
86105
}
87106
}
88107

0 commit comments

Comments
 (0)