Matched Geometry Effect动画Bug及滚动视图图片居中对齐求助
SwiftUI Matched Geometry Effect 动画问题与布局调整解决方案
问题概述
- 点击第一张图片时动画不流畅;
- 点击第二张图片时,弹出的分页ScrollView会同时显示图片1和图片2的一半;
- 点击第三张图片时动画过程中第一张图片会闪烁;
- 需要将底部ScrollView的图片居中对齐,且每张图片不占满屏幕宽度。
修复后的完整代码
import SwiftUI import Kingfisher struct TopPostMediaView: View { @State private var isExpanded: Bool = false @Namespace private var animation @State private var selectedItemID: UUID? = nil @State private var expandedScrollPosition: UUID? = nil // 自定义缩略图宽度,可根据需求调整 private let thumbnailWidth: CGFloat = 280 var body: some View { VStack(spacing: 0) { // 缩略图滚动区域 ScrollView(.horizontal) { HStack(spacing: 16) { ForEach(mynewtemp) { pic in KFImage(URL(string: pic.photo)) .resizable() .aspectRatio(contentMode: .fill) .frame(width: thumbnailWidth, height: 250) .clipShape(RoundedRectangle(cornerRadius: 10)) .contentShape(RoundedRectangle(cornerRadius: 10)) .matchedGeometryEffect(id: pic.id, in: animation) .onTapGesture { selectedItemID = pic.id expandedScrollPosition = pic.id withAnimation(.easeInOut(duration: 0.3)) { isExpanded = true } } } } // 左右内边距实现居中对齐 .padding(.horizontal, (UIScreen.main.bounds.width - thumbnailWidth) / 2) .scrollTargetLayout() } .scrollPosition(id: $selectedItemID, anchor: .center) .scrollIndicators(.hidden) .scrollTargetBehavior(.viewAligned) .frame(height: 250) // 展开后的分页视图 if isExpanded { ZStack(alignment: .topLeading) { Color.black.ignoresSafeArea() ScrollView(.horizontal) { LazyHStack(spacing: 0) { ForEach(mynewtemp) { pic in KFImage(URL(string: pic.photo)) .resizable() .aspectRatio(contentMode: .fit) .containerRelativeFrame(.horizontal) .clipped() .matchedGeometryEffect(id: pic.id, in: animation) } } .scrollTargetLayout() } .scrollPosition(id: $expandedScrollPosition) .scrollTargetBehavior(.paging) .scrollIndicators(.hidden) Button(action: { withAnimation(.easeInOut(duration: 0.3)) { isExpanded = false } }, label: { Image(systemName: "xmark.circle.fill") .font(.title) .foregroundColor(.white.opacity(0.8)) .padding() }) } .transition(.opacity) } } } } #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 }
关键修复说明
统一匹配ID:
把原代码中拼接字符串的ID改为直接使用pic.id,避免ID重复或无效匹配,彻底解决动画闪烁、错位问题。分离滚动状态:
将原代码复用的detailScrollPosition拆分为selectedItemID(控制缩略图滚动)和expandedScrollPosition(控制展开视图滚动),避免滚动状态冲突导致的视图显示异常。实现缩略图居中布局:
通过给HStack添加动态左右内边距(UIScreen.main.bounds.width - thumbnailWidth) / 2实现居中,同时设置固定缩略图宽度,让图片不占满屏幕。优化动画逻辑:
移除原代码中冗余的透明占位视图,直接通过matchedGeometryEffect处理过渡,减少视图层级和不必要渲染;调整动画时长到0.3秒,让过渡更自然流畅。简化布局计算:
移除手动计算高度的viewHeight()函数,改用ignoresSafeArea()让黑色背景铺满全屏;优化关闭按钮布局,使用自适应padding替代固定值,适配不同设备。
内容的提问来源于stack exchange,提问作者Ahmed Zaidan
相关产品推荐
相关产品推荐

