Skip to content

Commit c1d572a

Browse files
authored
Merge pull request #60 from SDWebImage/example_detail_scale_image
Example - Supports zoom-in in the detail page image
2 parents babb23b + ff7f740 commit c1d572a

File tree

2 files changed

+51
-5
lines changed

2 files changed

+51
-5
lines changed

Example/SDWebImageSwiftUIDemo/DetailView.swift

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,34 +13,79 @@ struct DetailView: View {
1313
let url: String
1414
let animated: Bool
1515
@State var isAnimating: Bool = true
16+
@State var lastScaleValue: CGFloat = 1.0
17+
@State var scale: CGFloat = 1.0
18+
@Environment(\.presentationMode) var presentationMode
1619

1720
var body: some View {
1821
VStack {
1922
#if os(iOS) || os(tvOS)
2023
if animated {
21-
contentView()
24+
zoomView()
2225
.navigationBarItems(trailing: Button(isAnimating ? "Stop" : "Start") {
2326
self.isAnimating.toggle()
2427
})
2528
} else {
26-
contentView()
29+
zoomView()
2730
}
2831
#endif
2932
#if os(macOS) || os(watchOS)
3033
if animated {
31-
contentView()
34+
zoomView()
3235
.contextMenu {
3336
Button(isAnimating ? "Stop" : "Start") {
3437
self.isAnimating.toggle()
3538
}
3639
}
3740
} else {
38-
contentView()
41+
zoomView()
3942
}
4043
#endif
4144
}
4245
}
4346

47+
func zoomView() -> some View {
48+
#if os(macOS) || os(iOS)
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+
#endif
60+
#if os(tvOS)
61+
return contentView()
62+
.scaleEffect(self.scale)
63+
.focusable(true)
64+
.onPlayPauseCommand {
65+
switch self.scale {
66+
case 1:
67+
self.scale = 2
68+
case 2:
69+
self.scale = 1
70+
default: break
71+
}
72+
}
73+
#endif
74+
#if os(watchOS)
75+
return contentView()
76+
// SwiftUI's bug workaround (watchOS 6.1)
77+
// If use `.focusable(true)` here, after pop the Detail view, the Content view's List does not get focus again
78+
// After some debug, I found that the pipeline to change focus becomes:
79+
// Detail Pop (resign focus) -> Content Appear (List view become focus) -> Detail Disappear (become focus again) -> End
80+
// Even you use `onDisappear`, it's too late because `.focusable` is called firstly
81+
// Sadly, Content view's List focus is managed by SwiftUI (a UICollectionView actually), call `focusable` on Content view does nothing as well
82+
// So, here we must use environment or binding, to not become focus during pop :)
83+
.focusable(self.presentationMode.wrappedValue.isPresented)
84+
.scaleEffect(self.scale)
85+
.digitalCrownRotation($scale, from: 0.5, through: 2, by: 0.1, sensitivity: .low, isHapticFeedbackEnabled: false)
86+
#endif
87+
}
88+
4489
func contentView() -> some View {
4590
HStack {
4691
if animated {

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,8 @@ Demo Tips:
268268
1. Use `Switch` (right-click on macOS/force press on watchOS) to switch between `WebImage` and `AnimatedImage`.
269269
2. Use `Reload` (right-click on macOS/force press on watchOS) to clear cache.
270270
3. Use `Swipe` to delete one image item.
271-
4. Clear cache and go to detail page to see progressive loading.
271+
4. Pinch gesture (Digital Crown on watchOS, play button on tvOS) to zoom-in detail page image.
272+
5. Clear cache and go to detail page to see progressive loading.
272273

273274
## Screenshot
274275

0 commit comments

Comments
 (0)