In a scrollview with LazyHStack
, I am operating into a problem with easily scrolling a tapped merchandise into view. That is the animation Im attempting to attain:
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 develop in addition to scroll fully into view.
My code is as follows:
struct CarouselItem: Identifiable, Equatable {
non-public(set) var id: UUID = .init()
var title: String
var yr: 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 non-public var namespace
non-public 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, peak: 200)
.matchedGeometryEffect(id: "picture", in: namespace, anchor: .topLeading, isSource: true)
.opacity(expanded ? 0 : 1)
.animation(.easeOut(period: 0.3), worth: expanded)
Picture(merchandise.stillImage)
.resizable()
.scaledToFill()
.body(width: expanded ? 250 : 150, peak: 200)
.matchedGeometryEffect(id: "picture", in: namespace, anchor: .topLeading, isSource: false)
.opacity(expanded ? 1 : 0)
.animation(.easeInOut(period: 0.2).delay(expanded ? 0.1 : 0), worth: expanded)
.overlay(alignment: .main) {
if expanded {
itemDetailsView()
}
}
}
.clipShape(RoundedRectangle(cornerRadius: 10))
Textual content(merchandise.title)
.body(peak: 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.yr)
}
.shadow(colour: .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("In style 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, peak: 250)
.clipShape(RoundedRectangle(cornerRadius: 10))
.contentShape(Rectangle())
.onTapGesture {
DispatchQueue.major.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(peak: 250)
.scrollIndicators(.hidden)
.clipped()
}
Spacer()
}
.padding()
.background {
Colour(.darkGray).ignoresSafeArea()
}
.foregroundStyle(.white)
}
}
Within the code above, the animation is type of jerky particularly if an merchandise is expanded and is partially seen on the left & proper edges.
Any assistance is appreciated.