如何通过DragGesture单独偏移每个Shape?
如何通过DragGesture单独偏移每个Shape?
嘿,我一眼就看出问题所在啦——你现在所有的星星都共用同一个off偏移量,不管拖动哪一个,都会修改这个全局变量,自然所有星星都会一起动啦。要让每个星星能单独拖动,我们得给每个星星分配独立的偏移状态,还要处理拖动结束后的位置保存,不然松开手星星会弹回去哦~
解决方案步骤:
- 创建独立的模型结构体:给每个星星封装自己的形状和偏移量,还要让它遵守
Identifiable,这样ForEach能更安全地识别每个元素。 - 替换全局偏移为模型内的偏移:把原来的全局
off换成每个模型里的持久化偏移量,再用GestureState处理拖动时的临时位移。 - 修改手势逻辑:拖动时只更新当前星星的偏移,结束后保存最终位置。
修改后的完整代码:
import SwiftUI // 定义带独立状态的星星模型 struct StarItem: Identifiable { let id = UUID() let shape: any Shape // 保存拖动后的最终偏移位置 var persistentOffset: CGSize = .zero } struct ContentView: View { @State var arrayOfStars: [StarItem] = [] // 临时保存拖动过程中的位移,手势结束后自动重置 @GestureState private var tempDragOffset: CGSize = .zero var body: some View { ZStack { HStack { Button { // 添加新的带独立状态的星星 arrayOfStars.append(StarItem(shape: Star())) } label: { Text("Add Star").foregroundColor(.red) } } ForEach($arrayOfStars) { $item in item.shape .frame(width: 25) .offset(x: -100) // 初始排列位置(保留你原来的逻辑) .offset(x: 20 + CGFloat(arrayOfStars.firstIndex(where: { $0.id == item.id })! * 42), y: -100) .foregroundColor(.red) // 当前位置 = 持久化偏移 + 临时拖动位移 .offset(item.persistentOffset + tempDragOffset) .gesture( DragGesture() // 实时更新临时拖动位移 .updating($tempDragOffset) { value, state, _ in state = value.translation } // 拖动结束后,把临时位移加到持久化偏移里,保存位置 .onEnded { value in item.persistentOffset += value.translation } ) } } } } // 假设你的Star形状实现(如果原代码已有可直接替换) struct Star: Shape { func path(in rect: CGRect) -> Path { var path = Path() let center = CGPoint(x: rect.midX, y: rect.midY) let radius = min(rect.width, rect.height) / 2 let points = (0..<5).map { i -> CGPoint in let angle = Double(i) * .pi * 2 / 5 - .pi / 2 let x = center.x + CGFloat(cos(angle)) * radius let y = center.y + CGFloat(sin(angle)) * radius return CGPoint(x: x, y: y) } path.move(to: points[0]) path.addLine(to: points[2]) path.addLine(to: points[4]) path.addLine(to: points[1]) path.addLine(to: points[3]) path.closeSubpath() return path } }
关键说明:
StarItem结构体给每个星星分配了唯一的id和独立的persistentOffset,这样每个星星的位置都是单独管理的,不会互相干扰。@GestureState修饰的tempDragOffset用来临时保存拖动过程中的位移,手势结束后会自动重置,不会污染其他星星的状态。- 拖动结束时,我们把临时位移加到
persistentOffset里,这样星星会保持在拖动后的位置,不会弹回初始状态。
这样修改后,你点击添加多个星星,每个都能单独拖动啦~
备注:内容来源于stack exchange,提问作者Kurt
相关产品推荐
相关产品推荐

