问题描述
在我的 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)
}
从这里开始,事情应该很简单了。这有点工作,但应该没什么大不了的。