SwiftUI中KFImage缩放后拖拽异常、仅能中心缩放的修复咨询
问题解决:SwiftUI图片全屏缩放拖拽优化
问题背景
开发的App支持点击图片全屏展示,全屏状态下用户可缩放图片并拖拽查看不同区域,但存在两个问题:
- 图片缩放后拖拽时会自动回正,拖拽体验差
- 仅能对图片中心进行缩放
需要修改代码实现:缩放后平滑拖拽任意区域,且支持对图片任意位置进行缩放。
修改后的完整代码
import SwiftUI import Kingfisher struct ContentView: View { @State private var myPhoto = "https://firebasestorage.googleapis.com:443/v0/b/hustle-85b6c.appspot.com/o/messages%2F7AC5914A-6239-41CF-85EF-E1C0F25C0A84?alt=media&token=8720789b-7cdd-410c-9532-143a2bcf3f3b" @State private var currentScale: CGFloat = 1.0 @State private var baseScale: CGFloat = 1.0 @State private var currentOffset = CGSize.zero @State private var baseOffset = CGSize.zero @State private var imageSize = CGSize.zero @State private var containerSize = CGSize.zero var body: some View { ZStack { Color.black GeometryReader { containerGeo in KFImage(URL(string: myPhoto)) .resizable() .aspectRatio(contentMode: .fit) .onSizeChange { size in imageSize = size containerSize = containerGeo.size } .scaleEffect(currentScale) .offset(currentOffset) .gesture( SimultaneousGesture( DragGesture() .onChanged { value in // 计算拖拽偏移,基于当前缩放比例调整 let newOffset = CGSize( width: baseOffset.width + value.translation.width / currentScale, height: baseOffset.height + value.translation.height / currentScale ) // 限制偏移,确保图片不会超出容器过多 currentOffset = clampedOffset(for: newOffset) } .onEnded { _ in baseOffset = currentOffset // 缩放小于1时重置位置 if currentScale < 1.0 { withAnimation(.easeInOut) { currentScale = 1.0 currentOffset = .zero baseOffset = .zero } } }, MagnificationGesture() .onChanged { value in let newScale = baseScale * value currentScale = max(min(newScale, 3.5), 1.0) // 计算锚点偏移,实现触摸位置缩放 let anchor = value.startLocation let scaledImageSize = CGSize( width: imageSize.width * currentScale, height: imageSize.height * currentScale ) let containerCenter = CGPoint( x: containerSize.width / 2, y: containerSize.height / 2 ) // 调整偏移,让缩放围绕触摸点进行 let offsetX = baseOffset.width + (anchor.x - containerCenter.x) * (1 - currentScale / baseScale) let offsetY = baseOffset.height + (anchor.y - containerCenter.y) * (1 - currentScale / baseScale) currentOffset = clampedOffset(for: CGSize(width: offsetX, height: offsetY)) } .onEnded { value in baseScale = currentScale baseOffset = currentOffset } ) ) } } .ignoresSafeArea() } // 计算合法的偏移量,防止图片空白区域过大 private func clampedOffset(for offset: CGSize) -> CGSize { let scaledWidth = imageSize.width * currentScale let scaledHeight = imageSize.height * currentScale let maxOffsetX = max(0, (scaledWidth - containerSize.width) / 2) let maxOffsetY = max(0, (scaledHeight - containerSize.height) / 2) return CGSize( width: max(-maxOffsetX, min(offset.width, maxOffsetX)), height: max(-maxOffsetY, min(offset.height, maxOffsetY)) ) } } // 扩展View获取尺寸变化 extension View { func onSizeChange(perform action: @escaping (CGSize) -> Void) -> some View { background( GeometryReader { proxy in Color.clear .onAppear { action(proxy.size) } .onChange(of: proxy.size) { newValue in action(newValue) } } ) } }
关键修改说明
- 修复拖拽自动回正问题:移除原代码硬编码的边界限制,改用
clampedOffset方法动态计算合法偏移范围,避免强行拉回图片;优化拖拽偏移计算逻辑,用baseOffset记录拖拽起始偏移,确保拖拽过程平滑无跳变。 - 支持任意位置缩放:在
MagnificationGesture中获取触摸锚点,计算锚点相对容器中心的偏移,缩放时同步调整图片偏移量,实现围绕触摸点缩放的效果;用baseScale记录缩放基准比例,保证缩放计算准确。 - 其他体验优化:新增
onSizeChange扩展统一处理尺寸获取,简化代码逻辑;设置缩放范围为1.0~3.5,缩放小于1时自动重置位置,保证基础交互一致性。
内容的提问来源于stack exchange,提问作者Ahmed Zaidan
相关产品推荐
相关产品推荐

