Post not yet marked as solved
Post marked as unsolved with 0 replies, 932 views
Hello all!
In my project, I have created a swipeable carousel view that changes a published property (currentHoleIdx) in my ViewModel that I use to programmatically change a TabView.
I want the TabView to animate when the index changes, and it does, but only with the deprecated .animated(.easeInOut).
I have tried .animation(.easeInOut, value:model.currentHoleIdx) and also tried withAnimation when I change the currentHoleIdx property.
I will do my best to post the code to show what I have done. Thanks in advance for any help!
TabView with animation
VStack {
ZStack(alignment: .top) {
// Mini Scorecard
MiniScorecard(scorecard:model.scorecards[model.currentScorecardIdx!], teams: model.scorecards[model.currentScorecardIdx!].teams)
.coordinateSpace(name: "mini")
// .opacity(showScore ? 1 : 0)
.background(Color("card"))
.background(
GeometryReader { geo in
Color.clear.onAppear {
showScoreOffset = geo.size.height
// print(geo.size.height)
}
}
)
// Scorecard TabView
TabView(selection: $model.currentHoleIdx,
content: {
ForEach(0..<model.scorecards[model.currentScorecardIdx!].holes.count) {idx in
let scorecard = model.scorecards[model.currentScorecardIdx!]
if scorecard.formatType == "individual" {
if scorecard.gameID == "Standard" {
IndivStandardScoreScrollview(idx:idx)
.tag(idx)
.animation(.easeInOut, value: model.currentHoleIdx) // // does not work does not work with idx or model.currentHoleIdx
}
} else {
if scorecard.gameID == "Standard" {
TeamStandardScoreScrollview(holeIdx:idx)
.tag(idx)
.animation(.easeInOut, value: idx) // does not work does not work with idx or model.currentHoleIdx
}
}
}
Color.clear
.tag(model.scorecards[model.currentScorecardIdx!].holes.count)
}).tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
.background(Color("card"))
.offset(y:showScore ? showScoreOffset : 0)
.animation(.easeInOut, value: showScore)
.animation(.easeInOut, value: scorecardOffset)
// .animation(.easeInOut, value: model.currentHoleIdx) // does not work
}.frame(width:UIScreen.main.bounds.width - 30)
}
.offset(y: scorecardOffset)
.offset(y: model.currentHoleIdx < model.scorecards[model.currentScorecardIdx!].holes.count ? 0 : scorecardHeight)
.padding(.top)
.padding(.horizontal, 15)
.animation(.easeInOut, value: scorecardOffset)
.animation(.easeInOut, value: model.currentHoleIdx) // does not work!!!
// .animation(.easeInOut) // Only thing that works! when model.currentHoleIdx changes from drag gesture
.overlay(
GeometryReader { geo in
Color.clear.onAppear {
scorecardHeight = geo.size.height
}
}
)
Swipeable carousel drag gesture - withAnimation when interacting with model.currentHoleIdx
return HStack(alignment: .center, spacing: spacing) {
items
}
.offset(x: CGFloat(calcOffset), y: 0)
.gesture(DragGesture(minimumDistance: 0, coordinateSpace: .named("canvas")).updating($screenDrag) { dragValue, gestureState, transaction in
// self.model.screenDrag = Float(currentState.translation.width)
// gestureState == screenDrag
gestureState = dragValue.translation
}.onEnded { value in
// screenDrag = 0 - Don't need this, bc GestureState automatically resets back to initial value
// Swipe to next hole
if (value.translation.width < -15) && self.model.currentHoleIdx < Int(numberOfItems) - 1 {
// calculate currentholeidx based on swipe width and cardwidth
let calculatedHoleIdx = self.model.currentHoleIdx - Int(floor(value.translation.width/(cardWidth + spacing + 10)))
withAnimation { // withAnimation Here
self.model.currentHoleIdx = calculatedHoleIdx > Int(numberOfItems - 1) ? Int(numberOfItems - 1) : calculatedHoleIdx
}
let impactMed = UIImpactFeedbackGenerator(style: .medium)
impactMed.impactOccurred()
}
// Swipe to previous hole
if (value.translation.width > 15) && self.model.currentHoleIdx > 0 {
let calculatedHoleIdx = self.model.currentHoleIdx - Int(ceil((value.translation.width/(cardWidth + spacing + 10))))
withAnimation { // withAnimation Here
self.model.currentHoleIdx = calculatedHoleIdx < 0 ? 0 : calculatedHoleIdx
}
self.model.currentHoleIdx = calculatedHoleIdx < 0 ? 0 : calculatedHoleIdx
let impactMed = UIImpactFeedbackGenerator(style: .medium)
impactMed.impactOccurred()
}
I feel like i've tried every possible iteration of .animation and withAnimation. The only one that works is using the deprecated .animation() modifier. Hope to hear from someone soon. thanks again!