6月 1, 2010
OS3.2からUIMenuControllerの項目をカスタマイズできるようになったのをご存知でしょうか。
UIMenuControllerとは、こんな吹き出しのことです。
3.2以前でこれをカスタマイズしようと思うと、Responderチェインに割り込んでcutを捕まえて、入れ替えて、などとなかなか手の込んだことをしなければならなかったのですが、ついに3.2でこの問題から解放されます。
使い方を紹介します。
UIMenuItem
表示項目をカスタマイズするにはUIMenuItemクラスを使います。UIMenuItemのインスタンスを作って、そのNSArrayをUIMenuControllerのmenuItemsにセットするだけです。
UIMenuItemで表示するタイトルと実行するactionを指定します。
サンプル
ビューをタップするとメニューが表示されるようにしたいと思います。
そこでTargetViewというUIMenuControllerを表示するViewを用意します。
こんな感じです。
TargetView.h
#import <UIKit/UIKit.h>
@interface TargetView : UIView {
}
@end
TargetView.m
#import "TargetView.h"
@implementation TargetView
- (id)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
}
return self;
}
- (void)dealloc {
[super dealloc];
}
- (BOOL)canBecomeFirstResponder {
return YES;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(@"touch");
UIMenuController *menu = [UIMenuController sharedMenuController];
[menu setTargetRect:CGRectZero inView:self];
menu.arrowDirection = UIMenuControllerArrowRight;
UIMenuItem *rt = [[[UIMenuItem alloc] initWithTitle:@"RT" action:@selector(rt:)] autorelease];
UIMenuItem *reply = [[[UIMenuItem alloc] initWithTitle:@"Reply" action:@selector(reply:)] autorelease];
menu.menuItems = [NSArray arrayWithObjects:rt, reply, nil];
[menu setMenuVisible:YES animated:YES];
}
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
if (action == @selector(rt:) || action == @selector(reply:)) {
return YES;
}
return NO;
}
- (void)rt:(id)sender {
NSLog(@"rt");
}
- (void)reply:(id)sender {
NSLog(@"reply");
}
@end
このViewを呼び出す側はこんな感じです。
- (void)viewDidLoad {
[super viewDidLoad];
TargetView *target = [[[TargetView alloc] initWithFrame:CGRectMake(x, y, size, size)] autorelease];
target.backgroundColor = [UIColor greenColor];
[self.view addSubview:target];
[target becomeFirstResponder];
}
firstResponderにしている所がポイントです。
メニューを表示する
初めてUIMenuControllerを使おうとする時けっこうメニューが表示できずハマります。
表示に必要なことは、
- viewがfirstResponderになっていること
- UIMenuControllerのTargetRectが設定されてること
- その上でUIMenuControllerがvisibleになっていること
です。
まずviewをfirstResponderにするために、TargetViewのcanBecomeFirstResponderメソッドでYESを返しています。これにより、becomeFirstResponderとした時にfirstResponderになることができます。
次にUIMenuControllerのsharedMenuControllerでインスタンスを取得し、setTargetRect:inViewでメニューを表示する場所を指定しています。
ここでは手抜きして、CGRectZeroとしているので、inView(self)の左上にメニューが表示されるようになります。
最後に、setMenuVisibleをYESとして、画面に表示しています。
この間に、UIMenuItemを使ってカスタム項目を設定してます。タイトルとactionを指定してUIMenuItemを生成し、NSArrayとしてmenuItemsにセット。
タイトルが表示される文字列で、actionは実行されるメソッドです。
ここまでが、表示するためにやっていることです。
ちなみに、menuのarrowDirectionで吹き出し元をどの方向にするかを指定できます。
項目の表示制御
このまま実行すると、メニューは表示されますが、カスタム項目は表示されません。デフォルトのaction達がずらずらっと表示されてしまいます。

これを制御するのが、canPerformAction:withSenderメソッドです。
上のサンプルでは、actionがrt:とreply:ならばYESを、そうでなければNOを返すようにしています。
有効にしたいactionでYESを返せば、そのアクションに対応するタイトルが表示されるようになります。

メニューを押された時の制御
後は、actionに指定したメソッドを定義するだけです。
- (void)rt:(id)sender
などがメニューを押された時に呼ばれるようになります。

UIMenuControllerをカスタマイズする | iPad Techfirm Lab http://ow.ly/1SfFP
This comment was originally posted on Twitter
[B!] UIMenuControllerをカスタマイズする | iPad Techfirm Lab http://labs.techfirm.co.jp/ipad/cho/598
This comment was originally posted on Twitter
UIMenuControllerをカスタマイズする | iPad Techfirm Lab: iPad http://bit.ly/cBNp6o
This comment was originally posted on Twitter
かっこいい – 見てるなう: UIMenuControllerをカスタマイズする | iPad Techfirm Lab – http://j.mp/chH4xB
This comment was originally posted on Twitter
[...] が押されたときのselsectorを登録。 http://labs.techfirm.co.jp/ipad/cho/598 [...]