4502


Swift でティッカーのようなものを作成しています。

`UILabel` が `animationWithDuration` によって画面右外から左端へ流れてきて、一定時間停止した後、画面左外へ消え、次の
`UILabel` がまた右から流れてくるという単純なものです。

各 `UILabel` をタップした際に、イベントが上手く取得できず悩んでいます。

TopicsLabel:

[code]

    import UIKit
    class TopicsLabel: UILabel {
    
    required init(frame: CGRect, tag: Int, topics: String) {
        super.init(frame: frame)
        self.text = topics
        self.tag = tag
        commonInit()
    }
    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        commonInit()
    }
    func commonInit() {
        self.textAlignment = NSTextAlignment.Left
        self.userInteractionEnabled = true
    }
    override func touchesEnded(touches: NSSet, withEvent event: UIEvent) {
        super.touchesEnded(touches, withEvent: event)
        println(self.tag)
    }
    }
    
[/code]

これを、親である `ViewController` から、複数個 `addSubview` し、下記アニメーションで順番に流すように動かしています。

[code]

    UIView.animateWithDuration(
            0.3,
            delay: show_delay,
            options: .CurveEaseInOut | .AllowUserInteraction | .AllowAnimatedContent,// | .BeginFromCurrentState
            animations: {() -> Void in
                target.center = CGPoint(x: 0+target.bounds.width/2, y: 0+target.bounds.height/2)
                return
            },
            completion: {(Bool) -> Void in
                UIView.animateWithDuration(
                    0.1,
                    delay: 3.0,
                    options: .CurveLinear | .AllowUserInteraction | .AllowAnimatedContent,// | .BeginFromCurrentState
                    animations: {() -> Void in
                        target.center = CGPoint(x: -self.bounds.width, y: 0+target.bounds.height/2)
                        return
                    },
                    completion: {(Bool) -> Void in
                        target.center = CGPoint(x: self.bounds.width + self.bounds.width/2, y: target.bounds.height/2)
                        self.showAnimation(target_tag + 1)
                    }
                )
            }
        )
    
[/code]

アニメーション自体は上手くいくのですが、色々と調べていたところアニメーションの仕様で、アニメーションが始まる前にすでに設定された位置にオブジェクトは移動しているが、見た目上はまだ移動していないように見えるだけということで、タッチイベントが発生する位置が、アニメーション後のまだティッカーの存在していないエリアになっています。

ちなみに、 `UILabel` が左端に来た際に一旦イベントを終了すれば良いかと思い、 `completion`
ブロックの中に次のイベントを書くのではなく、右から左端にくるアニメーション（A）と、左端から画面外に出て行くアニメーション（B）を別々に設定し、Bで行っていたdelayの代わりにAとBの間に
`sleep` を入れてみましたが、 `sleep` の間もイベントは発生しませんでした。  
タッチイベント自体が動いてないようにも思います。

何か足がかりをいただければと思います。


CC BY-SA 3.0
2015-01-13T08:40:19.573
4496
2015-01-13T10:46:05.953
2015-01-13T08:47:44.887
4978
7352
question
swift uilabel
Swift で UILabel の animateWithDuration 中にタップイベントを取得したい


足がかりだけでよいなら、

  * アニメーション中のビューの動的な座標は UIView.layer.presentationLayer().frame で取得できます
  * CGRectContainsPoint(rect:, point:) で、タッチ座標が移動中のビューのフレーム内か判定することで、移動中のビューのタッチを擬似的に実装できます
  * ラベルの親ビューに対して UITapGestureRecognizer など UIGestureRecognizer のサブクラスを仕込んで行えば、タッチされた座標は UIGestureRecognizer の locationInView(view:) で取得できます。特別な事情があるなら touches...系のオーバーライドでもいいと思いますけど……

ポイントは、タッチは移動アニメーションをしない親ビューに仕込み、その座標と移動中のビューのフレームを比較できる構造を作ることです。じぶんだったら、ラベルの上階層にコンテナ用のビューを作り、それをビューコントローラのルートビューに張り付けます。

簡単な検証コードを追記しておきます

[code]

    import UIKit
    
    class ViewController: UIViewController {
    
      override func viewDidLoad() {
        super.viewDidLoad()
    
        self.view.addGestureRecognizer(UITapGestureRecognizer.init(target: self, action: "tapped:"))
        self.view.addSubview(TopicsLabel(frame: CGRectMake(0, 20, 100, 40), tag: 1, topics: "topic 1"))
      }
    
      func tapped(sender: UIGestureRecognizer) {
        let location = sender.locationInView(sender.view)
        let target: UIView! = self.view.viewWithTag(1)
    
        if (CGRectContainsPoint(target.layer.presentationLayer().frame, location)) {
          println("Yes !!")
        }
    
        UIView.animateWithDuration(5,
          delay: 0,
          options: .CurveEaseInOut | .AllowUserInteraction | .AllowAnimatedContent,
          animations: {() -> Void in
            target.frame = CGRectMake(self.view.frame.width - target.frame.width, 20, 100, 40)
            return
        }, completion: nil)
      }
    }
[/code]


CC BY-SA 3.0
2015-01-13T10:28:13.037
4502
2015-01-13T10:46:05.953
2015-01-13T10:46:05.953
4496
answer