Skip to content

Commit 729ac91

Browse files
authored
Merge pull request #33 from payan-app/image-viewer
refactor: update image viewer for multiple images
2 parents 8f63e50 + 9bac3e4 commit 729ac91

File tree

5 files changed

+129
-99
lines changed

5 files changed

+129
-99
lines changed

PuraceDemo/PuraceDemo/Examples/Complex/ImageViewerExample.swift

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,23 @@ import Purace
1212
struct ImageViewerExample: View {
1313
@State var isVisible = false
1414

15+
let urls: [URL?] = [
16+
URL(string: "https://payan-dev-images.s3.us-east-2.amazonaws.com/santo-domingo.jpg"),
17+
URL(string: "https://payan-dev-images.s3.us-east-2.amazonaws.com/santo-domingo.jpg"),
18+
URL(string: "https://payan-places.s3.us-east-2.amazonaws.com/001/001.jpg")
19+
]
20+
1521
var body: some View {
1622
VStack {
1723
PuraceButtonView("Mostrar imagen") {
1824
isVisible.toggle()
1925
}
2026
Spacer()
2127
}.imageViewer(
22-
url: URL(string: "https://payan-dev-images.s3.us-east-2.amazonaws.com/santo-domingo.jpg"),
23-
isVisible: $isVisible
28+
urls: urls,
29+
isVisible: $isVisible,
30+
selectedIndex: 1
2431
)
32+
.navigationBarHidden(true)
2533
}
2634
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"images" : [
3+
{
4+
"filename" : "arrow_back.svg",
5+
"idiom" : "universal"
6+
}
7+
],
8+
"info" : {
9+
"author" : "xcode",
10+
"version" : 1
11+
}
12+
}
Lines changed: 8 additions & 0 deletions
Loading

Sources/Purace/Views/Complex/Image Viewer/PuraceImageViewer.swift

Lines changed: 91 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -11,117 +11,117 @@ import Kingfisher
1111

1212
public struct PuraceImageViewer: View {
1313
@Binding var isVisible: Bool
14-
let backgroundColor: Color
15-
let url: URL?
16-
@State var opacity: Double = 0
17-
@State var dragOffset: CGSize = .zero
18-
@State var backgroundOpacity: Double = 1
19-
@State var hasDraggedTheImage = false
20-
@State var dragInitialTime: Date?
21-
14+
let urls: [URL?]
15+
@State var currentIndex: Int
2216
@GestureState var scale: CGFloat = 1
17+
@State var dragOffset: CGFloat = .zero
18+
@State var backgroundOpacity = 1.0
19+
20+
private let numberOfImages: Int
2321

2422
private let maximumImageHeight = UIScreen.main.bounds.height * 0.65
2523

26-
public init(url: URL?, isVisible: Binding<Bool>) {
27-
let colors: [Color] = [
28-
PuraceStyle.Color.X1,
29-
PuraceStyle.Color.X2,
30-
PuraceStyle.Color.X3,
31-
PuraceStyle.Color.X4
32-
]
33-
backgroundColor = colors.randomElement()!
34-
self.url = url
24+
public init(urls: [URL?], isVisible: Binding<Bool>, index: Int = 0) {
25+
self.urls = urls
3526
self._isVisible = isVisible
27+
self._currentIndex = .init(initialValue: index)
28+
self.numberOfImages = urls.count
3629
}
3730

38-
private func differenceBeetwenInitialDragTime(and date: Date) -> Double {
39-
guard let dragInitialTime = dragInitialTime else {
40-
return .zero
31+
var indicator: some View {
32+
HStack {
33+
if numberOfImages > 1 {
34+
PuraceTextView("\(currentIndex + 1)/\(numberOfImages)", fontSize: 14, textColor: .white, weight: .medium)
35+
.padding(.trailing)
36+
}
4137
}
42-
return date.timeIntervalSince(dragInitialTime) * 1000
4338
}
4439

45-
var draggableArea: some View {
46-
Color.black
47-
.animation(.none)
48-
.opacity(0.001)
49-
.gesture(
40+
var backButton: some View {
41+
Image(systemName: "chevron.left")
42+
.foregroundColor(.white)
43+
.scaleEffect(1.2)
44+
.padding()
45+
.highPriorityGesture(
46+
TapGesture()
47+
.onEnded {
48+
withAnimation {
49+
isVisible = false
50+
}
51+
}
52+
)
53+
}
54+
55+
var topBar: some View {
56+
VStack {
57+
HStack(alignment: .center) {
58+
backButton
59+
60+
Spacer()
61+
62+
indicator
63+
}.frame(height: 60)
64+
.opacity((abs(dragOffset) >= .zero && abs(dragOffset) <= 5) ? 1 : 0.0002)
65+
}
66+
}
67+
68+
var viewer: some View {
69+
VStack(spacing: 0) {
70+
topBar
71+
72+
TabView(selection: $currentIndex) {
73+
ForEach(0..<numberOfImages) { index in
74+
PuraceImageView(url: urls[index])
75+
.scaledToFit()
76+
.tag(index)
77+
.scaleEffect(scale)
78+
.offset(y: dragOffset)
79+
.gesture(
80+
MagnificationGesture()
81+
.updating($scale) { value, scale, _ in
82+
if value >= 0.9 {
83+
scale = value
84+
}
85+
}
86+
)
87+
}
88+
}
89+
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
90+
.simultaneousGesture(
5091
DragGesture()
5192
.onChanged { value in
52-
hasDraggedTheImage = true
53-
if scale == 1 {
54-
if dragInitialTime == nil {
55-
dragInitialTime = Date()
56-
}
57-
let translation = value.translation.height
58-
dragOffset.height = translation
59-
backgroundOpacity = 1 - abs(translation) * 0.001
93+
dragOffset = value.translation.height
94+
let screenHeight = UIScreen.main.bounds.height
95+
let progress = abs(dragOffset) / screenHeight / 2
96+
withAnimation {
97+
backgroundOpacity = 1 - progress
6098
}
6199
}
62-
.onEnded { value in
63-
if scale == 1 {
64-
let diff = differenceBeetwenInitialDragTime(and: Date())
65-
if diff <= 150 || abs(dragOffset.height) >= UIScreen.main.bounds.height * 0.4 {
66-
hideView()
67-
} else {
68-
withAnimation {
69-
backgroundOpacity = 1
70-
}
71-
dragOffset = .zero
100+
.onEnded { _ in
101+
if abs(dragOffset) < 200 {
102+
withAnimation {
103+
dragOffset = 0
104+
backgroundOpacity = 1
105+
}
106+
} else {
107+
withAnimation {
108+
isVisible = false
72109
}
73-
dragInitialTime = nil
74110
}
75111
}
76112
)
77-
.simultaneousGesture(
78-
MagnificationGesture()
79-
.updating($scale, body: { value, state, _ in
80-
guard value > 0.7 else { return }
81-
state = value
82-
})
83-
)
84-
}
85-
86-
var image: some View {
87-
PuraceImageView(url: url)
88-
.scaledToFit()
89-
.offset(x: dragOffset.width, y: dragOffset.height)
90-
.animation(hasDraggedTheImage ? .easeOut(duration: 0.35) : .none)
91-
.scaleEffect(scale)
92-
.frame(maxHeight: maximumImageHeight)
93-
}
94-
95-
public var body: some View {
96-
ZStack {
97-
backgroundColor
113+
.onChange(of: currentIndex) { _ in
114+
dragOffset = .zero
115+
}
116+
117+
}.background(
118+
PuraceStyle.Color.X1
119+
.edgesIgnoringSafeArea(.all)
98120
.opacity(backgroundOpacity)
99-
image
100-
draggableArea
101-
}
102-
.edgesIgnoringSafeArea(.all)
103-
.transition(.opacity.animation(.linear))
104-
}
105-
}
106-
107-
extension PuraceImageViewer {
108-
private func hideImage() {
109-
withAnimation {
110-
if dragOffset.height > 0 {
111-
dragOffset.height = UIScreen.main.bounds.height
112-
} else {
113-
dragOffset.height = -UIScreen.main.bounds.height
114-
}
115-
}
121+
)
116122
}
117123

118-
private func hideView() {
119-
hideImage()
120-
withAnimation {
121-
backgroundOpacity = 0
122-
}
123-
DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) {
124-
isVisible = false
125-
}
124+
public var body: some View {
125+
viewer
126126
}
127127
}

Sources/Purace/Views/Complex/Image Viewer/PuraceImageViewerModifier.swift

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,28 @@ import Foundation
99
import SwiftUI
1010

1111
public struct PuraceImageViewerModifier: ViewModifier {
12-
let url: URL?
12+
let urls: [URL?]
1313
@Binding var isVisible: Bool
14+
let selectedIndex: Int
1415

15-
public init(url: URL?, isVisible: Binding<Bool>) {
16-
self.url = url
16+
public init(urls: [URL?], isVisible: Binding<Bool>, selectedIndex: Int) {
17+
self.urls = urls
1718
self._isVisible = isVisible
19+
self.selectedIndex = selectedIndex
1820
}
1921

2022
public func body(content: Content) -> some View {
2123
ZStack {
2224
content
2325
if isVisible {
24-
PuraceImageViewer(url: url, isVisible: $isVisible)
26+
PuraceImageViewer(urls: urls, isVisible: $isVisible, index: selectedIndex)
2527
}
2628
}
2729
}
2830
}
2931

3032
public extension View {
31-
func imageViewer(url: URL?, isVisible: Binding<Bool>) -> some View {
32-
modifier(PuraceImageViewerModifier(url: url, isVisible: isVisible))
33+
func imageViewer(urls: [URL?], isVisible: Binding<Bool>, selectedIndex: Int = 0) -> some View {
34+
modifier(PuraceImageViewerModifier(urls: urls, isVisible: isVisible, selectedIndex: selectedIndex))
3335
}
3436
}

0 commit comments

Comments
 (0)