在 Swift 中绘制正弦曲线

Draw Sinusoidal curve in Swift

在我的 Swift 项目中,我应该使用 Pan Gesture 检测用户的移动并绘制这样的正弦曲线。有没有图书馆可以画这个或者我可以用什么方法实现它??

这个正弦曲线也应该有控制点,在那里我可以动态地改变它的形状。

您可以使用点、直线或曲线段绘制任何数学函数。正弦曲线特别容易,因为您可以很容易地确定极值和其他兴趣点来构建这种曲线的近似值。

一种非常直接的绘制方式是这样的:

class SinusoidalCurveView: UIView {
    
    var resolution: CGFloat? = nil { didSet { setNeedsDisplay() } }
    var function: (n: CGFloat, verticalScale: CGFloat, horizontalScale: CGFloat) = (100.0, 30.0, 30.0) { didSet { setNeedsDisplay() } }
    
    private func solveY(_ x: CGFloat) -> CGFloat {
        let n = function.n
        let h = function.verticalScale
        let m = function.horizontalScale
        return h*sin(x/m) + n
    }
    
    override func draw(_ rect: CGRect) {
        super.draw(rect)
        
        let resolutionStep: CGFloat = {
            if let resolution = resolution {
                return rect.width/resolution
            } else {
                return 1.0/self.layer.contentsScale
            }
        }()
        
        var x: CGFloat = 0.0
        let path = UIBezierPath()
        path.move(to: CGPoint(x: x, y: solveY(x)))
        while x < rect.width {
            x += resolutionStep
            path.addLine(to: CGPoint(x: x, y: solveY(x)))
        }
        
        path.stroke()
    }
    
}

它可以使用一些改进和额外的参数等等。但我相信它应该说明该方法。

就控制点而言,你应该也没有问题。由于您可以确定所有极端和其他兴趣点,因此您可以简单地检测平移手势的起始位置并相应地管理行为。

例如,这会使用平移手势处理垂直缩放的更改:

enum PointOfInterest {
    case extreme(at: CGPoint)
    case zero(at: CGPoint)
}

private func getClosestPointOfInterest(to point: CGPoint) -> PointOfInterest? {
    // Do the math here
    return nil
}

private var selectedPointOfInterest: PointOfInterest?
@objc private func onPan(_ sender: UIGestureRecognizer) {
    switch sender.state {
    case .began:
        if let pointOfInterest = getClosestPointOfInterest(to: sender.location(in: sender.view)) {
            // Got a point that is near enough
            selectedPointOfInterest = pointOfInterest
        } else {
            selectedPointOfInterest = nil
            // Invalidate events
            sender.isEnabled = false
            sender.isEnabled = true
        }
    case .changed:
        guard let selectedPointOfInterest = selectedPointOfInterest else { return }
        switch selectedPointOfInterest {
        case .extreme(let initialLocation):
            let newLocation = sender.location(in: sender.view)
            let offset = newLocation.y - sinusoidalCurveView.function.n
            sinusoidalCurveView.function = (sinusoidalCurveView.function.n, offset, sinusoidalCurveView.function.horizontalScale)
        default:
            break
        }
    default:
        selectedPointOfInterest = nil
    }
}

没有添加控制点,所以在平移上没有任何反应。但是,在您将平移手势识别器添加到您的视图后,已经添加此代码将使一切正常。

private func getClosestPointOfInterest(to point: CGPoint) -> PointOfInterest? {
    // Do the math here
    return .extreme(at: .zero)
}

从这里开始,事情应该很简单了。这是一些工作,但应该没什么大不了的。