Skip to content

Commit b6ffc81

Browse files
authored
Merge pull request #19 from Jake-Short/add-caption-option
Added an optional caption parameter
2 parents 355712f + 09743c9 commit b6ffc81

File tree

3 files changed

+128
-47
lines changed

3 files changed

+128
-47
lines changed

README.md

+25
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,31 @@ struct ContentView: View {
6565

6666
# Customization
6767

68+
69+
### Caption
70+
71+
#### Availability: 2.1.0 or higher
72+
73+
A caption can be added to the image viewer. The caption will appear near the bottom of the image viewer (if the image fills the whole screen the text will appear on top of the image). The `caption` parameter accepts `Text`.
74+
75+
Example:
76+
```Swift
77+
import ImageViewer
78+
79+
struct ContentView: View {
80+
@State var showImageViewer: Bool = true
81+
@State var image = Image("example-image")
82+
83+
var body: some View {
84+
VStack {
85+
Text("Example!")
86+
}
87+
.frame(maxWidth: .infinity, maxHeight: .infinity)
88+
.overlay(ImageViewer(image: self.$image, viewerShown: self.$showImageViewer, caption: Text("This is a caption!")))
89+
}
90+
}
91+
```
92+
6893
### Explicit Aspect Ratio
6994

7095
#### Availability: 1.0.21 or higher

Sources/ImageViewer/ImageViewer.swift

+48-19
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,27 @@ public struct ImageViewer: View {
66
@Binding var viewerShown: Bool
77
@Binding var image: Image
88
@Binding var imageOpt: Image?
9+
@State var caption: Text?
910

1011
var aspectRatio: Binding<CGFloat>?
1112

1213
@State var dragOffset: CGSize = CGSize.zero
1314
@State var dragOffsetPredicted: CGSize = CGSize.zero
1415

15-
public init(image: Binding<Image>, viewerShown: Binding<Bool>, aspectRatio: Binding<CGFloat>? = nil) {
16+
public init(image: Binding<Image>, viewerShown: Binding<Bool>, aspectRatio: Binding<CGFloat>? = nil, caption: Text? = nil) {
1617
_image = image
1718
_viewerShown = viewerShown
1819
_imageOpt = .constant(nil)
1920
self.aspectRatio = aspectRatio
21+
_caption = State(initialValue: caption)
2022
}
2123

22-
public init(image: Binding<Image?>, viewerShown: Binding<Bool>, aspectRatio: Binding<CGFloat>? = nil) {
24+
public init(image: Binding<Image?>, viewerShown: Binding<Bool>, aspectRatio: Binding<CGFloat>? = nil, caption: Text? = nil) {
2325
_image = .constant(Image(systemName: ""))
2426
_imageOpt = image
2527
_viewerShown = viewerShown
2628
self.aspectRatio = aspectRatio
29+
_caption = State(initialValue: caption)
2730
}
2831

2932
func getImage() -> Image {
@@ -57,26 +60,51 @@ public struct ImageViewer: View {
5760
.zIndex(2)
5861

5962
VStack {
60-
self.getImage()
61-
.resizable()
62-
.aspectRatio(self.aspectRatio?.wrappedValue, contentMode: .fit)
63-
.offset(x: self.dragOffset.width, y: self.dragOffset.height)
64-
.rotationEffect(.init(degrees: Double(self.dragOffset.width / 30)))
65-
.pinchToZoom()
66-
.gesture(DragGesture()
67-
.onChanged { value in
68-
self.dragOffset = value.translation
69-
self.dragOffsetPredicted = value.predictedEndTranslation
70-
}
71-
.onEnded { value in
72-
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) {
73-
self.viewerShown = false
63+
ZStack {
64+
self.getImage()
65+
.resizable()
66+
.aspectRatio(self.aspectRatio?.wrappedValue, contentMode: .fit)
67+
.offset(x: self.dragOffset.width, y: self.dragOffset.height)
68+
.rotationEffect(.init(degrees: Double(self.dragOffset.width / 30)))
69+
.pinchToZoom()
70+
.gesture(DragGesture()
71+
.onChanged { value in
72+
self.dragOffset = value.translation
73+
self.dragOffsetPredicted = value.predictedEndTranslation
74+
}
75+
.onEnded { value in
76+
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) {
77+
self.viewerShown = false
78+
79+
return
80+
}
81+
self.dragOffset = .zero
82+
}
83+
)
84+
85+
if(self.caption != nil) {
86+
VStack {
87+
Spacer()
7488

75-
return
89+
VStack {
90+
Spacer()
91+
92+
HStack {
93+
Spacer()
94+
95+
self.caption
96+
.foregroundColor(.white)
97+
.multilineTextAlignment(.center)
98+
99+
Spacer()
100+
}
101+
}
102+
.padding()
103+
.frame(maxWidth: .infinity, maxHeight: .infinity)
76104
}
77-
self.dragOffset = .zero
105+
.frame(maxWidth: .infinity, maxHeight: .infinity)
78106
}
79-
)
107+
}
80108
}
81109
.frame(maxWidth: .infinity, maxHeight: .infinity)
82110
.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))
@@ -93,6 +121,7 @@ public struct ImageViewer: View {
93121
}
94122
}
95123

124+
96125
class PinchZoomView: UIView {
97126

98127
weak var delegate: PinchZoomViewDelgate?

Sources/ImageViewerRemote/ImageViewerRemote.swift

+55-28
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ public struct ImageViewerRemote: View {
99
@Binding var imageURL: String
1010
@State var httpHeaders: [String: String]?
1111
@State var disableCache: Bool?
12+
@State var caption: Text?
1213

1314
var aspectRatio: Binding<CGFloat>?
1415

@@ -17,11 +18,12 @@ public struct ImageViewerRemote: View {
1718

1819
@ObservedObject var loader: ImageLoader
1920

20-
public init(imageURL: Binding<String>, viewerShown: Binding<Bool>, aspectRatio: Binding<CGFloat>? = nil, disableCache: Bool? = nil) {
21+
public init(imageURL: Binding<String>, viewerShown: Binding<Bool>, aspectRatio: Binding<CGFloat>? = nil, disableCache: Bool? = nil, caption: Text? = nil) {
2122
_imageURL = imageURL
2223
_viewerShown = viewerShown
2324
_disableCache = State(initialValue: disableCache)
2425
self.aspectRatio = aspectRatio
26+
_caption = State(initialValue: caption)
2527

2628
loader = ImageLoader(url: imageURL)
2729
}
@@ -56,32 +58,10 @@ public struct ImageViewerRemote: View {
5658
.zIndex(2)
5759

5860
VStack {
59-
if(self.disableCache == nil || self.disableCache == false) {
60-
URLImage(url: URL(string: self.imageURL)!, content: { image in
61-
image
62-
.resizable()
63-
.aspectRatio(self.aspectRatio?.wrappedValue, contentMode: .fit)
64-
.offset(x: self.dragOffset.width, y: self.dragOffset.height)
65-
.rotationEffect(.init(degrees: Double(self.dragOffset.width / 30)))
66-
.pinchToZoom()
67-
.gesture(DragGesture()
68-
.onChanged { value in
69-
self.dragOffset = value.translation
70-
self.dragOffsetPredicted = value.predictedEndTranslation
71-
}
72-
.onEnded { value in
73-
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) {
74-
self.viewerShown = false
75-
return
76-
}
77-
self.dragOffset = .zero
78-
}
79-
)
80-
})
81-
}
82-
else {
83-
if loader.image != nil {
84-
Image(uiImage: loader.image!)
61+
ZStack {
62+
if(self.disableCache == nil || self.disableCache == false) {
63+
URLImage(url: URL(string: self.imageURL)!, content: { image in
64+
image
8565
.resizable()
8666
.aspectRatio(self.aspectRatio?.wrappedValue, contentMode: .fit)
8767
.offset(x: self.dragOffset.width, y: self.dragOffset.height)
@@ -100,9 +80,56 @@ public struct ImageViewerRemote: View {
10080
self.dragOffset = .zero
10181
}
10282
)
83+
})
10384
}
10485
else {
105-
Text(":/")
86+
if loader.image != nil {
87+
Image(uiImage: loader.image!)
88+
.resizable()
89+
.aspectRatio(self.aspectRatio?.wrappedValue, contentMode: .fit)
90+
.offset(x: self.dragOffset.width, y: self.dragOffset.height)
91+
.rotationEffect(.init(degrees: Double(self.dragOffset.width / 30)))
92+
.pinchToZoom()
93+
.gesture(DragGesture()
94+
.onChanged { value in
95+
self.dragOffset = value.translation
96+
self.dragOffsetPredicted = value.predictedEndTranslation
97+
}
98+
.onEnded { value in
99+
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) {
100+
self.viewerShown = false
101+
return
102+
}
103+
self.dragOffset = .zero
104+
}
105+
)
106+
}
107+
else {
108+
Text(":/")
109+
}
110+
}
111+
112+
if(self.caption != nil) {
113+
VStack {
114+
Spacer()
115+
116+
VStack {
117+
Spacer()
118+
119+
HStack {
120+
Spacer()
121+
122+
self.caption
123+
.foregroundColor(.white)
124+
.multilineTextAlignment(.center)
125+
126+
Spacer()
127+
}
128+
}
129+
.padding()
130+
.frame(maxWidth: .infinity, maxHeight: .infinity)
131+
}
132+
.frame(maxWidth: .infinity, maxHeight: .infinity)
106133
}
107134
}
108135
}

0 commit comments

Comments
 (0)