iPhoneのキーボードのボタンを再現したいのですが・・・


`UIButton`を使用して、個別App用のキーボードを作成しています。 （iOS8に導入されたカスタムキーボードではありません）

iPhoneの英語キーボードや、デフォルトアプリである計算機（Calculator）では、
ボタンをスワイプしていくと、タッチされている位置のボタンがハイライトされていき、 最終的にタッチを離した位置のボタンがタップされたようになります。
（キーボードの外からドラッグされてきた場合には、ボタンは反応しません）

このような仕組みを実装したいのですが、うまく行きません。 なにか、よき解決方法、よき例などありましたら、示唆いただけないでしょうか？
現在、Swiftを使っていますが、Objective-Cでも構いません。

独力でできる範囲では、

[code]

        self.addTarget(self, action: "buttonHighlight", forControlEvents: UIControlEvents.TouchDown)
        self.addTarget(self, action: "buttonHighlight", forControlEvents: UIControlEvents.TouchDragEnter)
        self.addTarget(self, action: "buttonUnhighlight", forControlEvents: UIControlEvents.TouchUpInside)
        self.addTarget(self, action: "buttonUnhighlight", forControlEvents: UIControlEvents.TouchDragExit)
    
[/code]

を組み込んだ`UIButton`のサブクラスを作成して、

`TouchDown`と`TouchDragEnter`でボタンをハイライト化

`TouchUpInside`と`TouchDragExit`でボタンをハイライト解除

するみたいな方法を検討したのですが、`TouchDragEnter`が、

最初にボタンをタッチしたあと、一度、ボタン外にドラッグされて、「再度」ボタン内にドラッグされてきた 場合

を意味しているため、意図通りになりませんでした。
（この`TouchDragEnter`の挙動については、英語版のStackoverflowにもObjective-Cでの場合ですが、 記事がありました。）

なお、 iPadの英語キーボードの場合には、最初にタッチされた場所のボタンがハイライト
されたあと、ドラッグしてタッチされている位置がボタンの範囲から外れると、 そのボタンのハイライトが解除されるだけで、他のボタンがタッチされている状態に
なっても、それぞれのボタンは反応しません。（ちなみに、ドラッグしたまま元のボタン に戻っても何の反応もしません）

こちらは、上記の方法で、ほぼ同等の状態が出来ています。 （ドラッグしたまま元のボタンに戻ると、ボタンが押された状態になってしまいますが）




`ViewController`にコードを追加する必要がありますが、このような方法はどうでしょうか。  
ボタンが3つある場合のサンプルです。`NSLog("button released: %d",
index)`の部分で最終的にタッチを離した位置のボタン番号を取得しています。

[code]

    class ViewController: UIViewController {
      @IBOutlet weak var button0: TestButton!
      @IBOutlet weak var button1: TestButton!
      @IBOutlet weak var button2: TestButton!
      var buttons: [UIButton] = []
    
      override func viewDidLoad() {
        super.viewDidLoad()
        self.buttons = [button0, button1, button2]
        for button: UIButton in buttons {
          button.addTarget(self, action: "buttonTouchDrag:event:", forControlEvents: UIControlEvents.TouchDragInside)
          button.addTarget(self, action: "buttonTouchDrag:event:", forControlEvents: UIControlEvents.TouchDragOutside)
          button.addTarget(self, action: "buttonTouchUp:event:", forControlEvents: UIControlEvents.TouchUpInside)
          button.addTarget(self, action: "buttonTouchUp:event:", forControlEvents: UIControlEvents.TouchUpOutside)
        }
      }
    
      func buttonTouchDrag(sender:UIButton, event: UIEvent) {
        let point = event.allTouches()?.anyObject()?.locationInView(self.view);
        for button: UIButton in buttons {
          if CGRectContainsPoint(button.convertRect(button.bounds, toView: self.view), point!) {
            button.sendActionsForControlEvents(UIControlEvents.TouchDragEnter);
          } else {
            button.sendActionsForControlEvents(UIControlEvents.TouchDragExit);
          }
        }
      }
    
      func buttonTouchUp(sender:UIButton, event: UIEvent) {
        let point = event.allTouches()?.anyObject()?.locationInView(self.view);
        for (index, button) in enumerate(buttons) {
          if CGRectContainsPoint(button.convertRect(button.bounds, toView: self.view), point!) {
            NSLog("button released: %d", index)
          }
          button.sendActionsForControlEvents(UIControlEvents.TouchDragExit);
        }
      }
    }
    
[/code]

![Screenshot](https://i.stack.imgur.com/eDhmF.gif)




`ViewController`にコードを追加する必要がありますが、このような方法はどうでしょうか。  
ボタンが3つある場合のサンプルです。`NSLog("button released: %d",
index)`の部分で最終的にタッチを離した位置のボタン番号を取得しています。

[code]

    class ViewController: UIViewController {
      @IBOutlet weak var button0: TestButton!
      @IBOutlet weak var button1: TestButton!
      @IBOutlet weak var button2: TestButton!
      var buttons: [UIButton] = []
    
      override func viewDidLoad() {
        super.viewDidLoad()
        self.buttons = [button0, button1, button2]
        for button: UIButton in buttons {
          button.addTarget(self, action: "buttonTouchDrag:event:", forControlEvents: UIControlEvents.TouchDragInside)
          button.addTarget(self, action: "buttonTouchDrag:event:", forControlEvents: UIControlEvents.TouchDragOutside)
          button.addTarget(self, action: "buttonTouchUp:event:", forControlEvents: UIControlEvents.TouchUpInside)
          button.addTarget(self, action: "buttonTouchUp:event:", forControlEvents: UIControlEvents.TouchUpOutside)
        }
      }
    
      func buttonTouchDrag(sender:UIButton, event: UIEvent) {
        let point = event.allTouches()?.anyObject()?.locationInView(self.view);
        for button: UIButton in buttons {
          if CGRectContainsPoint(button.convertRect(button.bounds, toView: self.view), point!) {
            button.sendActionsForControlEvents(UIControlEvents.TouchDragEnter);
          } else {
            button.sendActionsForControlEvents(UIControlEvents.TouchDragExit);
          }
        }
      }
    
      func buttonTouchUp(sender:UIButton, event: UIEvent) {
        let point = event.allTouches()?.anyObject()?.locationInView(self.view);
        for (index, button) in enumerate(buttons) {
          if CGRectContainsPoint(button.convertRect(button.bounds, toView: self.view), point!) {
            NSLog("button released: %d", index)
          }
          button.sendActionsForControlEvents(UIControlEvents.TouchDragExit);
        }
      }
    }
    
[/code]

![Screenshot](https://i.stack.imgur.com/eDhmF.gif)

