スライドショーの作成

2010. 06. 07
基礎からのiPhone SDK 改訂版』の次のお題はスライドショーです。


●サンプルアプリケーションの概要

複数画像の連続表示ですが、

・スライドショーの開始と停止(ボタン)
・順次表示とランダム表示の切り替え(セグメンテッドコントロール)
・切り替え時間間隔の調整(スライダ)

という制御をするツールバーを持っています。

411


●プロジェクトの作成

Window-based Applicationテンプレートで、プロジェクト名を『Slide』とします。

388


●nibファイルの編集


1)画像素材の準備

nibファイルの編集の前に素材を用意する必要があります。

・スライドショーで流す画像
・ツールバーに使用するアイコン画像

スライドショー用の画像はお好みでご用意ください。
サイズや枚数は任意で構わないのですが今回は7枚のJPG画像(320x480ピクセル)を用意しました。
(また起動時の背景画像に別途Background.png(320x480ピクセル)を使っていますが、スライドショー用の画像を流用しても構いません)

ツールバーに使用するアイコン画像は自作されても良いですし、既存のボタンを流用する手もありますが、今回は『基礎からのiPhone SDK 改訂版』の出版社のサイトからサンプルコードをダウンロードし、そこからアイコン画像をコピーして使用します。
(スライドショー用の画像が用意できない方は、それもコピーしてください)

iPhoneBG2.zipを展開すると『SampleCode』→『60.01.Slide』フォルダ下に画像ファイルがあります。

photo1.jpgスライドショー用画像(兼背景画像)
photo2.jpgスライドショー用画像
photo3.jpg
photo4.jpg
fast.pngスライダ用画像(画像切り替え速い)
grayButton.pngStart/Stopボタン用背景画像
normal.pngセグメンテッドボタン用画像(切り替え順序通常)
shuffle.pngセグメンテッドボタン用画像(切り替え順序シャッフル)
slow.pngスライダ用画像(画像切り替え遅い)

新規作成したSlideプロジェクトのフォルダに画像ファイルを入れ、XcodeのResourcesに登録し、MainWindow.xibをダブルクリックしてInterface Builderを開きます。

389


2)背景画像の設定

起動時の背景画像を設定します。

LibraryウィンドウからImage Viewをドラッグ&ドロップでViewウィンドウに配置し、InspectorウィンドウのImageでBackground.pngまたは背景用の画像(サンプルコードではphoto1.jpg)を選択します。

390

Image Viewは後々フルスクリーン表示を行うため全画面(X:0、Y:0、W:320、H:480)に設定します。


3)ツールバーの設置

LibraryウィンドウからToolbarをドラッグ&ドロップでViewウィンドウの下端に配置します。

設定はデフォルト(X:0、Y:436、W:320、H:44)のままです。

391

ツールバーにデフォルトで付いているBar Button Itemは、Round Rect Buttonに置き換えますので削除します。

ViewウィンドウでBar Button Itemを選択し、ウィンドウ外にドラッグすると削除できます。

392


4)Start/Stopボタンの設置

LibraryウィンドウからRound Rect Buttonをドラッグ&ドロップでViewウィンドウのツールバーの左端に配置します。

393

InspectorウィンドウのSizeパネルで、位置とサイズを調整します。

394

XとYは変更できませんが、W:51、H:29と指定すると、自動で微調整してX:12、Y:8になるようです。

396

Attributesパネルでの設定を行います。

・Button

Start/StopボタンはgrayButton.pngを使ってカスタマイズしますので、『Type』を『Rounded Rect』から『Custom』にします。

『Title』は文字の初期値として『Start』とします。

『Shadow』はボタンの影で、『Black』にします。

ボタンを押した時に光るように『Drawing』の『Shows Touch On Highlight』にチェックを入れます。

・View

『Background』のOpacityを0%にして、ボタンを透明化します。

『Drawing』の『Clear Context Before Drawing』は、ボタンの文字列を更新する時に前の文字列をクリアするかどうかの設定です。

ここではTitleで設定した『Start』が、ボタンが押された時に『Stop』に、もう一度押すと『Start』に戻るということを繰り返しますので、チェックを入れます。
(チェックを入れないと重ね書きになります)

395

『Background』のOpacityを0%にしても、Interface Builderのボタンが白いままですが、iPhone Simulatorで実行するとクリアになっています。

397

この設定は、nibファイル編集中はInterface Builderで反映されないようで、一旦ファイルを閉じて開き直すと正常に表示されます。

398

grayButton.pngを使ったカスタマイズは、画像をそのまま貼り付けるのではなく、コードで画像を分割拡大して貼るので、Interface Builderの設定はここまでになります。


5)モード変更ボタンの設置

LibraryウィンドウからSegmented Controlをドラッグ&ドロップでViewウィンドウのツールバーのRound Rect Buttonのすぐ右側に配置します。

399

セグメンテッドコントロールはXとYとHが変更できませんので、W:82と設定します。

400

Attributesパネルでの設定を行います。

・Segmented Control

モード変更のセグメンテッドコントロールは、文字ではなくアイコンのボタンになりますので、『Title』の『First』文字列を削除します。

Segment 0は『Images』のプルダウンメニューから『normal.png』を選びます。

・View

先程のRound Rect Buttonと異なりボタンの表示内容は変更しませんので『Drawing』の『Clear Context Before Drawing』のチェックは外しておきます。

401

続いてSegment 1の設定をします。

Segmented Controlの『Tint』と『Title』にあるプルダウンメニューから『Segment 1』を選択します。

Segment 0と同様に『Title』の文字列を削除し、『Image』は『shuffle.png』にします。

402


6)速度切り替えバーの設置

LibraryウィンドウからSliderをドラッグ&ドロップでViewウィンドウのツールバーのSegmented Controlのすぐ右側に配置します。

403

スライダもXとYとHが変更できませんので、W:148と設定します。

404

Attributesパネルでの設定を行います。

・Slider

『Values』はスライダの最小値と最大値、初期値、検出方法を設定します。

制御内容に依存する数値なので、自作アプリの場合は予め数値を考えておく必要がありますが、今回はサンプルコードの数値に従います。

Minimum:2.00、Maximum:20.00、Initial:4.00、『Continuous』のチェックは外します。

『Continuous』はスライダの移動をリアルタイム検出するかどうかの設定で、チェックが入っている場合は随時値が反映されるので、音楽系アプリでのボリューム制御などの場合にはチェックを入れた方がいいかもしれません。

今回はリアルタイム制御の必要がないので、チェックは外します。

『Min Image』と『Max Image』はスライダの左側(Min)と右側(Max)に画像を設定する項目です。

『Min Image』は『fast.png』、『Max Image』は『slow.png』をプルダウンメニューから選択します。

・View

サンプルコードを見ると、『Drawing』の『Clip Subviews』と『Interaction』の『Multiple Touch』にチェックが入っていますが、これについては理由が分かりません。

『Clip Subviews』ははみ出た場合に自動で収まるように調整する機能なのですが、スライダで画像がはみ出ることは考えられません。

※2010.8.7補足
サブビューが親ビューからはみ出ている場合、はみ出た部分は縮小されるのではなく、カットオフされるようです。
また、チェックするとカットオフの為の余計な演算が入ることになるので、通常はデフォルトのままチェックを入れない方が良さそうです。

また『Multiple Touch』にしても、マルチタッチで操作する類のものではありませんし、コードでそのような実装も行いません。

本書でもこの辺の説明はされていないのですが、一応同じ設定にはしておきます。

Valuesの操作などをするとInterface Builder上の表示が乱れますが、保存して一度閉じて再度開くと正常に表示されます。

405

Interface Builderでの画面レイアウトはこれで完了です。


●スライドショークラスの作成

今回もスライドショーを行う部分は独立させたクラスに記述します。

Xcodeの『グループとファイル』ペインの『Classes』を右クリックして、コンテキストメニューから『追加』→『新規ファイル』を選択し、名前を『Slide』としてSlideクラスを追加します。


●アウトレットとアクションの設定

Slide.hヘッダファイルにアウトレットとアクションを定義します。
(太字が追加した部分)

#import <Foundation/Foundation.h>

@interface Slide : NSObject {

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

}

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

@end

406

本書では特に触れられていないのですが、Slideクラスのインスタンスをデリゲートに接続するため、SlideAppDelegate.hを編集します。
(太字が追加した部分)

#import <UIKit/UIKit.h>
#import "Slide.h"

    @interface SlideAppDelegate : NSObject {
    IBOutlet Slide *slide;

    UIWindow *window;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;

@end

409

編集が終わったらファイルを保存し、Interface Builderで接続します。

まずSlideクラスのインスタンスを作るため、LibraryウィンドウからObjectをDocumentウィンドウにドラッグ&ドロップします。

Documentウィンドウの追加したObjectを選択した状態で、InspectorウィンドウのIdentityパネルを開き、『Class Identity』の『Class』を『Slide』にします。

407

次にInspectorウィンドウのConnectionsパネルを開き、アウトレットとアクションを接続します。

Outlets
btnStartStopStart/Stopボタン
imageSlideイメージビュー(背景画像)
SegShuffleモード変更ボタン
sliderDuration速度切り替えバー
toolbarツールバー
Received Actions
changeDuration:速度切り替えバー(Value Changed)
changeOrder:モード変更ボタン(Value Changed)
startStop:Start/Stopボタン(Touch Up Inside)
Referencing Outlets
slideSlide App Delegate

408


●アクションメソッドの実装

Slide.mソースファイルにメソッドを実装します。
(太字が追加した部分)

#import "Slide.h"

@implementation Slide

- (NSArray *)animationImages {
    // 画像リソースの読み込み
    UIImage *img1 = [UIImage imageNamed:@"photo08.jpg"];
    UIImage *img2 = [UIImage imageNamed:@"photo09.jpg"];
    UIImage *img3 = [UIImage imageNamed:@"photo10.jpg"];
    UIImage *img4 = [UIImage imageNamed:@"photo11.jpg"];
    UIImage *img5 = [UIImage imageNamed:@"photo12.jpg"];
    UIImage *img6 = [UIImage imageNamed:@"photo13.jpg"];
    UIImage *img7 = [UIImage imageNamed:@"photo14.jpg"];

    // 画像順の配列の生成
    NSMutableArray *imgs = [NSMutableArray arrayWithObjects:img1, img2, img3, img4, img5, img6, img7, nil];

    // 表示順が画像順かシャッフルか判定
    if (segShuffle.selectedSegmentIndex ==1) {
        int i;
        // 配列の個数を取得
        int count = [imgs count];
        // 現在の日時で乱数のシード値を変更
        srand([[NSDate date] timeIntervalSinceReferenceDate]);

        for (i = 0; i < 10; i++) {
            // 乱数の生成
            NSUInteger pos1 = rand() % count;
            NSUInteger pos2 = rand() % count;
            // 要素の入れ替え
            [imgs exchangeObjectAtIndex:pos1 withObjectAtIndex:pos2];
        }
    }
    // 配列を返す
    return(imgs);
}

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

    // UIImageViewのアニメーション初期化

    // アニメーション画像の設定
    NSArray *imgArray = [self animationImages];
    imageSlide.animationImages = imgArray;

    // アニメーションの長さの設定
    imageSlide.animationDuration = sliderDuration.value;

    // アニメーションの回数の設定
    imageSlide.animationRepeatCount = 0;

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

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

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

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

- (IBAction)startStop:(id)sender {
    // アニメーションの再生状態を取得
    BOOL isAnimating = [imageSlide isAnimating];

    // アニメーション停止処理
    if (isAnimating == YES) {
        [imageSlide stopAnimating];
        [btnStartStop setTitle:@"Start" forState:UIControlStateNormal];
    }
    else {
        [imageSlide startAnimating];
        [btnStartStop setTitle:@"Stop" forState:UIControlStateNormal];
    }
}

- (IBAction)changeDuration:(id)sender {
    // 現在の再生状態を取得
    BOOL isAnimating = [imageSlide isAnimating];

    // スライダの値を取得し、アニメーションの長さを変更
    UISlider *slider = (UISlider *)sender;
    imageSlide.animationDuration = slider.value;

    // アニメーションを再開
    if (isAnimating == YES) {
        [imageSlide startAnimating];
    }
}

- (IBAction)changeOrder:(id)sender {
    // 現在の再生状態を取得
    BOOL isAnimating = [imageSlide isAnimating];

    // 画像の配列を変更
    imageSlide.animationImages = [self animationImages];

    // アニメーションを再開
    if (isAnimating == YES) {
        [imageSlide startAnimating];
    }
}


@end

410


●ビルドと実行

ビルドと実行を行うと下図のようになります。

411

スライドショーに使用する画像と別に背景画像を設定しているので、スライドショーが動いていない状態の時は背景画像が表示されます。

412

次回からアプリケーションの内容について掘り下げていきます。



参考文献

基礎からの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