2010年9月22日水曜日

Day6 Reaction Time(3)信号機画像を追加する

信号機ケーブル画像を追加する
画像をプログラミングで、表示したい位置に追加するために以下のように実装した。

UIImage* stopLightCableImage = [UIImage imageNamed:@"stopLightCable.png"];
UIImageView* stopLightCableView = [[UIImageView alloc] initWithImage:stopLightCableImage];
stopLightCableView.frame = CGRectMake(150, 0, stopLightCableImage.size.width, stopLightCableImage.size.height);
stopLightCableView.image = stopLightCableImage;
[self.view addSubview:stopLightCableView];

2行目
initWithImage メソッドで指定した画像で初期化する。

3行目
UIImageView の frame メソッドで表示位置を指定する。
→ bounds メソッドでは、stopLightCableView の、ローカルな座標の指定になるので間違い。frame メソッドで、親Viewから見た座標で位置を指定する。


4行目
image プロパティに画像を指定する。

信号機画像3種類をランダムに表示させるメソッドを実装する

以下の内容を訂正する。これではやりたかったことが実現できないので。。
訂正ここから-----------------------------------
以下のように実装した。
-(NSArray *)makeAnimationImagesArray{

NSMutableArray* trafficLightArray = [NSMutableArray arrayWithObjects:
[UIImage imageNamed:@"redLightSmall.png"],
[UIImage imageNamed:@"yellowLightSmall.png"],
[UIImage imageNamed:@"greenLightSmall.png"], nil];

int count = [trafficLightArray count];
srand([[NSDate date] timeIntervalSinceReferenceDate]);

int i = 0;
for(i=0; i<10; i++){
NSUInteger pos1 = rand() % count;
NSUInteger pos2 = rand() % count;

[trafficLightArray exchangeObjectAtIndex:pos1 withObjectAtIndex:pos2];
}

return(trafficLightArray);
}
9行目擬似乱数の発生系列を変更する種を、現在時刻から生成する。
10行目〜0〜2をランダムに生成する。訂正ここまで-----------------------------------


改めて、信号機画像3種類を表示させる
次のメソッドを使用して、現行ループにタイマーとスケジュールを作成する。
scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:
Creates and returns a new NSTimer object and schedules it on the current run loop in the default mode.
このメソッドで、3種類の画像(黄→赤→緑)を3秒おきに表示させる。
アクセルペダルをタップした時の動作を実装する事前にフラグを持たせておいて、緑色画像が表示されたらフラグをONにする。また、その時の時刻を取得しておく。
次のメソッドを使用して、緑色画像が表示された時刻と、現在時刻の差を取得する。
timeIntervalSinceNow
Returns the interval between the receiver and the current date and time.

結果をUIAlertView で画面に表示する。

frame と boundsとcenter の関係

ビューオブジェクトである、frame,bounds,center は以下のように定義されている。
frame(フレーム)プロパティは、親ビューの座標系に基づいて、そのビューの
位置とサイズを定義した矩形(フレーム矩形)を表します。
フレーム矩形は、boundsとcenterを使用して計算される便利な値です。これは、ビューの変換が、恒等変換に設定されている場合にのみ有効です。
bounds(境界)プロパティは、ビュー固有のローカルな座標系に基づいて、ビューの位置とサイズを定義した矩形(境界矩形)を表します。境界矩形の原点は、通常(0, 0)に設定されますが、必ずしもその必要はありません。
境界矩形は、そのビューのローカルな座標系を表すので、描画やイベント処理のコードの中で、何らかの変化がビュー内のどこで発生したかを知る必要があるときに、最もよく使います。
center(中心)プロパティは、フレーム矩形の中心点を表します。
中心点は、ビューの既知の中心点を表すので、ビューの位置を操作するのに最適な方法です。
----------------------------------------
frame と bounds の関係













参考PDF:
iPhone アプリケーションプログラミングガイド
Stanford University / CS 193P iPhone Apprication Development / Title: Lecture #5 - Views, Drawing, Animation

2010年9月17日金曜日

Day6 Reaction Time(2)view に背景画像を追加する

背景画像として、road.png をview に追加する。
road.png をResources フォルダに追加して、以下のように実装した。

- (void)viewDidLoad {
[super viewDidLoad];

UIImage* backgroundImage = [UIImage imageNamed:@"road.png"];
UIImageView* backgroundView = [[UIImageView alloc] initWithImage:backgroundImage];
[backgroundView setFrame:[[UIScreen mainScreen] bounds]];
[self.view addSubview:backgroundView];

[backgroundView release];
}

参考にしたのは以下の箇所。
How do I create a view for images?
To create a view for images, use the UIImageView class, as shown in Listing 14.

Listing 14: Creating a view for images
UIImage *image = [UIImage imageNamed:@"image.png"];
UIImageView *theImageView = [[UIImageView alloc] initWithImage:image];
さらに、UIImageView を setFrame メソッドで画面全体に表示させて、view に追加している。

参考サイト:

User Experiense Coding How-To's

Day6 Reaction Time(1)画面構成

Reaction Time アプリの内容はこんな感じか。

アプリの内容
画面中央に表示されている信号が青に変わったら、右下にあるアクセルペダル画像をタップすると、何ミリ秒で反応したかが表示される。
---------------------------------------
画像の配置
使用されている画像は次の4つ。
1.
道路(road.png)
背景画像として、view に追加する。

2-1.
信号機(redLightSmall.png、yellowLightSmall.png、greenLightSmall.png)
3つの画像をランダムに表示させている。

2-2.
信号機を上部から支えている線(stopLightCable.png)
細部も抜かりありませんね。

3.
アクセルペダル(gasPedalSmall.png)
コレをタップすると、信号が青に変わってからタップされるまでの経過時間が画面に表示される。
---------------------------------------
Alert メッセージの表示
次の状態の時、Alert メッセージを表示する。
1.
アプリを起動させた直後
操作方法を説明する。

2.
信号が青に変わってからペダルをタップした時
信号が青に変わってからタップされるまでの経過時間を表示する。

3.
信号が赤、または黄色でペダルをタップした時
「青信号でタップしろ」と警告する。

2010年9月16日木曜日

Day5 Count Me In

アプリの内容:
「+」ボタンと「ー」ボタン、数字が表示されたラベルが用意されている。
1回押すごとにラベルに表示された数字がインクリメント/デクリメントする。

実装:
View にUIButton とUILabel を追加する。
UILabel に表示する数字をインクリメント/デクリメントするメソッドを実装する。

ボタンアクション:
addTarget:action:forControlEvents: で、アクションとターゲットを追加する。
addTarget:action:forControlEvents:
Adds a target and action for a particular event (or events) to an internal dispatch table.

Control Events には、様々なイベントが用意されている。
今回の「ボタンを押す」アクションは、「UIControlEventTouchUpInside」を選択する。
UIControlEventTouchUpInside
A touch-up event in the control where the finger is inside the bounds of the control.

最初、特に理由もなく「UIControlEventAllEvents」を選択していたら、なぜかアクションに指定したメソッドが2回呼ばれてしまった。レファレンスを読むと、
UIControlEventAllEvents
All events, including system events.

と、あるのでシステムイベントでも呼ばれていたのだと思う。適当に選択するのはやめろ。

UILabel に表示する数字をインクリメント/デクリメントするメソッド:

以下のように実装した。

-(void)addUnit{
NSString* numValue = [[NSString alloc] initWithFormat:@"%d", ++count];

contLabel.text = numValue;
[numValue release];
}

-(void)subtractUnit{
if(count <= 0) return;
NSString* numValue = [[NSString alloc] initWithFormat:@"%d", --count];

contLabel.text = numValue;
[numValue release];
}
チュートリアルでは、インクリメント/デクリメント演算子が後置されていたが、それではボタンを1回押しただけでは目的が達成されないので前値に直した。
インクリメントC言語、C++、Java、JavaScriptなどでは、インクリメント演算子「++」が用意されている。厳密には、前置インクリメントと後置インクリメントの2種類の演算子があり、演算子記号は同じ「++」だがオペランドの前に置くか(例: ++x)後に置くか(例: x++)で区別される。前置インクリメントは式の評価の最初にオペランドがインクリメントされ、後置インクリメントは最後にインクリメントされる。
参考サイト:UIControl Class Refarence 、インクリメント

2010年9月14日火曜日

Xcodeデバッグする時に便利なショートカット

デバッグ開始
⌘ + option + return

デバッグ終了
⌘ + Shift + return

デバッグからプロジェクトへの切り替え
⌘ + 0

//挿入
⌘ + /

ブレークポイント挿入/削除

⌘ \

2010年9月10日金曜日

Day 3 OpenURL openMaps: カスタマイズ(2)キーボードを表示/非表示にする

以下のことを実装したい。
-------------------------
1.
テキストフィールドをタップしたときにキーボードを表示し、ユーザーがキーボードの「Done」ボタンをタップしたときにキーボードを非表示にする。
2.
テキストフィールドの下にある「openMaps」ボタンをタップすると、googleMapsが開き、テキストフィールドに入力した場所の地図が表示される。
-------------------------

UITextFieldDelegateプロトコルには、ユーザが「Return」ボタンをタップしたときにテキストフィールドを呼び出す(ボタンに表示されるテキストがどのようなものであっても)、textFieldShouldReturn:メソッドが含まれています。

textFieldShouldReturn:
Asks the delegate if the text field should process the pressing of the return button.

View Controllerはテキストフィールドのデリゲートとして設定したため、このメソッドを実装して、resignFirstResponderメッセージを送信する(キーボードを閉じる効果を持つ)ことによって、テキストフィールドからファーストレスポンダステータスを強制的になくすことができます。

resignFirstResponder
Notifies the receiver that it has been asked to relinquish its status as first responder in its window.

これを元に実装したソースは以下の通り。
-(BOOL)textFieldShouldReturn:(UITextField *)tf{

[tf resignFirstResponder];

return YES;
}

テキストフィールドに入力された文字を openMaps: メソッドに渡し、openURL でgoogleMapsを実行する処理は以下のように実装した。

-(void)openMaps:(id)sender {

self.addString = txtField.text;
NSString* addressText =self.addString;

addressText = [addressText stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
NSString* urlText = [NSString stringWithFormat:@"http://maps.google.com/maps?q=%@",addressText];

[[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlText]];

[addString release];

}
シミュレーターには日本語キーボードがないようなので、日本語入力を試すことが出来なかった。

参考PDF:
iPhone アプリケーション チュートリアル

Day 3 OpenURL openMaps: カスタマイズ(1)住所を直接入力する

ボタンをタップして決めうちの住所をgoogleMapsで表示するのではなく、テキストフィールドを実装してキーボードから住所を入力できるようにカスタマイズする。

UIKitフレームワークには、テキストコンテンツを表示するために、次の3つの主要なクラスがあります。
■ UILabel:静的なテキスト文字列を表示する
■ UITextField:編集可能な単一行のテキストを表示する
■ UITextView:編集可能な複数行のテキストを表示する

住所は1行程度の入力になると想定して、UITextFieldクラスを利用する。

編集可能なText Viewで作業をする場合は、常に、編集セッションを管理するデリゲートオブジェクトを提供する必要があります。
View Controllerは、それ自体がこのテキストフィールドのデリゲートになるため、UITextFieldDelegateプロトコルを採用しなければなりません。クラスがプロトコルを採用することを指定するには、インターフェイスで、そのクラスの継承元のクラスの名前の後に、角括弧(<>)で囲んでプロトコル名を追加します。

TextField を実装するソースコードは以下のようにした。

インターフェイスで、デリゲートを設定する。
RootViewController.h
#import <UIKit/UIKit.h>

@interface RootViewController : UIViewController <UITextFieldDelegate> {
UIView *view;
UITextField *txtField;
}
@end

TextField の実装は、loadView メソッドで行う。
デフォルトの画面 UIView に、テキストフィールドのビュー UITxetField を追加する。

RootViewController.m

-(void)loadView{

view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
view.backgroundColor = [UIColor grayColor];
self.view = view;

txtField = [[UITextField alloc] initWithFrame:CGRectMake(63, 56, 200, 30)];
txtField.borderStyle = 3;
txtField.placeholder = @"Enter Adress";
[self.view addSubview: txtField];
txtField.delegate = self;
txtField.returnKeyType = UIReturnKeyDone;

[txtField release];
[view release];

}

参考PDF:iPhone アプリケーションプログラミングガイド
iPhone アプリケーション チュートリアル

2010年9月7日火曜日

Day 3 OpenURL openMaps: メソッド詳細(2)

元の実装では、決め打ちで住所を指定していた(米国appleの住所、アルファベットと数字)。コレを日本語で指定したい(日本apple本社の住所)場合はstringWithCString:encoding: メソッドを使用する。
stringWithCString:encoding:
Returns a string containing the bytes in a given C array, interpreted according to a given encoding.

C言語の文字列からNSStringを返すメソッド。文字列は「" "」で囲む。エンコーディングの引数は「NSUTF8StringEncoding」を指定する。
日本語住所を指定する場合のソースは以下のようになる。
-(void)openMaps:(id)sender{
NSString* addressText =[NSString stringWithCString:"東京都新宿区西新宿3-20-2" encoding:NSUTF8StringEncoding];

addressText = [addressText stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

NSString* urlText = [NSString stringWithFormat:@"http://maps.google.com/maps?q=%@",addressText];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlText]];
}

Day 3 OpenURL openMaps: メソッド詳細(1)

openMaps ボダンをクリックすると実行される処理の内容を説明する。

ソースコードは以下の通り。

-(void)openMaps:(id)sender{
NSString* addressText = @"1 Infinite Loop, Cupertino, CA 95014";

addressText = [addressText stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];

NSString* urlText = [NSString stringWithFormat:@"http://maps.google.com/maps?q=%@",addressText];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlText]];
}

4行目
決め打ちの住所(米国appleの住所)をstringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding メソッドでエンコードする。
6行目
stringWithFormat メソッドで、文字列(googleMap検索のURL)を作る。
7行目
URLWithString メソッドで、NSURLを作成する。そのNSURL を利用してgoogleMapでその住所を表示する。

6行目補足
作成する文字列は、googleMapで検索した結果を表示するURL

7行目補足
sharedApplicationメソッドでインスタンスを取得して、openURL メソッドでアプリケーション(googleMaps)にアクセスする。

2010年9月6日月曜日

Day 3 OpenURL ローカル環境で実行してみる

アプリを実行してみると以下の5つのボタンが並んでいる。
 Open phone URL
 Open SMS URL
 Open E-mail URL
 Open Map URL
 Open Browser URL

ソースコードを見ると、ボタンをタップして実行されるコードを書いているのは「Open Map URL」だけなのでそこだけ実装してみる。
ここで使われているのはカスタムURLと言われるもの。iPhoneAppProgramingGuide.pdf より引用。
アプリケーションが既知の型のURLを扱う場合は、そのURLスキームを使用してそのアプリケーションとやり取りができます。
使うメソッドは、openURL:メソッド。
詳細は以降。

参考PDF:iPhone アプリケーションプログラミングガイド 他のアプリケーションとのやり取り

2010年9月3日金曜日

定義へジャンプ

定義へジャンプするショートカット

⌘ + ダブルクリック

*.hファイルと*.mファイルの切り替え

*.hファイルと*.mファイルの切り替えを行うショートカット

⌘ + option +↑

2010年9月1日水曜日

Day 2 画像をアニメーション表示させる

UIImageViewクラスを利用して画像をアニメーション表示させる。
viewDidLoadに以下で実装した処理を追加する。
実装手順は以下の通り。

1.
animationImagesプロパティに、アニメーションで使われる画像を格納した配列を指定する。最後に nil を入れるのを忘れない。

2.
アニメーションの設定を下記のプロパティで指定する。
animationDurationプロパティで、アニメーションの時間を指定する。
animationRepeatCountプロパティで、アニメーションを繰り返す回数を指定する。

3.
startAnimatingメソッドで、アニメーションを開始する。

4.
現在のviewにUIImageViewを追加する。

Navigation Controller

Navigation Controllerは、階層的に構成されたデータを表示するために使用するコンテナView Controllerです。
このクラスのメソッドは、カスタムView Controllerのコレクションをスタックベースで管理する機能をサポートしています。このスタックは、階層的なデータの中をユーザが通った経路を反映します。スタックの一番下は出発点を表し、スタックの一番上はデータ内のユーザの現在位置を表します。
Navigation ControllerはNavigation Barを1つ管理します。Navigation Barには、データ階層内のユーザの現在位置についての情報、前の画面に戻るためのボタン、および現在のView Controllerで必要なカスタムコントロールが表示されます。また、現在の画面に関連するコマンドを表示するために使うオプションツールバーの管理も行います。

Day 2 modalビューを表示させる

modalビューを表示させるために、mainviewの右下隅にあるinfoボタンを実装する。
参考にしたのは参照PDFの「モーダルモードでのNavigationControllerの表示」。

-(void)showInfo:(id)sender{

RootViewController *rootView = [[RootViewController alloc] init];
FlipsideViewController *modalview = [[FlipsideViewController alloc] init];
modalview.delegate = self;
modalview.view.backgroundColor = [UIColor greenColor];

UINavigationController *naviModalController = [[UINavigationController alloc] initWithRootViewController:rootView];

modalview.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[naviModalController pushViewController:modalview animated:NO];
[self presentModalViewController:naviModalController animated:YES];

[rootView release];
[modalview release];
[naviModalController release];

}

5行目
delegateプロパティを設定して、modalを閉じるメソッドをデリゲーションするときに使用する。

参考PDF:iPhone OS View Controller プログラミングガイド

イメージファイルの追加

xcodeのプロジェクトにイメージファイルを追加する方法。

1.
(プロジェクト名)フォルダ - Resourcesフォルダ下にimagesフォルダを追加する。
2.
imagesフォルダに既存ファイルとして、イメージファイルを追加する。