Viewのサイズをピンチジェスチャーで変更する
こんにちは、@yoheiMuneです。
今日は、ピンチジェスチャーを行った場合に、UIImageViewなどのサイズを拡大/縮小する方法を学びましたので、ブログに残したいと思います。
ピンチジェスチャーで、画像の拡大を簡単に行う
ピンチジェスチャーとは、2本指で画面に触れ、2本指が離れる方向にドラッグするジェスチャーです。GooglMapや、写真アプリで画像の拡大/縮小に使う、あれです!!
ピンチジェスチャーで拡大/縮小を行う方法として、UIGestureRecognizerのうち、UIPinchGestureRecognizerというピンチジェスチャー用のGestureRecognizerを使います。UIGestureRecognizerについては、"UIViewにタップした際のイベントを登録する"を参考にしてみて下さい。
今回は、以下のような画面を使います。画面上でピンチジェスチャーを行うと、海の画像が大きくなったり、小さくなったりします。
ピンチジェスチャーを登録する
まずは、UIPinchGestureRecognizerのインスタンスを作成して、ピンチジェスチャーを受けつけるViewにイベントとして登録します。以下のように実装する事で実現出来ます。
- (void)viewDidLoad { [super viewDidLoad]; // ピンチジェスチャーを登録する UIPinchGestureRecognizer *pinch = [[[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchAction:)] autorelease]; [self.view addGestureRecognizer:pinch]; }
上記例では、ピンチジェスチャーが発生した場合に、selfのpinchAction:というメソッドを呼び出すように設定しています。
ピンチジェスチャーを感知したら、Imageを拡大/縮小する
ピンチジェスチャー発生時に呼び出されるメソッドでは、以下のような実装を行う事で、Imageの拡大/縮小を行うことが出来ます。
// ピンチジェスチャー発生時に呼び出されように設定したメソッド。 // ピンチジェスチャー中に何度も呼び出される。 - (void)pinchAction : (UIPinchGestureRecognizer *)sender { // ピンチジェスチャー発生時に、Imageの現在のアフィン変形の状態を保存する if (sender.state == UIGestureRecognizerStateBegan) { currentTransForm = imgView.transform; // currentTransFormは、フィールド変数。imgViewは画像を表示するUIImageView型のフィールド変数。 } // ピンチジェスチャー発生時から、どれだけ拡大率が変化したかを取得する // 2本の指の距離が離れた場合には、1以上の値、近づいた場合には、1以下の値が取得できる CGFloat scale = [sender scale]; // ピンチジェスチャー開始時からの拡大率の変化を、imgViewのアフィン変形の状態に設定する事で、拡大する。 imgView.transform = CGAffineTransformConcat(currentTransForm, CGAffineTransformMakeScale(scale, scale)); }
ここでは、アフィン変換を用いて、ピンチジェスチャー発生時からの拡大率の変化に合わせて、imgViewを拡大/縮小しています。
最後に
UIGestureRecognizerとアフィン変換を用いる事で、簡単にViewの移動/拡大縮小/回転を行う事が出来ました。便利でイイですね♪(´ε` )アフィン変換はまだまだ勉強中なので、理解したらブログにも書けたら良いなぁ。
以下は、関連サイトです。参考になれば幸いです。
ローテーションジェスチャーを簡単に実装する
こんにちは、@yoheiMuneです。
今日は、iPhoneアプリケーションにおいて、簡単にローテーションジェスチャーを実装する方法を学んだので、ブログに残しておきたいと思います。
ローテーションジェスチャーとは
画面要素をくるくると回したいときに使うあれです。2本指で画面に触れ、2本指の距離を変えずに、指で円を描くように動くやり方です。
今日は、以下のような画面において、指の動き(ローテーションジェスチャー)に合わせて、表示されているUIImageViewを回転させます。
ローテーションジェスチャーを実装する
UIGestureRecognizerのひとつ、UIRotationGestureRecognizerを利用します。これを利用する事で、ローテーションジェスチャーが発生した際に、指定したメソッドを呼び出すことが出来ます。以下が、UIRotationGestureRecognizerの使用例です。
- (void)viewDidLoad { [super viewDidLoad]; // インスタンス作成時に、ローテーションジェスチャー発生時に呼びだすメソッドを指定する UIRotationGestureRecognizer *rotation = [[[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotationAction:)] autorelease]; // ローテーションジェスチャーをUIViewに設定する [self.view addGestureRecognizer:rotation]; }
ローテーションジェスチャーが発生したら
以下のメソッドが呼び出されるように、上記で実装しました。このメソッド内では、回転量を取得して、その回転量に応じて、UIImageViewを回転させています。
このメソッドは、ローテーションジェスチャー発生中に、何度も呼び出されます。
- (void)rotationAction : (UIRotationGestureRecognizer *)sender { // 回転した量を取得する。ここで取得出来るのは、radianという単位の値。 // radianの詳細は、[wiki:ラジアン]を参照してください。 CGFloat rotation = [sender rotation]; // imgViewは回転対象のUIImageView。 // CGAffineTransformMakeRotation関数を利用して、移動したradian分、imgViewを回転させる imgView.transform = CGAffineTransformMakeRotation(rotation); }
最後に
Viewの回転って難しそうで、意外と簡単に出来ました。ヨカタヨカタ♪(´ε` )
でもアフィン変形は難しそう。これから多用するだろうから、学ばねば。数学は、やっぱり必要なんですね。
最後に、以下は関連サイトです。参考になれば幸いです。
iPhone上の画像を簡単にドラッグする
こんにちは、@yoheiMuneです。
今日は、iPhoneアプリで画像などをドラッグする方法を学んだので、ブログに残しておきたいと思います。
ドラッグを感知するUIGestureRecognizer
ドラッグを簡単に感知する方法として、UIGestureRecognizerのうちUIPanGestureRecognizerを利用します。UIGestureRecognizerについては、『UIViewにタップした際のイベントを登録する』を参考にしてみて下さい。
今回は、以下のような画面を使います。背景白色のUIViewの上に、UIImageViewを乗せます。今回は、ユーザーのドラッグ操作に合わせて、UIImageViewの位置を変更してみました。
UIPanGestureRecognizerの動作を登録する
背景白色のUIView上で、ユーザーがドラッグをした場合に、指定したメソッドが呼び出されるように設定します。
- (void)viewDidLoad { [super viewDidLoad]; // drag UIPanGestureRecognizer *pan = [[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panAction:)] autorelease]; [self.view addGestureRecognizer:pan]; }
UIPanGestureRecognizerのインスタンス作成時に、ドラッグされた際に呼び出すメソッドを指定します。今回は、selfのpanAction:というメソッドを呼び出すように指定しています。
その後、UIViewのaddGestureRecognizerメソッドを使って、作成したUIPanGestureRecognizerインスタンスをUIViewに登録します。
ドラッグが発生した際に、呼び出されるメソッドでは
以下のような実装を行っています。panAction:はユーザーがドラッグしている間、何度も呼び出されます。
- (void)panAction : (UIPanGestureRecognizer *)sender { // ドラッグで移動した距離を取得する CGPoint p = [sender translationInView:self.view]; // 移動した距離だけ、UIImageViewのcenterポジションを移動させる CGPoint movedPoint = CGPointMake(imgView.center.x + p.x, imgView.center.y + p.y); imgView.center = movedPoint; // ドラッグで移動した距離を初期化する // これを行わないと、[sender translationInView:]が返す距離は、ドラッグが始まってからの蓄積値となるため、 // 今回のようなドラッグに合わせてImageを動かしたい場合には、蓄積値をゼロにする [sender setTranslation:CGPointZero inView:self.view]; }
この実装だけで、ユーザーの指の動きに合わせて、画像の位置を変える事が出来ました。カンタン(*´∇`*)
参考
以下を参考にしました。ありがとうございます。
Event Handling Guide for iOS
UIGestureRecognizer Class Reference
UIPanGestureRecognizer Class Reference
最後に
iPhoneアプリ作成をしていると、良く便利な基盤がそろっているなぁと思います。うん、便利。いや、まだ奥深いところに到達していないだけかもですが。。
UIGestureRecognizerは他にも色々と種類があるので、使えるようになると良いなぁ♪(´ε` )
以下は、関連サイトです。参考になれば幸いです。
iPadでImagePickerを使う方法
こんにちは、@yoheiMuneです。
今日は、iPadでImagePickerを使う方法を学んだので、ブログに残しておきたいと思います。
iPadで、iPhoneのようにImagePickerを開こうとすると
エラーが発生するんです。iPhoneでは、フォトアルバムから写真を取得したり、カメラから写真を取得するには、以下のように実装するかと思います。
UIImagePickerController *imgPicker = [[UIImagePickerController alloc] init]; // 取得元を設定する。今回の場合は、フォトライブラリを指定しています。 imgPicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; imgPicker.delegate = self; // モーダルビューで開く [self presentModalViewController:imgPicker animated:YES];
上記コードをiPadで実行すると、以下のようなエラーが出ます。残念(; ̄ェ ̄)
2011-09-24 20:39:35.145 PopOverSample[306:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'On iPad, UIImagePickerController must be presented via UIPopoverController'
英語を読む限り、iPadでUIImagePickerControllerを使う場合には、UiPopoverControllerを使いなさいと言うこと。
という事で、Popoverを使った実装に変更してみます。Popoverについては、『iPad専用のPopOverControllerを使ってみた』を参考にしてみて下さい。
Popoverを利用して、UIImagePickerControllerを使う
以下のように実装して、Popoverのなかに、ImagePickerを埋め込みます。
// PhotoLibraryが取得元として利用出来ない場合は、その後の処理は実行しない。 if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary] == NO) { // ここで何かしらの、失敗メッセージを出すとユーザーに優しい。 return; } // UIImagePickerControllerのインスタンスを作成して、 // 必要な入手元の設定や、delegateの設定を行う。 UIImagePickerController *imgPicker = [[UIImagePickerController alloc] init]; imgPicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; imgPicker.delegate = self; // 表示に使うPopoverのインスタンスを作成する。 imagePopControllerは、UIPopoverController型のフィールド変数。 // PopoverのコンテンツビューにImagePickerを指定する。 imagePopController = [[UIPopoverController alloc] initWithContentViewController:imgPicker]; // Popoverを表示する。 // senderはBarButtonItem型の変数で、このボタンを起点にPopoverを開く。 [imagePopController presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
次に、写真が選択された場合に、そのUIImageを画面に表示して、Popoverを閉じる実装をします。
#pragma mark - #pragma mark UIImagePickerControllerDelegate implementation - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { // ユーザーの選択した写真を取得し、imageViewというUIImageView型のフィールドのイメージに設定する UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage]; self.imageView.image = image; // UIPopoverControllerを閉じる [imagePopController dismissPopoverAnimated:YES]; }
また、UIImagePickerControllerDelegateのキャンセル(imagePickerControllerDidCancel:)した時にも、Popoverを消すと、イイですね(*゚▽゚)ノ
iPad専用のPopOverControllerを使ってみた
こんにちは、@yoheiMuneです。
今日は、iPad専用のPopOverControllerの使い方を学んだので、ブログに残しておきたいと思います。
PopOverControllerとは
以下画像のようなユーザーインターフェースです。画面の一部を覆うようなViewが出現して、その中で表示したり、ユーザーに選択してもらったりするユーザーインターフェースです。
このPopOverControllerは、PopOver部分以外をユーザーがタップすると消えるようになっています。そのため、モーダルViewよりもユーザーに使いやすい(ユーザーが行動を選択しやすい)インターフェースです。
パスワード入力などの必須操作の場合には、モーダルViewを使ってユーザー操作をブロックするのが良いかもですが、ユーザーに任意の操作を選択してもらう場合には、PopOverを使うのが良いのかと思います。
PopOverには、多くのViewを表示出来ます。普通のView、ImageView、TableView、NavigationView、TabViewなどなど。今回は、普通のViewをPopOverに表示するようにしています。
PopOverを表示する
PopOverを表示するには、以下の内容を実装します。
1、PopOverに表示するViewControllerのインスタンスを作成する
2、(任意)PopOverの領域の大きさを設定する
3、PopOverのインスタンスを作成する
4、(任意)PopOverのdelegateを設定する
5、PopOverを表示する
実装例は、以下となります。今回は、画面左上のBarButtonをタップされた際に、PopOverが表示されるようにしています。
- (IBAction) tapAction : (id)sender { // senderは、UIBarButtonItem if (popController == nil) { // popControllerはフィールドに存在する変数 // 1、PopOverに表示するViewControllerのインスタンスを作成する UIViewController *vc = [[[PopContentViewController alloc] init] autorelease]; // 2、(任意)PopOverの領域の大きさを設定する //vc.contentSizeForViewInPopover = vc.view.frame.size; // 3、PopOverのインスタンスを作成する popController = [[UIPopoverController alloc] initWithContentViewController:vc]; // 4、(任意)PopOverのdelegateを設定する。この場合、selfはUIPopoverControllerDelegateプロトコルを実装する必要がある。でも基本的には、delegateを使う用途はないかなぁ。 // popController.delegate = self; // popOverに表示するViewがタップされた場合に、PopOverを消したいので、ジェスチャーを登録しておく UITapGestureRecognizer *tap = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapContent:)] autorelease]; [vc.view addGestureRecognizer:tap]; } // 5、PopOverを表示する [popController presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES]; }
PopOverの表示を消す
PopOverの表示を消すのは、カンタン!以下のような実装をすれば、popOverの表示を消す事が出来ます。
// PopOverを表示する際に、PopOverの中に表示するViewに設定したタップイベント用のメソッド。 - (void) tapContent:(id)sender { // PopOverの表示を消す [popController dismissPopoverAnimated:YES]; }
最後に
iPad用のPopOverを使えるようになった(*´∇`*)カンタンに使えて、使いやすいインターフェースって良いですね。これから使っていこっと。
以下は、関連サイトです。ご参考になれば幸いです。
iPad用のSplitViewを利用する part2
こんにちは、@yoheiMuneです。
今日は、iPad用インターフェースのSplitViewの使い方を学んだので、ブログに残しておきたいと思います。
SplitViewとは & SplitViewの作り方
SplitViewとは何?や、作り方は、こちらの記事(SplitViewの作り方)を参考にしてみて下さい。
なお、今回は、以下のようなSplitViewを使います。左側がTableViewで、右側がToolBarを持つUIViewで構成されています。
SplitViewで2つのViewの動きを制御する
左側のViewで選択された文字が、右側のViewに表示される実装に取組みました。
SplitView内の2つのViewのやり取りは、全て実装者任せとなっているようです。
まずはSplitViewを作成する際に、左側のTableViewを持つViewControllerの変数に、右側のViewへの参照を設定します。
(UIWindowのDelegateでの実装例) - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { SplitLeftViewController *vc1 = [[SplitLeftViewController alloc] initWithNibName:@"SplitLeftView" bundle:nil]; SplitDetailViewController *vc2 = [[SplitDetailViewController alloc] initWithNibName:@"SplitDetailView" bundle:nil]; // 左側ViewControllerのdetailViewControllerという変数に、右側ViewControllerの参照を追加する vc1.detailViewController = vc2; UISplitViewController *spVc = [[UISplitViewController alloc] init]; spVc.viewControllers = [NSArray arrayWithObjects:vc1, vc2, nil]; [self.window addSubview:spVc.view]; [self.window makeKeyAndVisible]; return YES; }
そして、左側のViewControllerにて、テーブルセルがクリックされた際に、選択されたセルの文字列を、detailViewのラベルに設定するという処理を実装します。
(SplitLeftViewControllerにて) - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { NSString *info = [datas objectAtIndex:[indexPath row]]; // datas変数は、テーブルView用のデータソースでNSArray self.detailView.infoLabel.text = info; // infoLabelは、UILabelのインスタンス }
このメソッドは、UITableViewDelegateプロトコルが提供しており、SplitLeftViewControllerで実装しています。
左側のTableViewのdelegateに、SplitLeftViewControllerを指定する事で、テーブルのセルが選択されたときに、上記のメソッドが呼び出されます。
デバイスの縦横の回転に対応する
SplitViewは標準で、横状態では左のViewが表示、縦状態では左のViewが非表示となります。
縦状態の際に、左Viewを表示したい場合には、SplitViewのdelegate(UISplitViewControllerDelegate)を設定して、以下の実装を行います。
- iPadが縦表示になった場合に、Toolbarにボタンを追加し、そのボタンを押下時に、PopoverViewを表示するように設定
- iPadが横表示になった場合に、縦表示になった場合に追加したボタンを削除
上記の処理を、右側ViewControllerに実装します。
(SplitDetailViewControllerでの実装例)
// 縦表示になる場合の処理 - (void)splitViewController:(UISplitViewController*)svc willHideViewController:(UIViewController *)aViewController withBarButtonItem:(UIBarButtonItem*)barButtonItem forPopoverController:(UIPopoverController*)pc { barButtonItem.title = @"List"; NSMutableArray *items = [[toolbar items] mutableCopy]; [items insertObject:barButtonItem atIndex:0]; // ボタンを追加 [[self toolbar] setItems:items animated:YES]; [items release]; } // 横表示になる場合の処理 - (void)splitViewController:(UISplitViewController*)svc willShowViewController:(UIViewController *)aViewController invalidatingBarButtonItem:(UIBarButtonItem *)button { NSMutableArray *items = [[toolbar items] mutableCopy]; [items removeObjectAtIndex:0]; // ボタンを削除 [[self toolbar] setItems:items animated:YES]; [items release]; }
また、SplitViewControllerのdelegateに上記2つのメソッドを実装したインスタンスを設定する必要があります。
最後に
iPad用のViewを一つ使えるようになった(*゚▽゚)ノ次は、PopOverを使えるようになれれば良いなぁ。
以下は関連サイトです。参考になれば幸いです。
iPhoneの向きを特定するもう一つの方法
こんにちは、@yoheiMuneです。
今日は、iPhoneデバイスの向きを特定する方法を。
UIViewControllerのshouldAutorotateToInterfaceOrientationメソッド以外でも、特定する方法を学んだので、ブログに残しておきたいと思います。
UIDeviceとNSNotificationCenterを使って、デバイスの向きの変化を感知する
やり方は凄くカンタン!UIDeviceで向きの変化を感知を開始して、向きの変化があったらNSNotificationCenterに向きの変化を感知させる。こーするだけで、向きの変化を感知することが出来るようです。
以下がサンプルコートです。
- (void)viewDidLoad { [super viewDidLoad]; // start monitoring device orientation changes. [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didRotate:) name:UIDeviceOrientationDidChangeNotification object:nil]; }
ここでは、viewがロードされたタイミングで、UIDeviceのbeginGeneratingDeviceOrientationNotificationsメソッドを読み出し、向きの変化の監視を始めます。
そして、NSNotificationCenterに、UIDeviceOrientationDidChangeNotificationを監視させるオブザーバーを追加し、向きの変化をとらえると、selfのdidRotate:メソッドを呼び出すように指定しています。
didRotate:メソッドの実装例は以下です。
- (void) didRotate:(NSNotification *)notification { UIDeviceOrientation orientation = [[notification object] orientation]; if (orientation == UIDeviceOrientationPortrait) { label1.text = @"device orientation is Portrait."; } else if (orientation == UIDeviceOrientationPortraitUpsideDown) { label1.text = @"device orientation is Portrait Upside Down."; } else if (orientation == UIDeviceOrientationLandscapeLeft) { label1.text = @"device orientation is Landscape Left."; } else if (orientation == UIDeviceOrientationLandscapeRight) { label1.text = @"device orientation is Landscape Right."; } else if (orientation == UIDeviceOrientationFaceUp) { label1.text = @"device orientation is Face Up." } else if (orientation == UIDeviceOrientationFaceDown) { label1.text = @"device orientation is Face Down."; } else { label1.text = @"device orientation is Unkown."; } }
didRote:メドッドは引数にNSNotificationを貰うようにしてあります。NSNotificationからUIDeviceOrientationを取得し、その値を見る事で、デバイスの向きを特定出来ます。UIDeviceOrientationの取りうる値は以下の通りです。
UIDeviceOrientationPortrait | 立て向きで、ホームボタンは下 |
UIDeviceOrientationUpsideDown | 立て向きで、ホームボタンが上 |
UIDeviceOrientationLandscapeLeft | 横向きで、ホームボタンが右 |
UIDeviceOrientationLandscapeRight | 横向きで、ホームボタンが左 |
UIDeviceOrientationFaceUp | 画面が上向き |
UIDeviceOrientationFaceDown | 画面が下向き |
UIDeviceOrientationunKnown | 画面の向きが分からない |
参考サイト
以下のサイトを参考にしました。詳しくは、以下リファレンスをご参照ください。
UIDevice Class Reference
NSNotificationCenter Class Reference