如何限制视图/图层的移动路径到贝塞尔曲线路径?

问题描述:

之前问这个问题,我已经搜查了SO:如何限制视图/图层的移动路径到贝塞尔曲线路径?

iPhone-Move UI Image view along a Bezier curve path

但它没有给出明确的答案。我的要求是这样的,我有一个贝塞尔路径和一个视图(或层,如果确定),我想添加pan gesture到视图,并且视图(或图层)的移动路径必须约束到贝塞尔路径。

enter image description here

我的代码如下:

MainDrawView.swift

import UIKit 

class MainDrawView: UIView { 


    // Only override draw() if you perform custom drawing. 
    // An empty implementation adversely affects performance during animation. 
    override func draw(_ rect: CGRect) { 
     // Drawing code 

     drawArc() 
    } 

    func drawArc() { 

     let context = UIGraphicsGetCurrentContext() 

     // set start point 
     context?.move(to: CGPoint.init(x: 0, y: 400)) 
     //draw curve 
     context?.addQuadCurve(to: CGPoint.init(x: 500, y: 250), control: CGPoint.init(x: UIScreen.main.bounds.size.width, y: 200)) 

     context?.strokePath() 

    } 
} 

ViewController.swift

import UIKit 

class ViewController: UIViewController { 

    @IBOutlet weak var clickButton: UIButton! 

    lazy var view1:UIView = { 

     let view: UIView = UIView.init(frame: CGRect.init(origin: CGPoint.init(x: 0, y: 0), size: CGSize.init(width: 10, height: 10))) 
     view.center = CGPoint.init(x: UIScreen.main.bounds.size.width/2.0, y: UIScreen.main.bounds.size.height/2.0) 
     view.backgroundColor = UIColor.red 

     return view 
    }() 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     initData() 
     initUI() 
    } 

    func initData() { 

    } 

    func initUI() { 

     self.clickButton.isHidden = true 

     // init the view 
     self.view.addSubview(self.view1) 
    } 

} 

编辑-1

我深需求量的是,当我使用pan guester移动视图/层,视图将贝塞尔路径上移动。

+0

它可以是CALayers吗?至少在我看来,更容易完成UIViews。一个UIView可以有几个CALayers。如果这对你有用,我有代码可以做到这一点。 – dfd

+0

@dfd,好的,使用CALayer也可以实现它。 – aircraft

+0

@aircraft - 那么我是否正确理解你,你是否想让用户激活一个'UIPanGestureRecognizer',并且随着更新,广场将沿着路径移动? – Pierce

如果贝塞尔路径是离线的,那么你可以找到线的斜率,并且对于x或y中的每个变化,你都可以计算贝塞尔路径的位置。 var y :Float = (slope * (xPos-previousCoord.x))+previousCoord.y; xPos正在不断变化。同样,你可以找到x。对于具有线段的任何封闭形状,您可以使用它。

但是,如果你需要它的圈子,那么你需要将笛卡儿转换为极地。即...从坐标u可以找到角度,然后从该角度,你有半径,所以通过使用该角度,你需要找到笛卡尔坐标。 enter image description here

θ= TAN-1(5/12)

ü需要使用主要3坐标之一是圆的中心,第二个是你的触摸点,最后一个是(touchpoint.x ,centreofcircle.y)。从两个坐标之间的圆计算距离的中心 您有θ和圆的半径,然后使用

X = R×cos(θ)

Y = R×SIN(θ)

唐找到点不要将图像中的r误认为圆的半径,图像中的r是三个坐标的斜边。您应该计算触摸点中每个x的变化。

希望它有效。但对于不规则的形状,我不知道如何找到。

+0

我已经尝试了它的圈子,并能够限制它。如果你想要我可以给你代码。 –

+0

我已经通过电子邮件发送了代码,请检查并告知我是否需要对该 –

+0

邮件代码进行任何说明以及plz –

这听起来像你可能需要做一些计算。当您设置的方法来处理UIPanGestureRecognizer,你可以得到一个向量回锅里,像这样:

func panGestureRecognized(_ sender: UIPanGestureRecognizer) { 
    let vector:CGPoint = sender.translation(in: self.view) // Or use whatever view the UIPanGestureRecognizer was added to 
} 

然后,您可以用它来推断沿x和y轴的运动。我建议首先得到一个代数方程,用于移动视图的路径。要沿该线移动视图,必须能够计算沿着该线相对于UIPanGestureRecognizer的移动的点,然后使用该线上的计算点更新视图的位置。

我不知道这是否会为你想要做什么工作,但如果你想尝试沿路径动画视图,它实际上很简单:

let path = UIBezierPath() // This would be your custom path 

let animation = CAKeyframeAnimation(keyPath: "position") 
animation.path = path.cgPath 
animation.fillMode = kCAFillModeForwards 
animation.isRemovedOnCompletion = false  animation.repeatCount = 0 
animation.duration = 5.0 // However long you want 
animation.speed = 2 // However fast you want 
animation.calculationMode = kCAAnimationPaced 
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear) 

animatingView.layer.add(animation, forKey: "moveAlongPath")