【问题标题】:can't access object within UIPanGestureRecognizer无法访问 UIPanGestureRecognizer 中的对象
【发布时间】:2014-10-27 03:06:33
【问题描述】:

我正在使用以编程方式生成的对象制作贝塞尔动画。对象的数量可能大于 100。这些对象也会对触摸做出响应。

动画效果很好。现在我想让一些对象可以拖动。

但是,我无法访问 UIPanGestureRecognizer 函数中的各个对象。我假设我在调用类/子类时做错了什么,但想不出来..

我查看的教程为屏幕上的每个动画对象提供了 IBOutlets 或专用类变量。我确实有可能在 FOR 循环中生成大量对象。

你有什么建议?

func panning(pan: UIPanGestureRecognizer) {

    self.view.bringSubviewToFront(pan.view!)
    var translation  = pan.translationInView(self.view)

    pan.view.center = CGPointMake(pan.view.center.x + translation.x, pan.view.center.y + translation.y)

    pan.setTranslation(CGPointZero, inView: self.view)


        let panGesture = UIPanGestureRecognizer(target: self, action: "panning:");
                }
}

.. 在 vi​​ewDidLoad 中调用函数:

    // loop from 0 to 50
    for i in 0...50 {

        // create a square object
        let square = UIView()
        square.frame = CGRect(x: 55, y: 300, width: 40, height: 40)
        square.backgroundColor = UIColor.redColor()
        self.view.addSubview(square)


        let recognizer = UIPanGestureRecognizer(target: self, action: "panning:");
        recognizer.delegate = self;
        square.addGestureRecognizer(recognizer)
        panGesture.delegate = self;

感谢 Rob 的反馈,这是一个更新版本:

我真的不知道如何将 AllowUserInteraction 添加到 CAKeyframeAnimation(Rob 的回答 3a),因为它没有“选项”字段(我是菜鸟)。

停止正在移动的对象的动画(Rob 的答案 3b)完全让我无法理解。但这里绝对有必要。

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    srand48(Int(NSDate().timeIntervalSince1970))

    // loop from 0 to 5
    for i in 0...5 {

        // create a square
        let square = UIView()
        square.frame = CGRect(x: 55, y: 300, width: 40, height: 40)
        square.backgroundColor = UIColor.redColor()

        self.view.addSubview(square)
        //square.userInteractionEnabled = true;


        let recognizer = UIPanGestureRecognizer(target: self, action: "panning:");
        square.addGestureRecognizer(recognizer)



        // randomly create a value between 0.0 and 150.0
        let randomYOffset = CGFloat( drand48() * 150)

        // for every y-value on the bezier curve
        // add our random y offset so that each individual animation
        // will appear at a different y-position
        let path = UIBezierPath()
        path.moveToPoint(CGPoint(x: -16,y: 239 + randomYOffset))
        path.addCurveToPoint(CGPoint(x: 375, y: 239 + randomYOffset), controlPoint1: CGPoint(x: 136, y: 373 + randomYOffset), controlPoint2: CGPoint(x: 178, y: 110 + randomYOffset))

        // create the animation
        let anim = CAKeyframeAnimation(keyPath: "position")
        anim.path = path.CGPath
        anim.rotationMode = kCAAnimationRotateAuto
        anim.repeatCount = Float.infinity
        //anim.duration = 5.0

        // each square will take between 4.0 and 8.0 seconds
        // to complete one animation loop
        anim.duration = 4.0 + 3 * drand48()

        // stagger each animation by a random value
        // `290` was chosen simply by experimentation
        anim.timeOffset = 290 * drand48()


        // add the animation 
        square.layer.addAnimation(anim, forKey: "animate position along path")
    }
}


func panning(pan: UIPanGestureRecognizer) {

    if pan.state == .Began {
        println("pan began")
        self.view.bringSubviewToFront(pan.view!)

    } else if pan.state == .Changed {

        println("pan state changed")

        var translation  = pan.translationInView(self.view)

        pan.view?.center = CGPointMake(pan.view!.center.x + translation.x, pan.view!.center.y + translation.y)

        pan.setTranslation(CGPointZero, inView: self.view)

        println("translation")

    }
}

【问题讨论】:

    标签: uiview swift uigesturerecognizer


    【解决方案1】:

    我突然想到了两件事:

    1. 您的for 循环正在为recognizer(除非您正在做一些您没有与我们分享的特定事情)和panGesture(应该删除因为panGesture 是不是您在此for 循环中设置的变量,并且似乎完全不相关)。因此它将是:

      for i in 0...50 {
          let square = UIView()
          square.frame = CGRect(x: 55, y: 300, width: 40, height: 40)
          square.backgroundColor = UIColor.redColor()
          self.view.addSubview(square)
      
          let recognizer = UIPanGestureRecognizer(target: self, action: "panning:");
          square.addGestureRecognizer(recognizer)
      }
      
    2. panning 中,您正在实例化一个新的panGesture:您肯定想摆脱它。手势处理程序没有创建新手势的业务。所以去掉以let panGesture = ...开头的那一行。

    3. 在您最初的问题中,您没有分享您正在制作的动画。如果您使用基于块的动画制作动画,则必须指定 UIViewAnimationOptions.AllowUserInteraction 选项。此外,如果您开始在正在动画的视图周围拖动它,您还需要 (a) 停止该视图的动画; (b) 按照presentationLayer重置frame

      但是,现在很明显您正在使用CAKeyframeAnimation,在这种情况下,没有AllowUserInteraction 机制。因此,您必须将手势识别器添加到superview,然后遍历正方形的帧(由它们的表示层表示,即动画中间的位置)并测试是否有任何命中.

    4. 这取决于您,但我发现平移手势开始识别手势有点慢(因为它区分平移和轻敲。在这种情况下,您想要一些响应更快的东西,我想,所以我可能会使用带有

    5. 的长按手势识别器

    因此,将所有这些放在一起,您最终会得到如下结果:

    var squares = [UIView]() // an array to keep track of all of the squares
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    
        srand48(Int(NSDate().timeIntervalSince1970))
    
        // loop from 0 to 5
        for i in 0...5 {
    
            // create a square
            let square = UIView()
            square.frame = CGRect(x: 55, y: 300, width: 40, height: 40)
            square.backgroundColor = UIColor.redColor()
    
            self.view.addSubview(square)
    
            squares.append(square)
    
            // randomly create a value between 0.0 and 150.0
            let randomYOffset = CGFloat( drand48() * 150)
    
            // for every y-value on the bezier curve
            // add our random y offset so that each individual animation
            // will appear at a different y-position
            let path = UIBezierPath()
            path.moveToPoint(CGPoint(x: -16,y: 239 + randomYOffset))
            path.addCurveToPoint(CGPoint(x: 375, y: 239 + randomYOffset), controlPoint1: CGPoint(x: 136, y: 373 + randomYOffset), controlPoint2: CGPoint(x: 178, y: 110 + randomYOffset))
    
            // create the animation
            let anim = CAKeyframeAnimation(keyPath: "position")
            anim.path = path.CGPath
            anim.rotationMode = kCAAnimationRotateAuto
            anim.repeatCount = Float.infinity
            //anim.duration = 5.0
    
            // each square will take between 4.0 and 8.0 seconds
            // to complete one animation loop
            anim.duration = 4.0 + 3 * drand48()
    
            // stagger each animation by a random value
            // `290` was chosen simply by experimentation
            anim.timeOffset = 290 * drand48()
    
            // add the animation
            square.layer.addAnimation(anim, forKey: "animate position along path")
        }
    
        let recognizer = UILongPressGestureRecognizer(target: self, action: "handleLongPress:");
        recognizer.minimumPressDuration = 0
        view.addGestureRecognizer(recognizer)
    }
    
    var viewToDrag: UIView!          // which of the squares are we dragging
    var viewToDragCenter: CGPoint!   // what was the `center` of `viewToDrag` when we started to drag it
    var originalLocation: CGPoint!   // what was gesture.locationInView(gesture.view!) when we started dragging
    
    func handleLongPress(gesture: UILongPressGestureRecognizer) {
        let location = gesture.locationInView(gesture.view!)
    
        if gesture.state == .Began {
            for square in squares {
                let presentationLayer = square.layer.presentationLayer() as CALayer
                let frame = presentationLayer.frame
                if CGRectContainsPoint(frame, location) {
                    viewToDrag = square
                    viewToDragCenter = CGPointMake(CGRectGetMidX(frame), CGRectGetMidY(frame))
                    viewToDrag.layer.removeAnimationForKey("animate position along path")
                    viewToDrag.center = viewToDragCenter
                    originalLocation = location
                    return
                }
            }
        } else if gesture.state == .Changed {
            if viewToDrag != nil {
                var translation = CGPointMake(location.x - originalLocation.x, location.y - originalLocation.y)
                viewToDrag.center = CGPointMake(viewToDragCenter.x + translation.x, viewToDragCenter.y + translation.y)
            }
        } else if gesture.state == .Ended {
            viewToDrag = nil
        }
    }
    

    【讨论】:

    • 感谢您的快速反馈。我基本上复制了你的建议——所有这些都在我的小例子中(上面更新了)。 3a) 和 3b) 的实现对我来说仍然有些困难,但就所需的功能而言,您猜对了。
    • @SantaChris 是的,关于.AllowUserInteraction 的观察仅适用于您正在制作基于块的动画,但您使用的是CAKeyframeAnimation,因此不适用。我已经修改了我的答案,以展示您如何抓取带有关键帧动画的动画项目并拖动它们。
    • Rob,感谢上述完美答案。这完全解决了我的问题。非常感谢您!
    猜你喜欢
    • 1970-01-01
    • 2017-05-23
    • 1970-01-01
    • 2017-08-13
    • 2020-07-31
    • 1970-01-01
    相关资源
    最近更新 更多