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 アプリケーション チュートリアル