トランジションアニメーション(1)

2010. 06. 26
次にトランジションアニメーションの導入をします。

トランジションアニメーションは、変更前と後の画像の遷移を表すアニメーションで、左右のフリップと上下のカールの4種類あります。

451

左フリップ(UIViewAnimationTransitionFlipFromLeft)

452

上カール(UIViewAnimationTransitionCurlUp)

本書では、カールアニメーションがiPhone Simulatorではフェードエフェクトで代替表現されるとありますが、現在のiPhone Simulator(バージョン4.0(211.1)。Xcode 3.2.3 and iPhone SDK 4(10M2262)に入っているもの)ではカールアニメーションも表示されます。


・UIViewAnimationTransition
(UIViewクラス)

typedef enum {
    UIViewAnimationTransitionNone,
    UIViewAnimationTransitionFlipFromLeft,
    UIViewAnimationTransitionFlipFromRight,
    UIViewAnimationTransitionCurlUp,
    UIViewAnimationTransitionCurlDown,
} UIViewAnimationTransition;

アニメーションブロック内のビューに、指定した遷移を適用します。

UIViewAnimationTransitionNone
遷移を指定しません。

UIViewAnimationTransitionFlipFromLeft
(画像の中心を通る)縦軸を中心に左から右にビューが回転する、フリップ(裏返す)の遷移を行います。
ビューの左側が手前に、右側が奥に向かって動きます。

UIViewAnimationTransitionFlipFromRight
縦軸を中心に右から左にビューが回転する、フリップの遷移を行います。
ビューの右側が手前に、左側が奥に向かって動きます。

UIViewAnimationTransitionCurlUp
ビューの下部から上へ巻き上げる遷移を行います。

UIViewAnimationTransitionCurlDown
ビューの上部から下へ巻き下げる遷移を行います。


●トランジションアニメーションの実装

トランジションアニメーションを実装するには、遷移に必要な前後2枚の画像をアニメーションブロック内で読み込む必要があります。

そのため、遷移のトリガとしてスライドショー用のタイマー(timerSlide)を追加し、startStop:メソッドに組み込みます。

タイマーが発火するとトランジションアニメーションを実行するnextSlide:メソッドを呼び出します。

nextSlide:メソッド内で、画像配列imagesから次に表示する画像番号curImageIndexを取得し、画像の遷移を行います。

また画像の切り替え速度の変化に対応するため、changeDuration:メソッドもタイマーに置換します。


●Slide.hの編集

スライドショー用のタイマーと(timerSlide)、画像配列(images)、そして遷移用に次に表示する番号を配列から取得するための現在表示している配列番号(curImageIndex)を宣言します。
(太字が追加した部分)

#import <Foundation/Foundation.h>

@interface Slide : NSObject {

    // アウトレット
    IBOutlet UIImageView *imageSlide;    // 画像表示
    IBOutlet UIToolbar *toolbar;    // ツールバー
    IBOutlet UISlider *sliderDuration;    // 長さ変更
    IBOutlet UISegmentedControl *segShuffle;    //シャッフル
    IBOutlet UIButton *btnStartStop;    // 開始ボタン

    NSTimer *timerSlide;    // スライド用タイマー
    NSArray *images;    // スライド用画像配列
    int curImageIndex;    // 現在表示している画像の番号
}

// アクション
- (IBAction)startStop:(id)sender;    // スライドショーの開始停止
- (IBAction)changeOrder:(id)sender;    // スライドショーのシャッフル
- (IBAction)changeDuration:(id)sender;    // スライドショーの長さの変更

- (void)enterOrExitFullScreen;
- (void)enterOrExitFullScreenWithAnimation;

@end

453


●タイマー用画像配列と表示画像番号の初期化

タイマー用画像配列と表示画像番号の初期化をawakeFromNibメソッドに追加するとともに、不要になるUIImageViewのアウトレット(imageSlide)の処理を削除します。
(太字が追加した部分)

- (void)awakeFromNib {
    // スーパークラスによる初期化
    [super awakeFromNib];

    // 画像配列を自前の配列に保持
    images = [[self animationImages] retain];

    //表示画像番号を初期化
    curImageIndex = 0;

    // タイマーは動かさない
    timerSlide = nil;

    // UIButtonに画像を貼り付ける

    // 背景画像の読み込み
    UIImage *imgBtn1 = [UIImage imageNamed:@"grayButton.png"];

    // 背景画像から伸縮画像を生成
    UIImage *imgBtn2 = [imgBtn1 stretchableImageWithLeftCapWidth:13 topCapHeight:0];

    // 伸縮可能画像をUIButtonの背景に設定
    [btnStartStop setBackgroundImage:imgBtn2 forState:UIControlStateNormal];
}

454

本書内のコードでは、画像配列の読み込みが『setupImageArrayFromResource』(XML化時に名前を変更したメソッド)になっています。
(詳細は『スライドショーの画像配列をXML化』を参照してください)

このメソッド名変更は本書内では説明されておらず、サンプルコードで実装されているだけなので気付き難いかもしれません。

ここではanimationImagesに修正しています。


●Start/Stopボタンのアクションメソッドのタイマー化

Start/Stopボタンによるアニメーションの再生/停止を、UIImageViewによるアニメーションからタイマーによる発火に置き換えます。

また、スライドショー中は無操作でも自動スリープに入らない機能を追加しています。
(太字が追加・修正した部分)

- (IBAction)startStop:(id)sender {
    // アニメーション中かどうかの判定
    BOOL isAnimating = (timerSlide != nil);

    // アニメーション停止処理
    if (isAnimating == YES) {
        // タイマーを止め、nilに戻す
        [timerSlide invalidate];
        timerSlide = nil;
        [btnStartStop setTitle:@"Start" forState:UIControlStateNormal];
    }
    else {
        // タイマーを生成
        timerSlide = [NSTimer scheduledTimerWithTimeInterval:sliderDuration.value / [images count] target:self selector:@selector(nextSlide:) userInfo:nil repeats:YES];
        [btnStartStop setTitle:@"Stop" forState:UIControlStateNormal];
    }

    // スリープを抑制
    UIApplication *app = [UIApplication sharedApplication];
    app.idleTimerDisabled = isAnimating;
}

455

アニメーション中かどうかの判定を、UIImageViewのisAnimatingメソッドからスライドショー用timerSlideの有無にして、タイマーが有ればアニメーション中、無ければ停止中と判別します。

したがって判定後の処理も、アニメーションを停止する場合はタイマーの停止と無効化、再生する場合はタイマーの生成を行っています。

タイマーが発火するとトランジションアニメーションを実行するnextSlide:メソッドを呼び出します。


・invalidate
(NSTimerクラス)

- (void)invalidate

レシーバのタイマーを要求があるまで、再発火の停止および実行ループからの削除をします。

このメソッドはNSRunLoopオブジェクトからタイマーを除去する唯一の方法です。

NSRunLoopオブジェクトは、invalidメソッドが返す直前か少し後の時点でタイマーの除去と解放を行います。

ターゲットとユーザ情報オブジェクトと共に構成されている場合、レシーバは参照しているこれらのオブジェクトも解放します。

特別な考慮事項

このメッセージは、タイマーを設置しているスレッドからメッセージを送る必要があります。

このメッセージを他のスレッドから送信した場合、入力ソースに関連付けられているタイマーが実行ループから除去されず、スレッドが適切に終了できなくなります。


・idleTimerDisabled
(UIApplicationクラス)

@property(nonatomic, getter=isIdleTimerDisabled) BOOL idleTimerDisabled

アプリケーションのアイドルタイマーを無効にするかどうかを制御するブール値です。

このプロパティのデフォルト値はNOです。

アプリケーションでタッチ操作による短期間ユーザの入力が無い場合、システムはスリープ状態になり、デバイスの画面が薄暗くなります。

これは省電力の目的のために行われます。

しかし、ゲームなどの加速度センサ以外のユーザ入力の無いアプリケーションの場合、このプロパティをYESにすることでアイドルタイマーを無効にして、システムのスリープを防ぐことができます。

重要:このプロパティは必要な場合にのみ設定し、必要が無くなったらNOにしてリセットする必要があります。

アプリケーションは、アイドルタイマーが経過した時にシステムがスクリーンをオフにできるようにする必要があります。

これにはオーディオアプリケーションも含まれます。

適したオーディオセッションサービスを使い、スクリーンがオフになっても継続して再生や録音ができるようにしてください。

地図アプリケーションやゲームなどの、散発的にユーザと対話するアプリケーションでは、アイドルタイマーを無効にする必要があります。


●トランジションアニメーションを行うメソッドの実装

タイマー発火時に呼び出される、トランジションアニメーションを実行するnextSlide:メソッドを実装します。

- (void)nextSlide:(NSTimer *)timer {

    // 表示画像番号の更新
    curImageIndex++;
    if ([images count] <= curImageIndex) {
        curImageIndex = 0;
    }

    // アニメーションの準備
    [UIView setAnimationsEnabled:YES];
    [UIView beginAnimations:@"Slide" context:nil];
    [UIView setAnimationDuration:1.0f];

    // トランジションアニメーションの設定
    [UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:imageSlide cache:YES];

    // 画像の切り替え
    imageSlide.image = [images objectAtIndex:curImageIndex];

    // アニメーション実行
    [UIView commitAnimations];
}

456

最初に現在表示されている画像配列の番号(curImageIndex)をインクリメント(+1加算)して、トランジションアニメーションに用いる次の画像番号を得ます。

画像番号が画像配列の要素数を超える場合には0に戻しています。

setAnimationsEnabled:でアニメーションを有効に、beginAnimations:でアニメーションブロックを開始、setAnimationDuration:でアニメーションする時間を設定します。

トランジションアニメーションは、setAnimationTransition:forView:cache:メソッドで行います。

今回は4種類の中からカールアップを選択し、キャッシュも有効にしています。

そしてobjectAtIndex:メソッドでトランジション後の画像オブジェクトをimageプロパティで入れ替え、commitAnimationsでアニメーションブロックを終了します。


・setAnimationDuration:
(UIViewクラス)

+ (void)setAnimationDuration:(NSTimeInterval)duration

アニメーションブロックで、アニメーションを行うプロパティの継続時間を秒単位で設定して変更します。

このメソッドは、アニメーションブロックの外側で呼び出された場合は何もしません。

アニメーションブロックはbeginAnimations:context:クラスメソッドで開始し、commitAnimationsクラスメソッドで終了します。

デフォルト値は0.2(秒)です。

このメソッドは、iPhone OS 4.0以降は推奨されません。

代わりにブロックベースのアニメーションメソッドを使用してください。

duration:アニメーションを継続する期間を指定します。


・setAnimationTransition:forView:cache:
(UIViewクラス)

+ (void)setAnimationTransition:(UIViewAnimationTransition)transition forView:(UIView *)view cache:(BOOL)cache

アニメーションブロック中にビューの適用する遷移を設定します。

UIViewのインスタンスであるコンテナビューを使って、ビューの外観変更の遷移する(例えば、あるビューから別のビューにフリップで切り替わる)場合、以下のような手順になります。

1.アニメーションブロックの開始
2.コンテナビューの遷移を設定
3.コンテナビューからサブビューを削除
4.コンテナビューに新しいサブビューを追加
5.アニメーションブロックを確定

このメソッドは、iPhone OS 4.0以降は推奨されません。

代わりにブロックベースのアニメーションメソッドを使用してください。

transition:viewに適用する遷移を指定します。
指定可能な値は、UIViewAnimationTransitionに表されています。

view:遷移を適用するビューを指定します。

cache:YESの場合、viewの前後の画像を一度描画し、アニメーションのフレーム生成に使用します。
このパラメータをYESに設定すると、キャッシュにより性能を向上させることができますが、遷移中にビューまたはサブビューを更新することはできません。
アニメーション中にビューとサブビューを更新すると、キャッシュの動作を妨げるだけでなく、間違った内容や場所の表示になります。
遷移が終了するまでビューの更新を待つ必要があります。
NOの場合、遷移アニメーションの各フレームごとに、ビューとその内容を更新する必要がありますが、フレームレートに著しく影響を与える可能性があります。


・image
(UIImageViewクラス)

@property(nonatomic, retain) UIImage *image

イメージビューに画像を表示します。

このプロパティの初期値は、initWithImages:メソッドの画像が渡されるか、レシーバが初期化に別のメソッドを渡す場合はnilになります。

animationImagesプロパティの値にnil以外が含まれている場合は、このプロパティの内容は使用されません。

imageプロパティでは、UIImageViewのサイズを変更する設定はありません。

画像をビューのサイズに適応させる場合は、sizeToFitを呼び出してください。


●速度切り替えバーのアクションメソッドのタイマー化

スライダによるアニメーション速度の切り替えを行うchangeDuration:メソッドも、タイマーに置き換えます。

タイマーの間隔は後から変更できないので、一旦タイマーを停止・無効化して、生成し直します。
(太字が追加・修正した部分)

- (IBAction)changeDuration:(id)sender {

    // タイマーを止める
    [timerSlide invalidate];

    // タイマーを生成
    timerSlide = [NSTimer scheduledTimerWithTimeInterval:sliderDuration.value / [images count] target:self selector:@selector(nextSlide:) userInfo:nil repeats:YES];
}

457

invalidateメソッドで、タイマーを一旦停止・無効化します。

そしてscheduledTimerWithTimeInterval:target:selector:userInfo:repeats:メソッドでタイマーを作り直しています。

発動間隔はスライダの値(sliderDuration.value)を画像配列の要素数で割ったものを使用しています。



参考文献

UIView Class Reference

NSTimer Class Reference

UIApplication Class Reference

基礎からのiOS SDK基礎からのiOS SDK
(2010/10/09)
鶴薗 賢吾、松浦 健一郎 他

商品詳細を見る






Wave SoundTouch music system IV
0 Comments
Leave a comment
管理者にだけ表示を許可する
Top
0 Trackbacks
Top
Calendar
06 | 2017/07 | 08
Sun Mon Tue Wed Thu Fri Sat
- - - - - - 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 - - - - -
Recent Articles
iTunes


Swift
Categories
Tips
Profile

水月杏香

Author:水月杏香
永遠の初心者プログラマ。

Wish List
WACOM


ARC
Technical Q&A
情報プロパティリストキー
Start Developing iOS Apps Today
BOSE

Wave SoundTouch music system IV
Reference
NSApplicationDelegateプロトコル
NSArrayクラス
NSAutoreleasePoolクラス
NSBundleクラス
NSBundle UIKit追加分
NSCalendarクラス
NSCoderクラス
NSCodingプロトコル
NSCopyingプロトコル
NSDataクラス
NSDateクラス
NSDateFormatterクラス
NSDictionaryクラス
NSEntityDescriptionクラス
NSEnumeratorクラス
NSErrorクラス
NSExceptionクラス
NSFetchRequestクラス
NSFileHandleクラス
NSFileManagerクラス
NSIndexPathクラス
NSIndexPath UIKit追加分
NSKeyedArchiverクラス
NSKeyedUnarchiverクラス
NSKeyValueCodingプロトコル
NSLocaleクラス
NSManagedObjectクラス
NSManagedObjectContextクラス
NSManagedObjectModelクラス
NSMutableArrayクラス
NSMutableCopyingプロトコル
NSMutableDictionaryクラス
NSMutableSetクラス
NSNotificationクラス
NSNotificationCenterクラス
NSNullクラス
NSNumberクラス
NSObjectクラス
NSObject UIKit追加分
NSObjectプロトコル
NSPersistentStoreクラス
NSPersistentStoreCoordinatorクラス
NSPredicateクラス
NSPropertyListSerializationクラス
NSRunLoopクラス
NSSetクラス
NSStringクラス
NSString UIKit追加分
NSTimerクラス
NSTimeZoneクラス
NSURLクラス
NSURLProtectionSpaceクラス
NSURLRequestクラス
NSUserDefaultsクラス
NSValueクラス

UIActionSheetクラス
UIActionSheetDelegateプロトコル
UIActivityIndicatorViewクラス
UIAlertViewクラス
UIAlertViewDelegateプロトコル
UIApplicationクラス
UIApplicationDelegateプロトコル
UIBarButtonItemクラス
UIBarItemクラス
UIButtonクラス
UIColorクラス
UIControlクラス
UIDatePickerクラス
UIDeviceクラス
UIEventクラス
UIFontクラス
UIGestureRecognizerクラス
UIImageクラス
UIImageViewクラス
UIKit Function
UILabelクラス
UINavigationControllerクラス
UINavigationItemクラス
UIPickerViewクラス
UIPickerViewDataSourceプロトコル
UIPickerViewDelegateプロトコル
UIPinchGestureRecognizerクラス
UIResponderクラス
UIScreenクラス
UIScrollViewクラス
UISearchBarクラス
UISearchBarDelegateプロトコル
UISegmentedControlクラス
UISliderクラス
UISwipeGestureRecognizerクラス
UISwitchクラス
UITableViewクラス
UITableViewCellクラス
UITableViewControllerクラス
UITableViewDataSourceプロトコル
UITableViewDelegateプロトコル
UITapGestureRecognizerクラス
UITextFieldクラス
UITextFieldDelegateプロトコル
UITextInputTraitsプロトコル
UITextViewクラス
UITextViewDelegateプロトコル
UIToolbarクラス
UITouchクラス
UIViewクラス
UIViewControllerクラス
UIWebViewクラス
UIWebViewDelegateプロトコル
UIWindowクラス

AVAudioPlayerクラス
AVAudioPlayerDelegateプロトコル

CADisplayLinkクラス
CAEAGLLayerクラス
CALayerクラス

CGAffineTransform
CGBitmapContext
CGColor
CGColorSpace
CGContext
CGGeometry
CGImage
CGPath

EAGLContextクラス
EAGLDrawableプロトコル

Foundation Constants
Foundation Data Types
Foundation Functions

MPMediaItemクラス
MPMediaItemArtworkクラス
MPMediaPlaylistクラス
MPMediaPropertyPredicateクラス
MPMediaQueryクラス
MPMusicPlayerControllerクラス

Randomization Services

System Sound Services
Amazon


OpenGL ES
SQLite
Monthly Archives
Recent Comments
Recent TrackBacks
RSS Link
Visitors
QR Code
QR