[iOS] 複数セクションやボタン以外のコンテンツも利用可能な近代的アクションシート、JGActionSheetについて
1 はじめに
JGActionSheetは、豊富な機能を備えた、近代的なアクションシートです。
JGActionSheetは、UIActionSheetのすべての機能を持っていますが、それ以上に下記の機能を有しています。
- 複数のセクション
- ボタンやラベルのフルカスタマイズ
- ボタン以外のカスタムビュー
- ブロックのコールバック
- UIScrollViewによる、無制限のコンテンツ
JGActionSheetは、MITライセンスで公開されており、CocoaPodで簡単にインストールが可能です。
pod 'JGActionSheet'
なお、2016年3月現在、最新は、1.0.5です。
ライブラリの導入後は、下記のインポートで利用可能になります。
#import "JGActionSheet.h"
2 使用方法
(1) 簡単なサンプル
簡単なサンプルが、GitHubのREADME.mdに紹介されています。
使い方としては、まず、シートとして、JGActionSheetSectionオブジェクトを作成し、それをパラメータにして、JGActionSheetを生成します。
シートは、配列で渡されるため、複数のシートが作成可能であり、サンプルでは、2つのシートが渡されています。
また、ボタンを押した際のイベント処理は、setButtonPressedBlock:で非同期で処理され、どのシートの何番目のボタンを押されたかをNSIndexPathで受け取り、処理を記述することができます。
- (IBAction)tapActionSheet:(id)sender { JGActionSheetSection *section1 = [JGActionSheetSection sectionWithTitle:@"Title" message:@"Message" buttonTitles:@[@"Yes", @"No"] buttonStyle:JGActionSheetButtonStyleDefault]; JGActionSheetSection *cancelSection = [JGActionSheetSection sectionWithTitle:nil message:nil buttonTitles:@[@"Cancel"] buttonStyle:JGActionSheetButtonStyleCancel]; NSArray *sections = @[section1, cancelSection]; JGActionSheet *sheet = [JGActionSheet actionSheetWithSections:sections]; [sheet setButtonPressedBlock:^(JGActionSheet *sheet, NSIndexPath *indexPath) { [sheet dismissAnimated:YES]; }]; [sheet showInView:self.view animated:YES]; }
なお、ボタン選択時のブロックにdismissAnimated:がありますが、これが無いと、選択してもアクションシートは閉じません。
[sheet setButtonPressedBlock:^(JGActionSheet *sheet, NSIndexPath *indexPath) { [sheet dismissAnimated:YES]; }];
(2) デリゲート(JGActionSheetDelegate)
先ほどの例では、ボタンを押した時のイベントをブロックで処理していましたが、これをデリゲートで受け取ることもできます。
JGActionSheet.hには、次のようなデリゲートが設定されています。
// アクションシートが表示される前 - (void)actionSheetWillPresent:(JGActionSheet *)actionSheet; // アクションシートが表示された後 - (void)actionSheetDidPresent:(JGActionSheet *)actionSheet; // アクションシートが非表示になる前 - (void)actionSheetWillDismiss:(JGActionSheet *)actionSheet; // アクションシートが非表示になった後 - (void)actionSheetDidDismiss:(JGActionSheet *)actionSheet; // アクションシートが選択された時 - (void)actionSheet:(JGActionSheet *)actionSheet pressedButtonAtIndexPath:(NSIndexPath *)indexPath;
先のサンプルをデリゲートで処理してみると、次のようになります。
@interface ViewController ()<JGActionSheetDelegate> @end @implementation ViewController JGActionSheet *sheet = nil; - (IBAction)tapActionSheet:(id)sender { if (sheet == nil){ JGActionSheetSection *section1 = [JGActionSheetSection sectionWithTitle:@"Title" message:@"Message" buttonTitles:@[@"Yes", @"No"] buttonStyle:JGActionSheetButtonStyleDefault]; JGActionSheetSection *cancelSection = [JGActionSheetSection sectionWithTitle:nil message:nil buttonTitles:@[@"Cancel"] buttonStyle:JGActionSheetButtonStyleCancel]; NSArray *sections = @[section1, cancelSection]; sheet = [JGActionSheet actionSheetWithSections:sections]; [sheet setButtonPressedBlock:^(JGActionSheet *sheet, NSIndexPath *indexPath) { [sheet dismissAnimated:YES]; NSLog(@"ButtonPressBlock section=%ld row=%ld",indexPath.section,indexPath.row); }]; sheet.delegate = self; } [sheet showInView:self.view animated:YES]; } - (void)actionSheetWillPresent:(JGActionSheet *)actionSheet{ NSLog(@"WillPresent:"); } - (void)actionSheetDidPresent:(JGActionSheet *)actionSheet{ NSLog(@"DidPresent:"); } -(void)actionSheetWillDismiss:(JGActionSheet *)actionSheet{ NSLog(@"WillDismiss:"); } - (void)actionSheetDidDismiss:(JGActionSheet *)actionSheet{ NSLog(@"DidDismiss:"); } -(void)actionSheet:(JGActionSheet *)actionSheet pressedButtonAtIndexPath:(NSIndexPath *)indexPath{ NSLog(@"pressedButtonAtIndexPath section=%ld row=%ld",indexPath.section,indexPath.row); } // 省略
動作している様子です。 ブロックでもデリゲートでも、同じようにNSIndexPathで選択されたボタンを取得できます。
画像をクリックすると動作を確認できます。
(3) ボタン
ボタンには、スタイルを指定することができます。
方法としては、シートに対して、setButtonStyle:メソッドで指定します。
JGActionSheetSection *section1 = [JGActionSheetSection sectionWithTitle:@"Title" message:@"Message" buttonTitles:@[@"Yes", @"No"] buttonStyle:JGActionSheetButtonStyleDefault]; [section1 setButtonStyle:JGActionSheetButtonStyleRed forButtonAtIndex:0]; [section1 setButtonStyle:JGActionSheetButtonStyleGreen forButtonAtIndex:1];
指定できるスタイルは、次の通りです。
- JGActionSheetButtonStyleDefault // 白地 細字
- JGActionSheetButtonStyleCancel // 白地 太字
- JGActionSheetButtonStyleRed // 赤地 細字
- JGActionSheetButtonStyleGreen // 緑地 細字
- JGActionSheetButtonStyleBlue // 青地 細字
(4) マージン
insetsでマージンを設定できます。
sheet.insets = UIEdgeInsetsMake(20.0f, 40.0f, 100.0f, 0.0f);
上の設定で、表示は次のようになります。
(5) ボタン以外のコントロール
ボタン以外のコントロールも配置することができます。
次の例は、UISliderを配置しているものです。
UISlider *c = [[UISlider alloc] init]; c.frame = (CGRect){CGPointZero, {290.0f, c.frame.size.height}}; JGActionSheetSection *section1 = [JGActionSheetSection sectionWithTitle:@"Content View Section" message:nil contentView:c]; JGActionSheetSection *section2 = [JGActionSheetSection sectionWithTitle:nil message:nil buttonTitles:@[@"OK",@"Cancel"] buttonStyle:JGActionSheetButtonStyleDefault]; NSArray *sections = @[section1, section2]; sheet = [JGActionSheet actionSheetWithSections:sections]; [sheet setButtonPressedBlock:^(JGActionSheet *sheet, NSIndexPath *indexPath) { [sheet dismissAnimated:YES]; // 最初のセクションを取得する JGActionSheet *s = [sheet.sections objectAtIndex:0]; // セクションのサブビューからUISliderを検索する for(int i=0;i<3;i++){ UISlider *slider = [s.subviews objectAtIndex:i]; if([slider isMemberOfClass:[UISlider class]]){ NSLog(@"Slider Value = %f",slider.value); break; } } }]; sheet.delegate = self; } [sheet showInView:self.view animated:YES];
そして、実行している様子です。
画像をクリックすると動作を確認することができます。
配置したコントロールの値を読み取るには、グローバルで宣言されていない場合は、上のように芋づる式に検索するしかないでしょう。
作成したコントロールは、セクションのサブビューに格納されていますが、上の例では、これを順に検索しています。
サブビューに配置される順番は、タイトルがnilでない場合、0番目に入り、メッセージがnilでない場合その次の入り、コントロールはその次です。
従って、「タイトルあり(0番目)」、「メッセージ無(配置無し)」と決まっている場合は、その次の1番目に配置されるている事が確約されますので、決め打ちしても大丈夫です。
3 最後に
今回は、高機能なアクションシートである、JGActionSheetを紹介しました。 スクロールすることで、コンテンツが無制限に設定できたり、ボタン以外のコントロールが置けたりと、工夫すると面白い使い方ができるかも知れません。
4 参考資料
https://github.com/JonasGessner/JGActionSheet
http://cocoadocs.org/docsets/JGActionSheet/
Cocoapods Document