Skip to content

Commit f03d664

Browse files
committed
Added remote image viewing
1 parent a601ca1 commit f03d664

File tree

4 files changed

+152
-40
lines changed

4 files changed

+152
-40
lines changed

.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.resolved

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"object": {
3+
"pins": [
4+
{
5+
"package": "URLImage",
6+
"repositoryURL": "https://github.com/dmytro-anokhin/url-image.git",
7+
"state": {
8+
"branch": null,
9+
"revision": "a48feef3ef91f573a5f55779502e07adb19943b8",
10+
"version": "0.9.15"
11+
}
12+
}
13+
]
14+
},
15+
"version": 1
16+
}

Package.swift

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ let package = Package(
1717
dependencies: [
1818
// Dependencies declare other packages that this package depends on.
1919
// .package(url: /* package url */, from: "1.0.0"),
20+
.package(url: "https://github.com/dmytro-anokhin/url-image.git", from: "0.9.15")
2021
],
2122
targets: [
2223
// Targets are the basic building blocks of a package. A target can define a module or a test suite.

Sources/swiftui-image-viewer/swiftui_image_viewer.swift

+134-39
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,153 @@
11
import SwiftUI
22
import UIKit
3+
import URLImage
34

4-
struct ImageViewer: View {
5-
@State var image: Image
5+
struct ImageViewerRemote: View {
6+
@Binding var viewerShown: Bool
7+
@Binding var imageURL: String
68

79
@State var dragOffset: CGSize = CGSize.zero
810
@State var dragOffsetPredicted: CGSize = CGSize.zero
11+
12+
init(imageURL: Binding<String>, viewerShown: Binding<Bool>) {
13+
_imageURL = imageURL
14+
_viewerShown = viewerShown
15+
}
916

17+
@ViewBuilder
1018
var body: some View {
11-
ZStack {
12-
VStack {
13-
HStack {
14-
Button(action: { print("Close") }) {
15-
Image(systemName: "xmark")
16-
.foregroundColor(Color(UIColor.white))
17-
.font(.system(size: UIFontMetrics.default.scaledValue(for: 24)))
19+
VStack {
20+
if(viewerShown && imageURL.count > 0) {
21+
ZStack {
22+
VStack {
23+
HStack {
24+
Button(action: { self.viewerShown = false }) {
25+
Image(systemName: "xmark")
26+
.foregroundColor(Color(UIColor.white))
27+
.font(.system(size: UIFontMetrics.default.scaledValue(for: 24)))
28+
}
29+
30+
Spacer()
31+
}
32+
33+
Spacer()
1834
}
35+
.padding()
36+
.zIndex(2)
1937

20-
Spacer()
38+
VStack {
39+
URLImage(URL(string: self.imageURL ?? "https://via.placeholder.com/300.png")!) { proxy in
40+
proxy.image
41+
.resizable()
42+
.aspectRatio(contentMode: .fit)
43+
.offset(x: self.dragOffset.width, y: self.dragOffset.height)
44+
.rotationEffect(.init(degrees: Double(self.dragOffset.width / 30)))
45+
.pinchToZoom()
46+
.gesture(DragGesture()
47+
.onChanged { value in
48+
self.dragOffset = value.translation
49+
self.dragOffsetPredicted = value.predictedEndTranslation
50+
}
51+
.onEnded { value in
52+
print(abs(self.dragOffset.height) + abs(self.dragOffset.width))
53+
print((abs(self.dragOffsetPredicted.height)) / (abs(self.dragOffset.height)))
54+
print((abs(self.dragOffsetPredicted.width)) / (abs(self.dragOffset.width)))
55+
56+
if((abs(self.dragOffset.height) + abs(self.dragOffset.width) > 570) || ((abs(self.dragOffsetPredicted.height)) / (abs(self.dragOffset.height)) > 3) || ((abs(self.dragOffsetPredicted.width)) / (abs(self.dragOffset.width))) > 3) {
57+
self.viewerShown = false
58+
return
59+
}
60+
self.dragOffset = .zero
61+
}
62+
)
63+
}
64+
.frame(maxWidth: .infinity, maxHeight: .infinity)
65+
.background(Color(red: 0.12, green: 0.12, blue: 0.12, opacity: (1.0 - Double(abs(self.dragOffset.width) + abs(self.dragOffset.height)) / 1000)).edgesIgnoringSafeArea(.all))
66+
.zIndex(1)
67+
}
68+
.transition(AnyTransition.opacity.animation(.easeInOut(duration: 0.2)))
69+
.onAppear() {
70+
self.dragOffset = .zero
71+
self.dragOffsetPredicted = .zero
72+
}
2173
}
22-
23-
Spacer()
2474
}
25-
.padding()
26-
.zIndex(2)
27-
28-
VStack {
29-
self.image
30-
.resizable()
31-
.aspectRatio(contentMode: .fit)
32-
.offset(x: self.dragOffset.width, y: self.dragOffset.height)
33-
.rotationEffect(.init(degrees: Double(self.dragOffset.width / 30)))
34-
.pinchToZoom()
35-
.gesture(DragGesture()
36-
.onChanged { value in
37-
self.dragOffset = value.translation
38-
self.dragOffsetPredicted = value.predictedEndTranslation
39-
}
40-
.onEnded { value in
41-
print(abs(self.dragOffset.height) + abs(self.dragOffset.width))
42-
print((abs(self.dragOffsetPredicted.height)) / (abs(self.dragOffset.height)))
43-
print((abs(self.dragOffsetPredicted.width)) / (abs(self.dragOffset.width)))
44-
45-
if((abs(self.dragOffset.height) + abs(self.dragOffset.width) > 570) || ((abs(self.dragOffsetPredicted.height)) / (abs(self.dragOffset.height)) > 3) || ((abs(self.dragOffsetPredicted.width)) / (abs(self.dragOffset.width))) > 3) {
46-
print("would close")
75+
}
76+
.frame(maxWidth: .infinity, maxHeight: .infinity)
77+
}
78+
}
79+
80+
struct ImageViewer: View {
81+
@Binding var viewerShown: Bool
82+
@Binding var image: Image
83+
84+
@State var dragOffset: CGSize = CGSize.zero
85+
@State var dragOffsetPredicted: CGSize = CGSize.zero
86+
87+
init(image: Binding<Image>, viewerShown: Binding<Bool>) {
88+
_image = image
89+
_viewerShown = viewerShown
90+
}
91+
92+
@ViewBuilder
93+
var body: some View {
94+
VStack {
95+
if(viewerShown) {
96+
ZStack {
97+
VStack {
98+
HStack {
99+
Button(action: { self.viewerShown = false }) {
100+
Image(systemName: "xmark")
101+
.foregroundColor(Color(UIColor.white))
102+
.font(.system(size: UIFontMetrics.default.scaledValue(for: 24)))
103+
}
104+
105+
Spacer()
47106
}
48-
self.dragOffset = .zero
107+
108+
Spacer()
49109
}
50-
)
110+
.padding()
111+
.zIndex(2)
112+
113+
VStack {
114+
self.image
115+
.resizable()
116+
.aspectRatio(contentMode: .fit)
117+
.offset(x: self.dragOffset.width, y: self.dragOffset.height)
118+
.rotationEffect(.init(degrees: Double(self.dragOffset.width / 30)))
119+
.pinchToZoom()
120+
.gesture(DragGesture()
121+
.onChanged { value in
122+
self.dragOffset = value.translation
123+
self.dragOffsetPredicted = value.predictedEndTranslation
124+
}
125+
.onEnded { value in
126+
print(abs(self.dragOffset.height) + abs(self.dragOffset.width))
127+
print((abs(self.dragOffsetPredicted.height)) / (abs(self.dragOffset.height)))
128+
print((abs(self.dragOffsetPredicted.width)) / (abs(self.dragOffset.width)))
129+
130+
if((abs(self.dragOffset.height) + abs(self.dragOffset.width) > 570) || ((abs(self.dragOffsetPredicted.height)) / (abs(self.dragOffset.height)) > 3) || ((abs(self.dragOffsetPredicted.width)) / (abs(self.dragOffset.width))) > 3) {
131+
self.viewerShown = false
132+
133+
return
134+
}
135+
self.dragOffset = .zero
136+
}
137+
)
138+
}
139+
.frame(maxWidth: .infinity, maxHeight: .infinity)
140+
.background(Color(red: 0.12, green: 0.12, blue: 0.12, opacity: (1.0 - Double(abs(self.dragOffset.width) + abs(self.dragOffset.height)) / 1000)).edgesIgnoringSafeArea(.all))
141+
.zIndex(1)
142+
}
143+
.transition(AnyTransition.opacity.animation(.easeInOut(duration: 0.2)))
144+
.onAppear() {
145+
self.dragOffset = .zero
146+
self.dragOffsetPredicted = .zero
147+
}
51148
}
52-
.frame(maxWidth: .infinity, maxHeight: .infinity)
53-
.background(Color(red: 0.12, green: 0.12, blue: 0.12, opacity: (1.0 - Double(abs(self.dragOffset.width) + abs(self.dragOffset.height)) / 1000)).edgesIgnoringSafeArea(.all))
54-
.zIndex(1)
55149
}
150+
.frame(maxWidth: .infinity, maxHeight: .infinity)
56151
}
57152
}
58153

0 commit comments

Comments
 (0)