6.7 C
London
Wednesday, January 31, 2024

ios – Scroll to merchandise with animation problem


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:

enter image description here

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.

Latest news
Related news

LEAVE A REPLY

Please enter your comment!
Please enter your name here