In a scrollview with LazyHStack
, I am operating into a difficulty with easily scrolling a tapped merchandise into view. That is the animation Im attempting to realize:
Observe that the merchandise hovered on above easily expands into view with objects shifting on both aspect.
My scrollview merchandise is structured such that it expands with animation on faucet. Nevertheless for a scroll view merchandise that’s partially seen, I am unable to have it increase in addition to scroll utterly into view.
My code is as follows:
struct CarouselItem: Identifiable, Equatable {
personal(set) var id: UUID = .init()
var title: String
var 12 months: String
var runtime: String
var certification: String
var posterImage: String
var stillImage: String
}
struct CarousalItemView: View {
@State var merchandise: CarouselItem
@Binding var selectedItem: CarouselItem?
@Namespace personal var namespace
personal var expanded: Bool {
merchandise.id == selectedItem?.id
}
var physique: some View {
VStack(alignment: .main) {
ZStack {
Picture(merchandise.posterImage)
.resizable()
.scaledToFill()
.scaleEffect(expanded ? 1.5 : 1, anchor: .topLeading)
.body(width: expanded ? 250 : 150, top: 200)
.matchedGeometryEffect(id: "picture", in: namespace, anchor: .topLeading, isSource: true)
.opacity(expanded ? 0 : 1)
.animation(.easeOut(length: 0.3), worth: expanded)
Picture(merchandise.stillImage)
.resizable()
.scaledToFill()
.body(width: expanded ? 250 : 150, top: 200)
.matchedGeometryEffect(id: "picture", in: namespace, anchor: .topLeading, isSource: false)
.opacity(expanded ? 1 : 0)
.animation(.easeInOut(length: 0.2).delay(expanded ? 0.1 : 0), worth: expanded)
.overlay(alignment: .main) {
if expanded {
itemDetailsView()
}
}
}
.clipShape(RoundedRectangle(cornerRadius: 10))
Textual content(merchandise.title)
.body(top: 50)
}
}
@ViewBuilder func itemDetailsView() -> some View {
VStack(alignment: .main, spacing: 15) {
Spacer()
Textual content(merchandise.title)
.font(.title2)
HStack {
Textual content("CBFC: " + merchandise.certification)
.padding(.horizontal, 5)
.overlay {
Rectangle()
.stroke(.white, lineWidth: 1)
}
Textual content(merchandise.runtime)
Textual content(merchandise.12 months)
}
.shadow(coloration: .grey, radius: 5, y: 5)
Button {
} label: {
Textual content("Trailer")
}
.buttonStyle(.borderedProminent)
.tint(.grey)
.padding(.backside, 15)
}
.padding(.horizontal, 10)
}
}
struct ContentView: View {
var objects: [CarouselItem] = [
.init(title: "Oppenheimer", year: "2023", runtime: "3h 1m", certification: "UA", posterImage: "poster1", stillImage: "still1"),
.init(title: "Barbie", year: "2023", runtime: "1h 54m", certification: "PG", posterImage: "poster2", stillImage: "still2"),
.init(title: "The Martian", year: "2015", runtime: "2h 24m", certification: "UA", posterImage: "poster3", stillImage: "still3"),
.init(title: "The Shawshank Redemption", year: "1994", runtime: "2h 22m", certification: "U", posterImage: "poster4", stillImage: "still4"),
.init(title: "The Godfather", year: "1972", runtime: "2h 55m", certification: "UA", posterImage: "poster5", stillImage: "still5"),
.init(title: "The Dark Knight", year: "2008", runtime: "2h 32m", certification: "UA", posterImage: "poster6", stillImage: "still6")
]
@State var selectedItem: CarouselItem?
var physique: some View {
VStack {
HStack {
Textual content("Common movies")
.font(.title2.daring())
Spacer()
}
// MARK: Carousal
ScrollViewReader { proxy in
ScrollView(.horizontal) {
LazyHStack(spacing: 20) {
ForEach(objects, id: .id) { merchandise in
CarousalItemView(merchandise: merchandise, selectedItem: $selectedItem)
.body(width: selectedItem?.id != merchandise.id ? 150 : 250, top: 250)
.clipShape(RoundedRectangle(cornerRadius: 10))
.contentShape(Rectangle())
.onTapGesture {
DispatchQueue.most important.async {
withAnimation {
if selectedItem?.id == merchandise.id {
selectedItem = nil
} else {
selectedItem = merchandise
guard let merchandise = selectedItem else { return }
proxy.scrollTo(merchandise.id, anchor: .heart)
}
}
}
}
}
}
}
.body(top: 250)
.scrollIndicators(.hidden)
.clipped()
}
Spacer()
}
.padding()
.background {
Coloration(.darkGray).ignoresSafeArea()
}
.foregroundStyle(.white)
}
}
Within the code above, the animation is form of jerky particularly if an merchandise is expanded and is partially seen on the left & proper edges.
Any assistance is appreciated.