SimpleNumpadを利用した、拡張コントロールの作成(Swift)
SimpleNumpad
UITextField では、コントロールにフォーカスが入った時にキーボードが自動的に出現させることができます。今回は、このように使用できる数値入力コントロールを作成してみたいと思います。入力の際に出現させるキーボードは、札幌のnotoroidさんが制作されたSimpleNumpad を使用させて頂きました。
なお、SimpleNumpadの詳しい利用方法については、
[iOS][Objective-C] 数値入力をベンリでクールにしてくれる SimpleNumpad | Developers.IO
で紹介されています。
プロジェクトの作成とSimpleNumpadの導入
SimpleNumpadは、CocoaPodsでプロジェクトに組み込むことができます。
CocoaPodsを利用した、プロジェクト作成の手順は、下記のとおりです。
(1) Single View Application でプロジェクトを新規作成(プロジェクト名を、SampleSinpleNumpadとした)
(2) プロジェクトフォルダに移動して、下記の内容でPodfileを作成
pod 'SimpleNumpad', :git => 'https://github.com/notoroid/SimpleNumpad.git'
(3) $pod install を実行
(4) 生成されたプロジェクト名.xcworkspace を開く
(5) プロジェクトフォルダ内で、下記の内容でBridgingHeader.hを作成
#ifndef SampleSimpleNumpad_BridgingHeader_h #define SampleSimpleNumpad_BridgingHeader_h #import <SimpleNumpad/SimpleNumpad.h> #endif
(6) Build Settingの Swift Compiller - Code Generation で Objective-C Bridging Header にファイル名を追加する
拡張コントロール(UINumField)の作成
今回の拡張コントロールは、UILabelを継承して作成しました。
コントロールは、storyboardからも使用できるように@IBDesignable属性を設定し、SimpleNumpadのデリゲートクラスとなれるようIDPNumpadViewControllerDelegateも追加しています。
import UIKit @IBDesignable class UINumField: UILabel , IDPNumpadViewControllerDelegate{ private var vc:IDPNumpadViewController? }
初期化処理
まずは、initialize()を定義して、コントロールの見た目と、タッチイベントを処理できるようにしました(1)。この初期化処理は、実行時に init(coder aDecoder: NSCoder) から呼び出すようにしたのですが(2)、この init(NSCoder) を定義する場合は、
同時に init(CGRect) も定義(3)しないと、storyboadrでエラーが発生してしまいます。

なお、この見た目の初期化をstoryboard上でリアルタイムに表示したい場合は、prepareForInterfaceBuilder()から行うことできます(4)。
func initialize(){ // <= (1) // UILabelを Storyboard で置いた時のデフォルト値を削除する text="0.0" // Labelのフォントのサイズを修正 font = UIFont.systemFontOfSize(35) // Labelがタッチイベントを受け取るように設定する userInteractionEnabled = true } required init(coder aDecoder: NSCoder) { super.init(coder: aDecoder) initialize() // 実行時は、ここを通る <= (2) // SimpleNumpadの生成が、Storyboardで処理できないため、ここで初期化する vc = IDPNumpadViewController(style:IDPNumpadViewControllerStyle.CalcApp,inputStyle: IDPNumpadViewControllerInputStyle.Number,showNumberDisplay: false) vc?.delegate = self // SimpleNumpadのデリゲートクラスを自身とする } // init() イニシャライザを書く場合は、これも同時に定義しないとエラーとなる // Failed to update auto layout status interface Builder Cocoa touch override init(frame: CGRect) { // <= (3) super.init(frame: frame) } // ここでStoryboard上の見た目を初期化する override func prepareForInterfaceBuilder() { // <= (4) initialize() }
プロパティ
続いて、コントロールにフォーカスがある時と無い時に、背景色を変化させるようにし、この色を変更できるようにしました。@IBInspectable属性を指定することで、storyboardから、プロパティ値の変更が可能になります。
// フォーカスがない時の背景色 @IBInspectable var offColor: UIColor = .lightGrayColor(){ didSet{ //storyboardでリアルタイムに表示するため backgroundColor = offColor } } // フォーカスがある時の背景色 @IBInspectable var onColor: UIColor = .clearColor() { didSet{ //storyboardでリアルタイムに表示するため backgroundColor = onColor } }
フォーカス時の処理
コントロールがフォーカスを受け取った際の処理は、次のようになります。ステータスと背景色を変更し、SimpleNumpadをモーダルビューとして表示しています。
なお、このモーダルビューは、この拡張コントロールが置かれている親のViewからポップアップする必要があるので、親のレスポンダーを検索するparentViewControllerを定義しました(6)。
// コントロールがタッチされた際のイベント処理 override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) { if isBusy { return // 既に入力中の場合は処理なし } // ステータスを「入力中」に変更 isBusy = true // 背景色を変更 backgroundColor = onColor // 親のビューコントローラのモーダルビューとして、vc(SimpleNumpad)を開く parentViewController!.presentViewController(self.vc!, animated: true, completion: {}) } // 親となるUIViewControllerを検索(取得)する var parentViewController: UIViewController? { // <= (6) var parentResponder: UIResponder? = self while parentResponder != nil { parentResponder = parentResponder!.nextResponder() if let viewController = parentResponder as? UIViewController { return viewController } } return nil }
キー入力時の処理
キー入力時の処理は、デリゲートで委譲されたメソッドで処理します。Enterが押された場合は、モーダルビューを閉じると同時に、背景色を戻して、フォーカスが外れたことを表現しています(7)。
// SimpleNumpadの内部の値が変化した際のイベント処理 func numpadViewControllerDidUpdate(numpadViewController: IDPNumpadViewController!) { self.text = "\(vc!.value)" } // Enterが押された時のイベント処理 func numpadViewControllerDidEnter(numpadViewController: IDPNumpadViewController!) { // <= (7) // モーダルビューを閉じる parentViewController!.dismissViewControllerAnimated(true, completion: {}) // ステータスを変更 isBusy = false // 背景色を変更 backgroundColor = offColor }
コントロールの使用
それでは、作成した拡張コントロールを使用してみます。
UILabelをStoryboardに配置します。
続いて、Custom Class で UINumField を選択します
あとは、@IBInspectable属性を指定されたプロパティを変更します。
利用に際しての作業は、以上です。
実行している様子は、次のとおりです。
しかし、SimpleNumpad いいっすね〜
コードは、下記に置きました。github.com
まとめ
今回は、SimpleNumpadを利用させて頂いて、拡張コントロールを作成してみました。コントロールに関するdelegate処理などを、全部コントロールクラスに詰め込むことで、利用は非常にシンプルになると思います。
参考資料
[iOS][Objective-C] 数値入力をベンリでクールにしてくれる SimpleNumpad | Developers.IOnotoroid/SimpleNumpad · GitHub