为何ZStack未执行旋转与缩放,但其内部内容却响应手势?
问题:ZStack应用旋转/缩放效果无效,仅内部Image响应手势
我在ZStack上添加了旋转手势(rotation gesture)和放大手势(magnify gesture),明明将rotationEffect与scaleEffect应用于该ZStack,但ZStack本身未发生旋转和缩放,而其中的Image却能响应手势进行旋转与缩放。

原代码
var body: some View { NavigationView { VStack { GeometryReader { geo in let w = geo.size.width let h = geo.size.height let size = getSize(h, w) if size.width > 0 && size.height > 0 { ZStack { Image(uiImage: service.backgroundImage!) .resizable() .scaledToFill() .frame(width: size.width, height: size.height, alignment: .center) .clipped() // 目标ZStack ZStack{ Image(uiImage: foregroundImage) .resizable() .scaledToFit() .background(GeometryGetter(rect: $imageRect)) } .rotationEffect(rotationAngle) .scaleEffect(scale) .gesture(DragGesture(minimumDistance: 0 , coordinateSpace: .local) .onChanged { value in self.offset.x += value.location.x - value.startLocation.x self.offset.y += value.location.y - value.startLocation.y print("->> Location - \(value.location)") }) .offset(x: offset.x, y: offset.y) .gesture(simultaneous) .background(.blue) } .frame(width: size.width, height: size.height, alignment: .center) .clipped() .frame(maxWidth: .infinity, maxHeight: .infinity) .background(AppDefaults.Theme.secondaryColor) } } bottomContainerView() } .background(Color.black.ignoresSafeArea()) } }
问题原因
- 内层ZStack没有明确的尺寸约束,其大小完全由内部Image决定,导致旋转/缩放效果看起来仅作用于Image
- 手势叠加顺序不合理,且未统一坐标空间,可能导致手势识别目标偏离ZStack容器
修复方案
给内层ZStack添加明确尺寸约束,调整手势合并方式,确保变换效果作用于整个容器:
var body: some View { NavigationView { VStack { GeometryReader { geo in let w = geo.size.width let h = geo.size.height let size = getSize(h, w) if size.width > 0 && size.height > 0 { ZStack { Image(uiImage: service.backgroundImage!) .resizable() .scaledToFill() .frame(width: size.width, height: size.height, alignment: .center) .clipped() // 给内层ZStack设置明确尺寸,匹配背景图空间 ZStack{ Image(uiImage: foregroundImage) .resizable() .scaledToFit() .background(GeometryGetter(rect: $imageRect)) } .frame(width: size.width, height: size.height) .rotationEffect(rotationAngle) .scaleEffect(scale) .offset(x: offset.x, y: offset.y) // 合并拖拽与旋转/缩放手势,支持同时触发 .gesture( DragGesture(minimumDistance: 0, coordinateSpace: .local) .onChanged { value in self.offset.x += value.location.x - value.startLocation.x self.offset.y += value.location.y - value.startLocation.y print("->> Location - \(value.location)") } .simultaneously(with: simultaneous) ) .background(.blue) } .frame(width: size.width, height: size.height, alignment: .center) .clipped() .frame(maxWidth: .infinity, maxHeight: .infinity) .background(AppDefaults.Theme.secondaryColor) } } bottomContainerView() } .background(Color.black.ignoresSafeArea()) } }
关键修改说明
- 给内层ZStack添加
.frame(width: size.width, height: size.height),让它占据完整的背景图空间,此时旋转/缩放会作用于整个蓝色背景的ZStack容器 - 使用
.simultaneously(with:)合并拖拽手势与旋转/缩放手势,避免手势冲突,确保多个操作可以同时响应 - 调整
offset的位置到变换效果之后,保证偏移是基于旋转/缩放后的坐标系,避免位置混乱
内容的提问来源于stack exchange,提问作者dipon_the_pro_coder
相关产品推荐
相关产品推荐

