便利なUIActionSheetにpickerとtoolbarを追加してさらに便利な選択用UIにしてみた。い


UIActionSheetはヌルッと飛び出て選択肢を表示できて便利。選択肢としてのボタンを増やしていくとテーブルに変化して幾つもの選択肢を表示できます。しかし、別々の選択肢からそれぞれを選択するようなやり方をするには二度表示とかになってスマートではないです。

そこでアクションシートにピッカーとボタンを埋め込んで組み合わせによる選択を可能にするアクションシートを作ってみます。うまくいけば使いまわせるので、クラス化する方向でやってみます。

まず実現できるかという方向性なので突っ込みどころ満載でお送りします。

まずはアクションシートを継承したクラスを作り、そこへピッカーとツールバーを追加。

@interface Q66Selector : UIActionSheet
{
UIPickerView *_picker;
UIToolbar *_toolBar;
}

サイズの調整

ここで問題なのがサイズ。色々と試した結果、アクションシートのサイズは生成時点では0でオッケー、ピッカーとツールバーはお好みのサイズで作ります。この状態でアクションシートを表示してからBoundsプロパティにサイズをセットするといい感じになります。

_selector.bounds=CGRectMake(0, 0, 320, 504);

なんで504なのかは不明。

ピッカーとツールバーは位置を調整しないと重なって表示されるのでy軸でオフセット。

_toolBar=[[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
_picker=[[UIPickerView alloc] initWithFrame:CGRectMake(0,45,0,0)];

デリゲートする

さて次の問題はアクションシートやピッカーはデリゲートによってその表示や動作を呼び出し元のクラスに委譲します。アクションシートは呼び出し元での生成時に'[[Q66selector setDelegate] self]’のようにdelegateに呼び出し元をセットすればいいのですがピッカーへはどうすればいいのか少し悩みました。

最初の思いつきは初期化メソッドで呼び出し元のインスタンスを引数として渡して、メソッド内でピッカーのdelegateにセットする方法。

- (id)initWithFrame:(CGRect)frame callClass:(id)callClass{
/*
その他の初期化コード
*/
_picker=[[UIPickerView alloc] initWithFrame:CGRectMake(0,45,0,0)];
[self setDelegate:callClass];
[_picker setDelegate:callClass];
[_picker setDataSource:callClass];
}

次に思いついたのはピッカーをプロパティとして、呼び出し元でピッカーのdelegateにアクセスする方法。

[_selector setDelegate:self];
[_selector.picker setDelegate:self];
[_selector.picker setDataSource:self];

どちらがいいのかは不明だけども前者はこういう初期化コードをあまり見たことがないし後者のほうがシンプルなので後者を採用しました。

ツールバーのボタンの処理は

次の課題はツールバーに追加するボタンの処理

Shades

こんな画面になるのでcancelやdoneボタンの処理を出来るようにする。このボタンの処理もやっぱり呼び出し元に委譲する必要がある。

これも幾つかのパターンが思いついた。実は3つ目を思いついたのはこのブログを書いている最中でとりあえずは①で実装してある。

①ボタンを生成するときにターゲットとアクションの指定ができるので、先程の初期化メソッド内でセットする。
UIBarButtonItem *cancelButton=[[UIBarButtonItem alloc] initWithTitle:@"cancel" style:UIBarButtonItemStyleBordered target:callClass action:@selector(selectorCancelButton)];
②デリゲートの仕組みを自前で用意する
③ツールバーをプロパティにしてボタンのセットを呼び出し元で行い、ターゲットにselfをセットすれば無問題

①は先程と同様の理由であまりよろしくないかも、次に簡単なのは③だけど自身で管理するUIが増えるという部分が微妙。ということでデリゲートにするのがヨサゲなのでチョット学んで書き直したいと思っています。

アクションシートを消すには

最後にアクションシートの呼び出しは幾つもの呼び出しメソッドがありますが、問題は消すとき。通常はボタンタップとともに勝手に消えてしまう。そのため自前で消そうとするとちょっと悩みましたが、このメソッドで消せます。

[_selector dismissWithClickedButtonIndex:-1 animated:YES];

ButtonIndexの−1は通常のアクションシートでも領域外のタップするとこの値が入るらしいのでこうしてみました。リンクは忘れた。あとアクションシートのキャンセルボタンのインデックスを指定しなかった場合にキャンセルした場合も-1が戻るみたいですが未確認です。

とりあえずは完成

たぶんこれを使っていくと色々と問題が起きるのかもしれませんが、試して改良しては楽しいからまあいいか。そのへんも逐一報告していけたらと思います。

もしココを参考にしちゃう場合はもっといい方法を見つけたら教えて下さい。また誰が真似するかボケ、間違っとんねんという方は突っ込みお待ちしております。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です