SwiftUI:如何根据已拖动的距离更改拖动速度?

SwiftUI: How to change the speed of drag based on distance already dragged?

例如:我有一个可以自由移动的操纵杆,如何让拖动的速度随着距离的增加而变慢?我拖动操纵杆越远,拖动速度越慢。 提前致谢。

我的操纵杆代码,拖动有效但没有边界,如果将它拖动到边缘也不会减慢速度:

import SwiftUI

struct ContentView: View {

    @State var isDragging = false
    @State var dragValue = CGSize.zero

    var body: some View {
        VStack {
            Text("width: \(dragValue.width)")
            Text("height: \(dragValue.height)")
            VStack (spacing: 16) {
                HStack(spacing: 35) {
                    Image(systemName: "chevron.left")
                        .foregroundColor(.gray)


                    VStack (spacing: 80) {
                        Image(systemName: "chevron.up")
                            .foregroundColor(.gray)
                        Image(systemName: "chevron.down")
                            .foregroundColor(.gray)

                    }
                    Image(systemName: "chevron.right")
                        .foregroundColor(.gray)

                }


            }
            .offset(x: dragValue.width * 0.05, y: dragValue.height * 0.05)

            .frame(width: 150, height: 150)

            .background(LinearGradient(gradient: Gradient(colors: [Color(#colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)), Color(#colorLiteral(red: 0.8705882353, green: 0.8941176471, blue: 0.9450980392, alpha: 1))]), startPoint: .top, endPoint: .bottom))
            .clipShape(RoundedRectangle(cornerRadius: isDragging ? (55 - abs(dragValue.height) / 10) : 55, style: .continuous))
            .offset(x: dragValue.width, y: dragValue.height)

            .shadow(color: Color.black.opacity(0.2), radius: 20, x: 0, y: 20)
            .padding(.horizontal, 30)
            .gesture(
                DragGesture().onChanged { value in
                    self.dragValue = value.translation
                    self.isDragging = true
                }
                .onEnded { value in
                    self.dragValue = .zero
                    self.isDragging = false
                }
            )
                .animation(.spring(response: 0.5, dampingFraction: 0.6, blendDuration: 0))
        }

    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

reddit 上的一个人帮我解决了这个问题,我只需要将 .gesture 更改为:

.gesture(
    DragGesture().onChanged { dragValue in
        let translation: CGSize = dragValue.translation
        let multiplier: CGFloat = 15
        let incrementalW: CGFloat = log(abs(translation.width)) * multiplier
        let incrementalH: CGFloat = log(abs(translation.height)) * multiplier
        let incremental = CGSize(
            width: translation.width > 0 ? incrementalW : -incrementalW,
            height: translation.height > 0 ? incrementalH : -incrementalH
        )
        let resistance = CGSize(
            width: abs(translation.width) < abs(incremental.width) ? translation.width : incremental.width,
            height: abs(translation.height) < abs(incremental.height) ? translation.height : incremental.height
        )

        self.dragValue = resistance
        self.isDragging = true
    }
    .onEnded { dragValue in
        self.dragValue = .zero
        self.isDragging = false
    }
)

这是基于渐近曲线的可能解决方案(如果有人觉得它有帮助的话)。

测试 Xcode 11.4 / iOS 13.4

更新:用 Xcode 13.4 / iOS 15.5

重新测试

更改部分

DragGesture().onChanged { value in
    let limit: CGFloat = 200        // the less the faster resistance 
    let xOff = value.translation.width
    let yOff = value.translation.height
    let dist = sqrt(xOff*xOff + yOff*yOff);
    let factor = 1 / (dist / limit + 1)
    self.dragValue = CGSize(width: value.translation.width * factor,
                        height: value.translation.height * factor)
    self.isDragging = true
}

backup