画像ビューとかを簡単に変形させる

こんにちは、@yoheiMuneです。
今日は、画像ビュー(UIImageView)などを、簡単に移動・拡大縮小・回転を行う、アフィン変換を学んだので、ブログに残しておきたいと思います。




アフィン変換とは

アフィン変換とは、wikiでは以下のように話が始まっています。

幾何学におけるアフィン写像(アフィンしゃぞう、英語: affine map)はベクトル空間(厳密にはアフィン空間)の間で定義される、平行移動を伴う線型写像である。

wikipedia:アフィン写像

はい。難しい。数学的なお話は、なかなか理解出来ない。色々と値を変化させると、その値によって、対象図形が移動したり、回転したり、大きくなったりするようです。
でも、良いんです。iPhoneアプリ開発では、アフィン変換用の便利な関数がたくさん用意されています。
それを使えば、簡単にできます。




iPhoneで用意されているアフィン変換

以下のような、関数たちがいます。

■アフィン変換を作成する関数

CGAffineTransformMakeRotation 回転用のアフィン変換を作成できます
CGAffineTransformMakeScale 拡大/縮小用のアフィン変換を作成できます
CGAffineTransformMakeTranslation 移動用のアフィン変換を作成できます
CGAffineTransformMake 回転、移動などをまぜて自分の好きなアフィン変換を作成できます

■アフィン変換を変更する関数

CGAffineTransformTranslate 移動量を変更することができます
CGAffineTransformScale 拡大率を変更することができます
CGAffineTransformRotate 回転率を変更することができます
CGAffineTransformInvert 現在のアフィン変換を反転させることができます
CGAffineTransformConcat 2つのアフィン変換値を組み合わせることができます

アフィン変換を使ってみた

アフィン変換を使って、移動、回転、縮小をしてみました。

- (void)translate {
  // x軸に10pt、y軸に10pt移動する
  imgView.transform = CGAffineTransformMakeTranslation(10.0f, 10.0f);	
}

- (void)rotate {
  // 90度回転する
  imgView.transform = CGAffineTransformMakeRotation(90f * M_PI / 180.0f);
}

- (void)scaleUp {
  // 縦横1.5倍にする
  imgView.transform = CGAffineTransformMakeScale(1.5f, 1.5f);
}

- (void)translate_and_rotate {

  CGAffineTransform t1 = CGAffineTransformMakeTranslation(10.0f, 10.0f);	
  CGAffineTransform t2 = CGAffineTransformMakeScale(1.5f, 1.5f);

  // 移動と回転を組み合わせてみた
  imgView.transform = CGAffineTransformConcat(t1, t2);
}

- (void) reset {
  // アフィン変換のかかっていない状態に戻す
  imgView.transform = CGAffineTransformIdentity;
}


アフィン変換と指のジェスチャーを組み合わせて、ピンチジェスチャーやドラッグジェスチャーで画像の移動や拡大を行う事も可能です。
以下で、試してみたので、もしよければご覧頂けると幸いです。

2011年秋のJJUG_CCCに参加して学んだこと

こんにちは、@yoheiMuneです。
昨日、Japan Java User Groupの秋カンファレンスに参加してきました。今日は珍しくJavaな内容です。
そこで学び取れた事を、ブログに残しておきたいと思います。

Keynote1(Java One 報告会) 丸山先生

メモ全文→→ http://www.facebook.com/note.php?note_id=190925654315275

OracleがPublicクラウドに進出!!アプリケーションを全く変えずに、Oracle Cloud, Amazon Cloud, On Premiseで動作可能な、業界標準クラウドを作ったとのこと。これは凄い!!

★★★
■JavaSE7では、Fork/Join Frameworkなどのマルチコア対応のプログラミングがより簡単に可能。マルチコア対応のプログラミングはこれから出来ないといけないなぁと、実感(`・ω・´)

■JavaSE8は、2013年ころにリリース予定らしい。Project Lamdaというモノがあり、大量データをJavaでもバルク処理が出来るようになるらしい。filter, map, reduce処理を定義して、for文などのループではなくて、バルク処理を行えると。これにより、マルチコアの性能をより引き出せるんだって。ほーほー。

■javaEE7は、2012年第3四半期にリリースされる予定らしい。JavaEE7はなんと、PaaS化する。これはビックニュース!!PaaS化することで、JavaEE7上で実装したアプリケーションは、いろんな環境で動作出来る可能性があり。
これは、業務アプリケーションのクラウド移行を渋る人には、朗報かも(*´∇`*)

■最後に、「Javaは永い眠りから覚めようとしている」という言葉は名言でした。JavaEE6が出てから数年たち、JavaSE7でも微々たる変更だったが、JavaSE8やJavaEE7は大きな変革を遂げようとしていて、これからのJavaの再始動に期待するとのことでした。これから熱くなりそうですね、Java

Keynote1(Java One 報告会) 寺田さん

メモはこちら→→ http://www.facebook.com/note.php?note_id=190925880981919

★★★
■JavaFX2.0のWindows版がリリース!!今後、デスクトップアプリなどのリッチクライアントは、SwingからJavaFXに切り替わるらしい。JavaSE8では、javaFX3.0が盛り込まれると。今から、JavaFXを使えるようになって損はないかもです(((o(*゚▽゚*)o)))

★★★
■JavaEE6は、全世界で一番使われているらしい。日本ではstruts, Springといったフレームワークがまだ主流だが、世界は違う。javaEE6は、自分も使えるようになりたいー!TomeeというTomcatにおけるJavaEEの実装も出たらしい。


■JavaOne 2012 Tokyoが、4/4-5で六本木ヒルズで開催されるらしい。お金があったら、参加してみたいなー。


Twitter社がJCPとOpenJDKに参加。信頼・実績あるJavaを採用する。大規模トランザクションの処理に有効、マルチ言語サポート(Scale, Clojure)が有用




今日は、午前中の分しか記述出来なかった。
いつかは、午後分もかけたらいいなぁ(*´∇`*)

アニメーションを使ってみた

こんにちは、@yoheiMuneです。
今日は、UIViewを使ったアニメーションを学んだので、ブログに残しておきたいと思います。



アニメーションを使い始める

アニメーションを簡単に使うには、UIViewを使うと良いようです。Core Animationというアニメーションを詳細に扱えるフレームワークもありますが、まずは簡単に使うなら、UIViewから入ると良いのではないでしょうか。
UIViewでのアニメーションは、ブロックベースメソッド(iOS4以降)と、Begin/Commitメソッド(iOS3.2 or それ以前)の2種類が用意されているようです。今回は、Begin/Commitメソッドを利用します。ブロックベースメソッドは今度いつか(*´∇`*)



UIViewでアニメーション可能な対象

UIViewのメソッドでアニメーションが行える対象は、以下のようです。

frame ビューの位置とサイズ
bounds ビューのサイズ
center ビューの位置
transform ビューへの変形処理。アフィン変形を適用できる
alpha ビューの透過度
backgroundColor ビューの背景色
contentStretch ビュー上のコンテンツ(画像など)のストレッチ方法

上記以外の要素(レイヤー関連など)をアニメーションしたい場合には、Core Animationを利用する必要があるようです。



アニメーションを実行する

UIViewのメソッドを利用してアニメーションを実現するのは、とても簡単です。
以下のように、begin/commit処理の間に、アニメーションを掛けて変更したい内容を記載するだけで、アニメーションが実現出来ます。
簡単カンタン(((o(*゚▽゚*)o)))

// アニメーションの開始を指定する
[UIView beginAnimations:@"alphaAnimation" context:nil];	

// アニメーションで変更したい内容を記載する
targetView.alpha = 0.0f; 

// アニメーションを開始する
[UIView commitAnimations];

ここでは、対象のビューを透明にするアニメーションを実現します。
beginAnimationsで指定する2つの引数ですが、1つ目がアニメーションID、2つ目がアニメーションに関連づけたい任意のデータです。
これらは、アニメーション発生時のdelegateで使いたい場合には指定しますが、必要なければnilでも大丈夫です。




アニメーションの動きを設定する

上記例では、デフォルトでのアニメーションが発生しますが、アニメーションを以下のように設定する事も可能です。

[UIView beginAnimations:@"alphaAnimation" context:nil];
	
// アニメーションの発生を2秒遅らせる
[UIView setAnimationDelay:2];
// アニメーション時間を2秒に設定する
[UIView setAnimationDuration:2];
// アニメーション動作を指定する。EaseInは、最初ゆっくり、だんだんと早く変化するアニメーション。他の種類もあります。
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
// 同じアニメーションを2度実行するように指定する
[UIView setAnimationRepeatCount:2];
	
[UIView setAnimationBeginsFromCurrentState:YES];
	
targetView.alpha = 0.0f;
[UIView commitAnimations];

上記以外にも設定出来る事項があります。さらに詳しく知りたい!!という場合には、参考文献をご覧下さい。




アニメーション発生前後で、任意の処理を挟みたい

そんな場合には、UIViewにdelegateを設定します。そうすることで、アニメーション発生前、発生後に任意の処理を実行する事が可能となります。

[UIView beginAnimations:@"alphaAnimation" context:nil];

// デリゲートを設定する
[UIView setAnimationDelegate:self];
// アニメーション開始前に呼び出されるメソッドを指定する
[UIView setAnimationWillStartSelector:@selector(animationWillStart:context:)];
// アニメーション終了後に呼び出されるメソッドを指定する
[UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];
	
targetView.alpha = 0.0f;
[UIView commitAnimations];

以下は、上記処理で設定したdelegateメソッドの例です。

// アニメーション実行前に呼び出されるメソッド。
// アニメーション開始時に指定した、アニメーションIDと任意のデータを受け取ることができるため、
// 特定のアニメーションの時だけ、何か処理をする事も可能。
- (void)animationWillStart:(NSString *)animationID context:(void *)context {
	NSLog(@"animationWillStart:context: is called.");
}

// アニメーション実行後に呼び出されるメソッド。
// finished引数は、アニメーションが完了したのか、途中で止まったのか判別するための、BOOL値が格納されている。
- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
	NSLog(@"animationDidStop:finished:context: is called.");
}

参考文献

以下の文献を参考にしました。ありがとうございます。
View Programming Guide for iOS
UIView Class Reference




最後に

アニメーションが実行出来るようになって、より楽しいアプリが作成出来るようになりました。
使ってて楽しいアプリを開発できるように、今後も色々と勉強していくべしバシ(`・ω・´)

以下は関連サイトです。参考になれば幸いです。

iPhoneアプリでデバイスの回転を独自に対応する

こんにちは、@yoheiMuneです。
今日は、iPhone/iPadアプリケーションで、デバイスの回転に独自に対応する方法を学んだので、ブログに残しておきたいと思います。



まずはデバイスの回転を感知して、必要に応じて各種アイテムを回転させる

バイス回転を独自に感知するには、UIDeviceクラスとNSNotificationCenterクラスを利用します。詳しい利用方法は、"iPhoneの向きを特定するもう一つの方法"を参考にしてみて下さい。
バイスが回転したら、特定のメソッドが呼び出されるように設定します。

// ViewControllerの実装にて
- (void)viewDidLoad {
  [super viewDidLoad];

  // デバイスの回転を開始する
  [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
  // デバイスが回転した際に、呼び出してほしいメソッドを設定する。
  // 今回は、selfのdidRotate:というメソッドを呼び出し対象に設定してみました。
  [[NSNotificationCenter defaultCenter] addObserver:self 
                                                         selector:@selector(didRotate:) 
                                                             name:UIDeviceOrientationDidChangeNotification 
                                                            object:nil];
}

バイスが回転したら、以下のメソッドが呼び出されます。
このメソッドの中で、デバイスの向きに合わせて画面上のアイテムを回転します。
また、ステータスバーの位置も修正します。

// デバイスが回転した際に、呼び出されるメソッド
- (void) didRotate:(NSNotification *)notification {
  UIDeviceOrientation o = [[notification object] orientation];

  // 縦向きで、ホームボタンが下になる向き
  if (o == UIDeviceOrientationPortrait) {

    // 画面上の各種アイテムを回転させる為に作ったメソッド。内容は下を参照ください。
    [self correspondToDeviceRotation:0];
    // ステータスバーの位置を変更する。
    [[UIApplication sharedApplication] setStatusBarOrientation:UIDeviceOrientationPortrait animated:YES];

  // 縦向きで、ホームボタンが上になる向き
  } else if (o == UIDeviceOrientationPortraitUpsideDown) {
    [self correspondToDeviceRotation:180];
    [[UIApplication sharedApplication] setStatusBarOrientation:UIDeviceOrientationPortraitUpsideDown animated:YES];

  // 横向きで、ホームボタンが右になる向き		
  } else if (o == UIDeviceOrientationLandscapeLeft) {
    [self correspondToDeviceRotation:90];
    [[UIApplication sharedApplication] setStatusBarOrientation:UIDeviceOrientationLandscapeLeft animated:YES];

  // 横向きで、ホームボタンが左になる向き
  } else if (o == UIDeviceOrientationLandscapeRight) {
    [self correspondToDeviceRotation:270];
    [[UIApplication sharedApplication] setStatusBarOrientation:UIDeviceOrientationLandscapeRight animated:YES];

  // 画面が上向き
  } else if (o == UIDeviceOrientationFaceUp) {
    NSLog(@"device orientation is Face Up.");
    // no need actions.

  // 画面が下向き		
  } else if (o == UIDeviceOrientationFaceDown) {
    NSLog(@"device orientation is Face Down.");
    // no need actions.

  // 向きが不明な場合		
  } else {
    NSLog(@"device orientation is Unkown.");
    // no need actions.

  }
}

// 画面上の各種アイテムを回転させるメソッド
- (void) correspondToDeviceRotation : (int)angle {

  // 回転させるためのアフィン変形を作成する
  CGAffineTransform t = CGAffineTransformMakeRotation(angle * M_PI / 180);
	
  // 回転させるのにアニメーションをかけてみた
  [UIView beginAnimations:@"device rotation" context:nil];
  [UIView setAnimationDuration:0.3];
	
  trustButton.transform	= t;  // ゴミ箱ボタン
  undoButton.transform	= t;  // Redoボタン
  redoButton.transform	= t;  // Undoボタン

  // アニメーション開始	
  [UIView commitAnimations];
}

ここでは、デバイスの向きに合わせて、アフィン変換を利用して、ボタンの回転を行っています。アフィン変換の回転については、"ローテーションジェスチャーを簡単に実装する"を参考にしてみて下さい。



独自にデバイスの回転に対応する上で大切なこと

それは、ステータスバーの位置を、デバイスの向きによってちゃんと変える事です。
これを行う事で、新しく開くView(例:UIImagePickerView)などの向きを変えることが出来ます。
動作させたところ、ステータスバーが上になるようにUIViewの向きが決定されるようです。
という事で、ステータスバーの位置変更も忘れず行うと、デバイスの回転に自分で対応することは、出来るようです。



最後に

バイス回転を、「shouldAutorotateToInterfaceOrientation:」メソッドを使わずに行う方法には、かなり悩まされました。
でも、いったんの上記のような解決策を作れて良かったヨカッタ♪(´ε` )
iPhoneアプリ作成では、学ぶ事がホントに多いですね。もっと実力をつけねば。


以下は関連サイトです。参考になれば幸いです。

Viewの背景色を透明にする方法

こんにちは、@yoheiMuneです。
今日は、UIViewの背景色を透明にする方法を学んだので、ブログに残しておきたいと思います。今日はライトなネタ(*゚▽゚)ノ



背景色透明のViewを作成する

背景色透明のViewを作成すると、一つ下のViewの表示内容も見えるようになり、アプリケーションとしての表現力が向上するのではないでしょうか。
例えば、描画アプリの場合には、レイヤーという考えを、背景色透明なVIewで実現することが出来ます。
実装方法は簡単。以下のようにすれば出来るようです♪(´ε` )

- (void)viewDidLoad {
  [super viewDidLoad];

  // 背景色を透明にしたいUIViewのインスタンスを作成する
  UIView *aView = [[UIView alloc] initWithFrame:self.view.frame];

  // opaque属性にNOを設定する事で、背景透過を許可する
  aView.opaque = NO;

  // backgroundColorにalpha=0.0fの背景色を設定することで、背景色を透明にしている
  aView.backgroundColor = [UIColor colorWithWhite:1.0f alpha:0.0f]; // transparent background.

  // 作成した背景色透明のViewを現在のViewの上に追加する
  [self.view addSubview:aView];
}

上記のopqueとbackgroundは、Interface Builderでも設定する事は可能です。
opaqueのチェックボックスをオフにして、背景色指定する箇所で、透明度=0.0に設定すると、上記コードと同じ効果を得ることができます。



参考

以下のサイトを参考にしました。ありがとうございます。
UIView Class Reference



最後に

ちなみに、Appleのガイドによると、「描画パフォーマンスに影響するから、背景色を透明や半透明にするViewは最小限にしましょう」とのこと。
iPhoneアプリ開発を初めて1年弱。初めてUIViewの背景を完全透明にする方法を知りました。今迄そんなこと必要なかったから使わなかったけど、出来ると便利ですね。

以下は関連ページです。参考になれば幸いです(・∀・)

画像のリサイズを行うには

こんにちは、@yoheiMuneです。
今日は、画像のリサイズ方法を学んだので、ブログに残したいと思います。今日はライトなネタ♪(´ε` )




画像のリサイズを行う

画像の拡大縮小を行うには、以下のような処理を実行する事で、リサイズを行うことが出来ます。画像はUIImageのオブジェクトを前提とします。

- (void) doSomething : (id) sender {

  UIImage *aImage = imageView.image;  // imageViewはUIImageView型のフィールド変数。

  // 画像を縮尺1/2にする  ←今回説明したい部分
  UIImage *resizedImage = [self resizeImage:aImage scale:0.5f];
  
  // 縮小した画像をUIImageViewの画像として登録する
  imageView.image = resizedImage;
}

// 画像をリサイズするメソッド。
// @param img リサイズ対象の画像
// @param scale リサイズ縮尺
// @return リサイズ後の画像
- (UIImage*)resizeImage:(UIImage *)img scale:(float)scale {

  // 指定されたスケールから、画像のリサイズ後のサイズを計算する
  CGSize resizedSize = CGSizeMake(img.size.width * scale, img.size.height * scale);

  // UIGraphics××の関数を利用して、画像をリサイズする   ←ここが重要な部分!!!
  UIGraphicsBeginImageContext(resizedSize);
  [img drawInRect:CGRectMake(0, 0, resizedSize.width, resizedSize.height)];
  UIImage* resizedImage = UIGraphicsGetImageFromCurrentImageContext();
  UIGraphicsEndImageContext();

  // リサイズ後の画像を呼び出し元に返す
  return resizedImage;
}

上記のように実装する事で、画像の拡大縮小を簡単に行う事が可能です。「resizeImage:scale:」メソッドは、他のプロジェクトにそのまま移植する事も可能かもしれません。





最後に

リサイズや回転など、画像をいじる処理は、たびたび必要になるもんですね。画像をだんだんと自由に扱えるようになってくると、楽しいかも。次は回転をやってみよっと(*゚▽゚)ノ
以下は、関連ページです。参考になれば幸いです。

ナビゲーションボタンを小ビューから追加する

こんにちは、@yoheiMuneです。
今日は、またニッチなネタかも。。
ナビゲーションビューから呼び出された子ビューから、親ビューであるナビゲーションビューのナビゲーションバーにボタンを追加する方法を学んだので、ブログに残しておきたいと思います。



子ビューから親のナビゲーションビューのナビゲーションバーにボタンを追加する

iPhoneアプリケーションにおいて、ナビゲーションビューを使う事も多いかと思います。
ナビゲーションビューから呼び出された子ビューにおいて、親のナビゲーションバーにボタンを追加したいと思った時に、以下のような実装を子ビューでする事で、ボタンを追加することが出来るようです。

- (void)viewDidLoad {
  [super viewDidLoad];

  // OKという文字が表示されたボタンを追加する
 // UIBarButtonItemのインスタンス作成時に、ボタン押下時に呼び出すメソッドを指定する
  UIBarButtonItem *okButton = [[UIBarButtonItem alloc] initWithTitle:@"OK" style:UIBarButtonItemStylePlain target:self action:@selector(okAction:)];

  // 親NavigationViewControllerのナビゲーションバーにボタンを追加する
  self.navigationItem.rightBarButtonItem = okButton;
  [okButton release];
}

ここでは、「self.navigationItem」というUIViewControllerのフィールドがポイントです。
navigationItemは、"UIViewController Class Reference"では以下のように説明されています。

This is a unique instance of UINavigationItem created to represent the view controller when it is pushed onto a navigation bar. The first time you access this property, the UINavigationItem is created.

NavigationItem オブジェクトは、View Controllerが表示されるときにNavigation Barに表示されるオブジェクトを提供します。このオブジェクトを使用して、ビューにカスタムタイトルや追加のコントロールを提供できます。
そして今回は、NavigationItemオブジェクトのrightBarButtonプロパティに、独自に作成したOKボタンを追加するように実装しました。




最後に

iPhoneアプリケーションでは、絶対に使うViewControllerですが、知らない機能がいっぱいですね(*´∇`*)もっとガイドも読んで、勉強しよっと。
以下は関連サイトです。参考になれば幸いです。