Created
April 1, 2021 09:59
-
-
Save diogoos/eb37848c0ebf6289e5d47e003ba2342c to your computer and use it in GitHub Desktop.
A mini image carousel to display thumbnails
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| struct ThumbnailSlideView: View { | |
| // parameters | |
| @Binding var images: [UIImage] | |
| // element sizing | |
| var size: CGFloat = 100 | |
| var spacing: CGFloat = 16 | |
| private var pageSize: CGFloat { size + spacing } | |
| private var marginAdjust: CGFloat { pageSize / 2 } | |
| // internal position trackers | |
| @State private var offset: CGFloat = 0 | |
| @State private var lastCount: Int = 0 | |
| @State private var currentPage: Int = -1 | |
| var body: some View { | |
| VStack { | |
| HStack(spacing: spacing) { | |
| ForEach(images, id: \.hashValue) { image in | |
| Image(uiImage: image) | |
| .resizable() | |
| .scaledToFill() | |
| .frame(width: size, height: size) | |
| .cornerRadius(5) | |
| } | |
| } | |
| .offset(x: offset, y: 0) | |
| .onReceive(images.publisher.receive(on: RunLoop.main), perform: { _ in | |
| if lastCount < images.count { | |
| if images.count > 1 { offset -= marginAdjust } // no need to offset the first image | |
| currentPage += 1 | |
| lastCount = images.count | |
| } | |
| if lastCount > images.count { | |
| offset += marginAdjust | |
| currentPage -= 1 | |
| lastCount = images.count | |
| } | |
| }) | |
| .gesture(DragGesture().onEnded { value in | |
| if value.translation.width < 0 && currentPage < images.count - 1 { | |
| withAnimation { | |
| offset -= pageSize | |
| currentPage += 1 | |
| } | |
| } | |
| if value.translation.width > 0 && currentPage > 0 { | |
| withAnimation { | |
| offset += pageSize | |
| currentPage -= 1 | |
| } | |
| } | |
| }) | |
| .frame(width: size, height: size) | |
| .clipped() | |
| .fixedSize() | |
| .zIndex(-1) | |
| if images.count <= 6 && images.count > 1 { | |
| HStack(spacing: 1) { | |
| Spacer() | |
| ForEach(0..<images.count, id: \.self) { i in | |
| Circle() | |
| .fill(i == currentPage ? Color(UIColor.systemGray) : Color(UIColor.systemGray3)) | |
| .frame(width: 20) | |
| } | |
| Spacer() | |
| } | |
| .frame(width: size) | |
| .fixedSize() | |
| } else if images.count > 1 { | |
| Text("\(currentPage)/\(images.count)") | |
| .font(.caption) | |
| } | |
| } | |
| } | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Demo implementation:
Preview:
