匹配几何效果动画错误

问题描述 投票:0回答:1

我有一个基本视图,尝试将单个图像动画化为图像的选项卡视图。我使用下面的代码遇到一些动画问题。另外,在底部滚动视图中,图像在前缘上对齐,如何在不使每个图像与屏幕全宽的情况下将它们对齐?

  • 单击第一张图像动画效果很好(可能更平滑)
  • 单击第二张图片会出现一个有问题的分页滚动视图(显示了 image1/image2 的一半)
  • 单击第三个图像可以工作,但第一个图像在动画过程中闪烁

复制可粘贴的工作代码,(您需要 king Fisher,否则使用 asyncimage):

import SwiftUI
import Kingfisher

struct TopPostMediaView: View {
    @State var isExpanded: Bool = false
    @Namespace var animation
    @State var detailScrollPosition: UUID? = nil
    @State var animMid = ""
    
    var body: some View {
        GeometryReader {
            let size = $0.size
            ScrollView(.horizontal) {
                HStack(spacing: 10) {
                    ForEach(mynewtemp) { pic in
                        LazyHStack {
                            let mid = pic.photo + pic.id.uuidString
                            
                            if !isExpanded || animMid != mid {
                                KFImage(URL(string: pic.photo))
                                    .resizable()
                                    .aspectRatio(contentMode: .fill)
                                    .frame(maxWidth: size.width)
                                    .clipShape(RoundedRectangle(cornerRadius: 10))
                                    .contentShape(RoundedRectangle(cornerRadius: 10))
                                    .matchedGeometryEffect(id: mid, in: animation)
                                    .onTapGesture {
                                        //move to the image
                                        detailScrollPosition = pic.id
                                        //sub view id to animate up
                                        animMid = mid
                                        //present top view
                                        withAnimation(.easeInOut(duration: 0.15)){
                                            isExpanded = true
                                        }
                                    }
                            } else {
                                KFImage(URL(string: pic.photo))
                                    .resizable()
                                    .aspectRatio(contentMode: .fill)
                                    .frame(maxWidth: size.width)
                                    .clipShape(RoundedRectangle(cornerRadius: 10))
                                    .contentShape(RoundedRectangle(cornerRadius: 10))
                                    .opacity(0.0)
                            }
                        }
                        .frame(maxWidth: size.width).frame(height: size.height)
                        .contentShape(.rect)
                    }
                }.scrollTargetLayout()
            }
            .scrollPosition(id: $detailScrollPosition, anchor: .center)
            .scrollIndicators(.hidden)
            .scrollTargetBehavior(.viewAligned)
            .scrollClipDisabled()
        }
        .frame(height: 250)
        .overlay {
            if isExpanded {
                ZStack {
                    Color.black.frame(height: viewHeight() + 30.0).clipShape(RoundedRectangle(cornerRadius: 40))
                    ScrollView(.horizontal) {
                        LazyHStack(spacing: 0) {
                            ForEach(mynewtemp) { pic in
                                KFImage(URL(string: pic.photo))
                                    .resizable()
                                    .aspectRatio(contentMode: .fit)
                                    .containerRelativeFrame(.horizontal)
                                    .clipped()
                            }
                        }.scrollTargetLayout()
                    }
                    .matchedGeometryEffect(id: animMid, in: animation)
                    .scrollPosition(id: $detailScrollPosition)
                    .scrollTargetBehavior(.paging)
                    .scrollIndicators(.hidden)
                    .overlay(alignment: .topLeading) {
                        Button("", systemImage: "xmark.circle.fill") {
                            withAnimation(.easeInOut(duration: 0.15)){
                                isExpanded = false
                            }
                        }
                        .foregroundStyle(.white.opacity(0.8), .white.opacity(0.15))
                        .padding(.top, 100).padding(.leading)
                    }
                }
            }
        }
    }
}

// IGNORE

#Preview {
    TopPostMediaView()
}

let mynewtemp: [tempStruct] = [tempStruct(id: UUID(), photo: "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRmCy16nhIbV3pI1qLYHMJKwbH2458oiC9EmA&s"), tempStruct(id: UUID(), photo: "https://th.bing.com/th/id/OIG2.9O4YqGf98tiYzjKDvg7L"), tempStruct(id: UUID(), photo: "https://th.bing.com/th/id/OIG2.9O4YqGf98tiYzjKDvg7L")]

struct tempStruct: Identifiable, Hashable {
    var id: UUID
    var photo: String
}

func viewHeight() -> CGFloat {
    let scenes = UIApplication.shared.connectedScenes
    let windowScene = scenes.first as? UIWindowScene
    let window = windowScene?.windows.first
    return window?.screen.bounds.height ?? 0
}
swift swiftui matchedgeometryeffect
1个回答
0
投票

使用选项卡视图效果更好,我还必须在底部视图中匹配的地理修改器之前添加框架修改器。

import SwiftUI
import Kingfisher

struct TopPostMediaView: View {
    @State var isExpanded: Bool = false
    @Namespace var animation
    @State var detailScrollPosition: UUID? = nil
    @State var animMid = ""
    @State var offset: CGSize = .zero
    
    var body: some View {
        ScrollView {
            VStack(alignment: .leading, spacing: 10) {
                GeometryReader {
                    let size = $0.size
                    ScrollView(.horizontal) {
                        HStack(spacing: 10) {
                            ForEach(mynewtemp) { pic in
                                LazyHStack {
                                    let mid = pic.photo + pic.id.uuidString
                                    
                                    if !isExpanded || animMid != mid {
                                        KFImage(URL(string: pic.photo))
                                            .resizable()
                                            .aspectRatio(contentMode: .fill)
                                            .frame(maxWidth: size.width)
                                            .overlay(content: {
                                                RoundedRectangle(cornerRadius: 10).stroke(Color.gray.opacity(0.4), lineWidth: 1.0)
                                            })
                                            .clipShape(RoundedRectangle(cornerRadius: 10))
                                            .contentShape(RoundedRectangle(cornerRadius: 10))
                                            .frame(height: 250)
                                            .matchedGeometryEffect(id: mid, in: animation)
                                            .onTapGesture {
                                                withAnimation(.easeInOut(duration: 0.15)){
                                                    detailScrollPosition = pic.id
                                                }
                                                animMid = mid
                                                withAnimation(.easeInOut(duration: 0.15)){
                                                    isExpanded = true
                                                }
                                            }
                                    } else {
                                        KFImage(URL(string: pic.photo))
                                            .resizable()
                                            .aspectRatio(contentMode: .fill)
                                            .frame(maxWidth: size.width)
                                            .clipShape(RoundedRectangle(cornerRadius: 10))
                                            .contentShape(RoundedRectangle(cornerRadius: 10))
                                            .opacity(0.0)
                                    }
                                }
                                .frame(maxWidth: size.width)
                                .frame(height: size.height)
                                .contentShape(.rect)
                            }
                        }
                        .scrollTargetLayout()
                    }
                    .scrollPosition(id: $detailScrollPosition, anchor: .center)
                    .scrollIndicators(.hidden)
                    .scrollTargetBehavior(.viewAligned)
                    .scrollClipDisabled()
                }.frame(height: 250)
            }
        }
        .overlay {
            if isExpanded {
                ZStack {
                    Color.black.frame(height: viewHeight() + 30.0).clipShape(RoundedRectangle(cornerRadius: 40))
                    TabView(selection: $detailScrollPosition) {
                        ForEach(mynewtemp) { pic in
                            KFImage(URL(string: pic.photo))
                                .resizable()
                                .aspectRatio(contentMode: .fit)
                                //.frame(width: widthOrHeight(width: true))
                                .containerRelativeFrame(.horizontal)
                                .clipShape(Rectangle())
                                .contentShape(Rectangle())
                                .tag(pic.id)
                        }
                    }
                    .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
                    .matchedGeometryEffect(id: animMid, in: animation)
                    .overlay(alignment: .topLeading) {
                        Button("", systemImage: "xmark.circle.fill") {
                            withAnimation(.easeInOut(duration: 0.15)){
                                isExpanded = false
                            }
                        }
                        .foregroundStyle(.white.opacity(0.8), .white.opacity(0.15)).font(.title)
                        .padding(.top, 100).padding(.leading)
                    }
                }
                .offset(x: offset.width, y: offset.height)
                .gesture (
                    DragGesture()
                        .onChanged { value in
                            if value.translation.height >= 0 || offset != .zero {
                                offset = value.translation
                            }
                        }
                        .onEnded({ value in
                            withAnimation {
                                offset = .zero
                            }
                            if value.translation.height > 100 {
                                withAnimation(.easeInOut(duration: 0.15)){
                                    isExpanded = false
                                }
                            }
                        })
                )
            }
        }
    }
}

#Preview {
    TopPostMediaView()
}

let mynewtemp: [tempStruct] = [tempStruct(id: UUID(), photo: "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRmCy16nhIbV3pI1qLYHMJKwbH2458oiC9EmA&s"), tempStruct(id: UUID(), photo: "https://th.bing.com/th/id/OIG2.9O4YqGf98tiYzjKDvg7L"), tempStruct(id: UUID(), photo: "https://th.bing.com/th/id/OIG2.9O4YqGf98tiYzjKDvg7L")]

struct tempStruct: Identifiable, Hashable {
    var id: UUID
    var photo: String
}

func viewHeight() -> CGFloat {
    let scenes = UIApplication.shared.connectedScenes
    let windowScene = scenes.first as? UIWindowScene
    let window = windowScene?.windows.first
    return window?.screen.bounds.height ?? 0
}
© www.soinside.com 2019 - 2024. All rights reserved.