カスタムキーボードで、削除ボタン(バックスペースボタン)を実装しようといろいろ調べてみると、単純にaddTargetで削除処理を呼び出せばいいというわけではなく、削除ボタンを押し続けた際の動きなどいろいろ考慮しないといけないようで、少しSwift初心者にはハードルが高そうだ。
ネット上にいいサンプルコードがないか探してみたところ、GitHubにうってつけのコードを発見。
https://github.com/archagon/tasty-imitation-keyboard
英語キーボードを全てコードで実装しているらしい(すごい)。各アイコンもベジエ曲線などを使いを見事に表現している。
とりあえず、削除の処理の部分のみを抜粋し、自分のプロジェクトに適用してみる。
※全てKeyboardViewController内に記述。
まずは各種プロパティを定義。
@IBOutlet var backspaceButton: UIButton! let backspaceDelay: NSTimeInterval = 0.5 let backspaceRepeat: NSTimeInterval = 0.07 var backspaceActive: Bool { get { return (backspaceDelayTimer != nil) || (backspaceRepeatTimer != nil) } } var backspaceDelayTimer: NSTimer? var backspaceRepeatTimer: NSTimer?
次にdeinitを。理由はよくわからないが、NSNotificationCenterの解除はdeinitで行うらしい。
deinit { backspaceDelayTimer?.invalidate() backspaceRepeatTimer?.invalidate() NSNotificationCenter.defaultCenter().removeObserver(self) }
次に、viewDidLoad内で、backspaceButtonをAutoLayoutを使ってviewに設置する。
override func viewDidLoad() { super.viewDidLoad() …省略 //削除ボタン self.backspaceButton = UIButton.buttonWithType(.System) as! UIButton self.backspaceButton.setTitle("削除", forState: .Normal) self.backspaceButton.sizeToFit() self.backspaceButton.setTranslatesAutoresizingMaskIntoConstraints(false) let cancelEvents: UIControlEvents = UIControlEvents.TouchUpInside|UIControlEvents.TouchUpInside|UIControlEvents.TouchDragExit|UIControlEvents.TouchUpOutside|UIControlEvents.TouchCancel|UIControlEvents.TouchDragOutside self.backspaceButton.addTarget(self, action: "backspaceDown:", forControlEvents: .TouchDown) self.backspaceButton.addTarget(self, action: "backspaceUp:", forControlEvents: cancelEvents) self.view.addSubview(self.backspaceButton) //AutoLayoutを指定するときこれは必ず記述 self.backspaceButton.setTranslatesAutoresizingMaskIntoConstraints(false) var backspaceButtonRightSideConstraint = NSLayoutConstraint(item: self.backspaceButton, attribute: .Right, relatedBy: .Equal, toItem: self.view, attribute: .Right, multiplier: 1.0, constant: 0.0) var backspaceButtonBottomConstraint = NSLayoutConstraint(item: self.backspaceButton, attribute: .Bottom, relatedBy: .Equal, toItem: self.view, attribute: .Bottom, multiplier: 1.0, constant: 0.0) self.view.addConstraints([backspaceButtonRightSideConstraint, backspaceButtonBottomConstraint]) …省略 }
最後に各種メソッドを定義。
func cancelBackspaceTimers() { self.backspaceDelayTimer?.invalidate() self.backspaceRepeatTimer?.invalidate() self.backspaceDelayTimer = nil self.backspaceRepeatTimer = nil } func backspaceDown(sender: UIButton) { self.cancelBackspaceTimers() if let textDocumentProxy = self.textDocumentProxy as? UIKeyInput { textDocumentProxy.deleteBackward() } // trigger for subsequent deletes self.backspaceDelayTimer = NSTimer.scheduledTimerWithTimeInterval(backspaceDelay - backspaceRepeat, target: self, selector: Selector("backspaceDelayCallback"), userInfo: nil, repeats: false) } func backspaceUp(sender: UIButton) { self.cancelBackspaceTimers() } func backspaceDelayCallback() { self.backspaceDelayTimer = nil self.backspaceRepeatTimer = NSTimer.scheduledTimerWithTimeInterval(backspaceRepeat, target: self, selector: Selector("backspaceRepeatCallback"), userInfo: nil, repeats: true) } func backspaceRepeatCallback() { if let textDocumentProxy = self.textDocumentProxy as? UIKeyInput { textDocumentProxy.deleteBackward() } }
これで、ビルドすれば「削除」と書かれたボタンが右下に設置され、タップすると削除処理が実行されるだろう。
とりあえずシミュレータ上ではうまく動いているようだ。