79173546

Date: 2024-11-09 19:31:44
Score: 0.5
Natty:
Report link

As mentioned in the comments, it is difficult to follow the logic behind the OP's approach, as it doesn't offer additional advantages nor simplify things in any way that I can tell.

Since @Sweeper provided the solution for fixing the drag gesture (incorporated with some minor changes in the example below), here's how the same functionality could be achieved in a more SwiftUI way and more along the lines of what I believe @Sweeper was suggesting in earlier comments.

Some additional notes:

Here's the full code:

import SwiftUI

struct StarDragGesture: View {
    
    //State values
    @State private var points: [CustomPoint] = [CustomPoint(x: 100, y: 100), CustomPoint(x: 200, y: 200, size: CGSize(width: 50, height: 50)), CustomPoint(x: 300, y: 100)]
    
    //Body
    var body: some View {
        ZStack {
            
            //Background color
            Color.blue
                .ignoresSafeArea()
            
            //Display a star for every point in the points array, at the specified position
            ForEach($points) { $point in
                StarView(position: $point)
            }
            
            //Button for checking the updated star positions in the console
            Button {
                print("-----")
                for (index, point) in points.enumerated() {
                    print("Point \(index + 1) - X: \(point.x), Y: \(point.y)")
                }
            } label: {
                Text("Check positions")
                    .foregroundStyle(.blue)
            }
            .buttonStyle(.borderedProminent)
            .tint(.white)
            
        }
        
    }
}

struct StarView: View {
    
    //Parameters
    @Binding var position: CustomPoint
    
    //State values
    @State private var lastTranslation: CGSize = .zero
    @State private var initialPosition: CustomPoint?
    
    //Body
    var body: some View {
        
        StarShape(points: 5, innerRatio: 0.4)
            .fill(Color.white)
            .shadow(radius: 5)
            .frame(width: position.size.width, height: position.size.height)
            .position(position.coordinates)
        
            //Reset star position on double tab
            .onTapGesture(count: 2) {
                if let initialPosition {
                    position = initialPosition
                }
            }
            .gesture(dragGesture)
        
            //Optional - Capture initial position for resetting
            .onAppear {
                initialPosition = position
            }
        
    }
    
    private var dragGesture: some Gesture {
        
        DragGesture(minimumDistance: 0)
            .onChanged { value in
                updatePosition(value.translation)
                lastTranslation = value.translation
            }
            .onEnded { value in
                updatePosition(value.translation)
                lastTranslation = .zero
            }
    }
    
    //Helper function for updating the position based on gesture translation
    private func updatePosition(_ translation: CGSize ) {
        position.x += translation.width - lastTranslation.width
        position.y += translation.height - lastTranslation.height
    }
    
}

struct StarShape: Shape {
    var points: Int = 5
    var innerRatio: CGFloat = 0.5  // Adjusts the depth of the star's inner points
    
    func path(in rect: CGRect) -> Path {
        guard points >= 2 else { return Path() }
        
        let center = CGPoint(x: rect.width / 2, y: rect.height / 2)
        let angle = 2 * .pi / CGFloat(points)
        let radius = min(rect.width, rect.height) / 2
        
        var path = Path()
        let startAngle = -CGFloat.pi / 2
        
        for i in 0..<points * 2 {
            let rotationAngle = startAngle + angle * CGFloat(i) / 2
            let pointRadius = i % 2 == 0 ? radius : radius * innerRatio
            let x = center.x + pointRadius * cos(rotationAngle)
            let y = center.y + pointRadius * sin(rotationAngle)
            
            if i == 0 {
                path.move(to: CGPoint(x: x, y: y))
            } else {
                path.addLine(to: CGPoint(x: x, y: y))
            }
        }
        
        path.closeSubpath()
        return path
    }
}

struct CustomPoint: Identifiable {
    
    let id: UUID = UUID()
    var x: CGFloat
    var y: CGFloat
    
    //Computed properties
    var coordinates: CGPoint {
        CGPoint(x: x, y: y)
    }
    
    //Optional property for possibly creating stars of various sizes
    var size: CGSize = CGSize(width: 100, height: 100)
}

#Preview {
    StarDragGesture()
}

Give this a try and let me know if it makes sense or if it still makes things difficult for your use case.

Reasons:
  • Blacklisted phrase (0.5): thanks
  • Long answer (-1):
  • Has code block (-0.5):
  • User mentioned (1): @Sweeper
  • User mentioned (0): @Sweeper
  • Low reputation (0.5):
Posted by: Andrei G.