Created
September 16, 2022 11:15
-
-
Save dmikots/8b201f84eb9aeb7ab8754db867b342d8 to your computer and use it in GitHub Desktop.
This file contains 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 CustomAvatarSlider<Content: View, T: Identifiable>: View { | |
var content: (T) -> Content | |
var list: [T] | |
var spacing: CGFloat | |
var trailingSpace: CGFloat | |
@Binding var index: Int | |
init(spacing: CGFloat = 15, trailingSpace: CGFloat = 100, index: Binding<Int>, items: [T], @ViewBuilder content: @escaping (T) -> Content) { | |
self.list = items | |
self.spacing = spacing | |
self.trailingSpace = trailingSpace | |
self._index = index | |
self.content = content | |
} | |
@GestureState var offset: CGFloat = 0 | |
@State var currentIndex: Int = 0 | |
var body: some View { | |
GeometryReader { proxy in | |
let width = proxy.size.width - (trailingSpace - spacing) | |
let adjustMentWidth = (trailingSpace / 2) - spacing | |
HStack(spacing: spacing) { | |
ForEach(list) { item in | |
content(item) | |
.frame(width: proxy.size.width - trailingSpace) | |
} | |
.frame(width: width) | |
} | |
.padding(.horizontal, spacing) | |
.offset(x: (CGFloat(currentIndex) * -width) + (currentIndex != 0 ? adjustMentWidth : 0) + offset) | |
.gesture( | |
DragGesture() | |
.updating($offset, body: { value, out, _ in | |
out = value.translation.width | |
}) | |
.onEnded { value in | |
let offsetX = value.translation.width | |
let progress = -offsetX / width | |
let roundIndex = progress.rounded() | |
currentIndex = max(min(currentIndex + Int(roundIndex), list.count - 1), 0) | |
currentIndex = index | |
} | |
.onChanged { value in | |
let offsetX = value.translation.width | |
let progress = -offsetX / width | |
let roundIndex = progress.rounded() | |
index = max(min(currentIndex + Int(roundIndex), list.count - 1), 0) | |
} | |
) | |
} | |
.animation(.easeInOut, value: offset == 0) | |
} | |
func getOffset(item: T, width: CGFloat) -> CGFloat { | |
let progress = ((offset < 0 ? offset : -offset) / width) * 60 | |
let topOffset = -progress < 60 ? progress : -(progress + 120) | |
let previuos = getIndex(item: item) - 1 == currentIndex ? (offset < 0 ? topOffset : -topOffset) : 0 | |
let next = getIndex(item: item) + 1 == currentIndex ? (offset < 0 ? -topOffset : topOffset) : 0 | |
let checkBetween = currentIndex >= 0 && currentIndex < list.count ? (getIndex(item: item) - 1 == currentIndex ? previuos : next) : 0 | |
return getIndex(item: item) == currentIndex ? -60 - topOffset : checkBetween | |
} | |
// Fetching Index... | |
func getIndex(item: T) -> Int { | |
let index = list.firstIndex { currentItem in | |
currentItem.id == item.id | |
} ?? 0 | |
return index | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment