Archive for the ‘Dev’ Category

メニューとボタン

2011年7月2日

ゴルフのスコアカウンターにメニューボタンと戻るボタンの処理を追加して、少し使いやすくしてみる。戻るボタンのデフォルトの処理では、アプリを終了させてしまうので、データが消えてしまう。プレー中にデータが消えてしまうと大変なので、戻るボタンを押すとワーニングを表示するようにする。そうなるとアプリを終了させる方法がなくなるので、メニューからCloseを選択して終了できるようにする。また、スコアデータをクリアするメニューも追加する。

ソース

■ボタンのイベントハンドラ

戻るボタンを押すとワーニングが表示

戻るボタンを押すとワーニングが表示

ActivityのonKeyDownをOverrideする。keyCodeを見てどのボタンが押されたか判定。trueを返すと、後続のイベント処理は行われなくなる。

   @Override
   public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
	    	// Show dialog, if YES, close this application.
	    	m_alertdlg_close.show();
        	return true;
        }
        return false;
    }

ワーニングのダイアログ(m_alertdlg_close)は onCreate の中で作成

        //Alert dialog for Closing Application
    	builder.setMessage("If closed, data will be cleared. If you just hide this window, press HOME key. Are you sure you close this application? ")
    	       .setCancelable(false)
    	       .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
    	           public void onClick(DialogInterface dialog, int id) {
    	        	   finish();
    	           }
    	       })
    	       .setNegativeButton("No", new DialogInterface.OnClickListener() {
    	           public void onClick(DialogInterface dialog, int id) {
    	                dialog.cancel();
    	           }
    	       });
    	m_alertdlg_close = builder.create();

■メニューの実装

メニューボタンを押すとメニューが表示

メニューボタンを押すとメニューが表示

実装方法は、開発者サイトの Dev Guide > User Interface > Creating Menus に書いてある通り。丁寧に書いてあるので、すぐに実装できた。

http://developer.android.com/guide/topics/ui/menus.html

アプリでSMSを受信したい

2011年6月11日

携帯へ何かを通知したい場合、日本のようにi-modeメールでプッシュ配信できない海外では、SMSを使うのが主流。サーバーからアプリに何かの情報を配信する場合も、この仕組みをつかうのが一番簡単だと思う。

★AndroidのSMSに関する資料

上に紹介したAPI Demoをビルドして検証しようとしたところ、なぜかSMSのデモがメニューからなくなっていた。調べてみると、自分のAndroid(Experia X10 mini: Android version 2.1 update)にあわせて設定したビルドターゲット、つまりAPI Level 7(=Version2.1 update)のAPI DemoにはSMS関連のソースが無かった(Level8と9にはある)。ビルドターゲットをAPI Level8 でAPI Demoのプロジェクトを作り直しすと、SMS関連のデモも動いた。

エミュレータにSMSを送るには、Eclipseで[Window]-[Open Perspective]-[DDMS]を開き、Emulator Controlから送信。

SMSを受信すると、メッセージを表示するウィンドウが現れ、さらにメッセージを読み上げる。SMSを受信する設定になっている間は、API Demo の画面を閉じても、SMSを受信するとメッセージを表示するウィンドウは現れる。

しかしSDKのリファレンスによると、SMS関連のクラスはAPI Level7でも使えるはずだ。API Level 8のAPI DemoのソースからSMS関連のソースをコピーしてビルドターゲットをAPI Level 7にしてビルドしてみた。

新規プロジェクトを作成し、SmsMessageReceiver.java と SmsReceivedDialog.java はそのままコピーしてPackage名だけを変更。プロジェクトのActivityクラスには、SmsMessageDemo.java の中身をそっくりコピー。res/values/strings.xml には、関連する文字列をコピー。res/layout/sms_demo.xml はそのままコピーしただけではビルドできなかったが、プロパティ layout_widthとlayout_heightの値 “match_parent” を “fill_parent” に置き換えてビルドできた。

・・・で、動かしてみるが、SMSを送っても反応しない。SmsMessageReceiver にブレークポイントを張って動かしてみたが、最初から最後まで止まらない。よくソースを見返してみると、SmsMessageReceiver を BroadcastReceiverとして追加するコードがない・・・。API Demo の元のソースをみてもない。しかし、上で紹介した http://www.androidcompetencycenter.com の記事を見て、Manufest.xmlで Receiver として設定する必要があることがわかった。API Demo の元のソースにもあったので、そこからコピー。さらに、元の Manufest.xml には SMSの機能に関する uses-permission も設定されていたので、それもコピー。これで SMS に反応するようになった。

しかし、SMS を受信してすぐに落ちてしまう・・・。ログを見ると、権限が足りなくてExceptionが発生している。SMS 関連の uses-permission は全てつけたはずだが・・・?デバッガで見てみると、SMS を受信した後で、電話帳から発信元番号の主を検索する処理が入っていて、ここで落ちていた。なるほど!電話帳のアクセス件が必要だったわけだ。確かに元の Manufest.xml にはあったので、それをコピーして追加。これで正常に動くようになった。SMS の受信だけでなく、電話帳の検索方法まで紹介してくれていた。なんて親切なサンプルコードなんだ!(>_<)

ちなみにiPhoneでは、SMSの送信はできるが受信はできないらしい。アプリにプッシュ式で通知する仕組みとしては、Local and Push Notification というのがあるようだが、ハードルが高そうなので、今は止めておく。

★iPhoneのSMSとLocal and Push Notification に関する資料

ゴルフのスコアカウンター(iPhone版)

2011年5月28日

ゴルフのスコアカウンターのiPhone版。

ソース

●画面のレイアウト

layout

レイアウト

Window baseアプリケーションとして作成。図のように配置した。PARの値を選択するのにドロップダウンリストを使いたかったが、ドロップダウンリストがなかった。仕方なくSegmented controlを使用した。

●クラス構成

xibファイルのFileOwnerはAppDelegateなので、イベントハンドラはここに書くこともできたが、今回はあえてGUIイベントハンドラとして、Controllerという名前のNSObjectの派生クラスを作成した。同時にxibファイルにもObjectを追加し、Custom Class にControllerクラスを設定して連携させ、AppDelegateにOutletとして追加することでインスタンス化する。(一方、Viewを使った場合はView毎にxibファイルを作成するので、UIViewControllerの派生クラスはxibファイルのFileOwnerに指定する。よって、ControllerのObjectを別途xibに追加しなくてよい。アプリ初期化時にinitWithNibNameにxibファイル名を指定して呼び出すことで、xibを読み込んでインスタンス化する。)

●データの初期化

スコアのデータは2次元配列に保持する。Controllerを分けたので、モデルも別にしようかとは思ったが、面倒なのでControllerに持たせた。パーの値は4を初期値として設定する。この初期化処理は、AppDelegateのdidFinishLaunchingWithOptionsから呼び出す。

●イベント処理

前述のControllerクラスに各ボタンが操作された際のActionを定義し、xibで各ボタンのイベントと関連づける。

●課題

ドロップダウンリストの実装方法・・・。リストから選択させるときは何を使うのか?iPhoneを持っていないのでよくわからないが、買うと高いし・・・。サンプルなどをよく調べる必要がある。

ゴルフのスコアカウンター(Android版)

2011年4月30日

ゴルフのスコアをカウントするための、簡単なアプリを作成した。(私のようにダブルパー以上を普通に叩く人は、打数を数えるのが大変なので、こんなのが必要!)各ホールの打数を記録するとともに、トータルスコアとPAR数を引いたオーバーの値も出すようにする。

ソース

●画面のレイアウト

layout.xml

レイアウト

一番底がLinearLayoutで、上からホール数表示エリア、PAR表示エリア、スコア表示エリア、トータルスコア表示エリアとした。
ホール数表示エリア内をRelativeLayoutにしてホール数を増減するボタンを両端に、ホール数表示のラベル(TextView)を真ん中に配置した。
PAR表示エリアは、PAR数を選択するSpinnerのみ。
スコア表示エリアは、これもRelativeLayoutにしてスコアを増減するボタンを両端に、真ん中をさらにLinearLayoutにして上にこのホールのスコア、下にPARを引いた値を表示。
トータルスコア表示エリアはラベル(TextView)のみである。

●クラス構成

Activity の派生クラスのGolfscntという名前のクラスのみ。このクラスのonCreateメソッド内で、各コントロールのイベントハンドラを一時クラスとして実装している。

●課題

PARを選択するspinnerの字を他のにあわせて大きくしたいのだが、textSizeを変えても大きくならなかった。

課題という訳ではないが、実際に使ってみたとことろ・・・明るい野外では液晶が見にくくて、結局ほとんど使えなかった。残念・・・orz

ダウンロードはこちら

Cocoa Application Tutorial の Converterアプリを iPhone に移植

2011年4月9日

Cocoa Application Tutorial (下)の Converterアプリを iPhone に移植してみた。

CocoaTutrial

CocoaTutrial

プロジェクトの選択

NewProjectWindowBased

NewProjectWindowBased

プロジェクトの新規作成では Window-based Application を選択。
このあとは、Cocoa Application Tutorial の指示通りにすすめればOK。(ただし、コントロールのクラス名はNSTextField → UITextField という要領で置き換える。)

変更すべき点

しかし、Controllerの定義と実装には、NSTextField と UITextField の違いにより若干変更が必要。

【ConverterController.h】
★NSTextField を UITextField に置き換える。

@interface ConverterController : NSObject {
	IBOutlet UITextField *amountField;
	IBOutlet UITextField *dollarField;
	IBOutlet UITextField *rateField;
	Converter *converter;
}
- (IBAction)convert:(id)sender;
@end

【ConverterController.m】
★NSTextField にはあるが UITextField にはないメソッドを書き換える。

@implementation ConverterController
- (IBAction)convert:(id)sender {
    float amount;
    converter = [[Converter alloc]init]; 

//    [converter setSourceCurrencyAmount:[dollarField floatValue]];
// UITextField には floatValue がない
    [converter setSourceCurrencyAmount: [dollarField.text floatValue]]; 	

//    [converter setRate:[rateField floatValue]];
// UITextField には floatValue がない
    [converter setRate: [rateField.text floatValue]]; 	

    amount =   [converter convertCurrency];

//    [amountField setFloatValue:amount];
// UITextField には floatValue がない
    [amountField setText: [[NSNumber numberWithFloat: amount] stringValue]]; 

//    [rateField selectText:self];
// UITextField には selectText がない。
// 書き換えができなかったので、保留。

// iOS にはガベージコレクタがないので、リリースする必要がある。
	[converter release];
}
@end


また、数値の入力フィールドについては、キーボードを Number&Punctuation に設定した方が便利。


シミュレーターでの実行結果

iPhoneSDKのサンプルMoveMeをAndroidに移植

2011年3月6日

iPhoneSDKのサンプルMoveMeをAndroidに移植してみた。ソースはこちら

左がオリジナル(iPhone版)、右が移植したもの。

(ならべて見ると・・・大きさが違い過ぎだが・・・気にしない・・・ )

MoveMeというプログラムは、次のような簡単なプログラムである。

  • 最初に画面中央にメッセージ(短い挨拶文)が書かれたボタンが表示される。
  • ボタンをタッチすると少し膨らみ、ボタンの中心はタッチされた位置に移動する。
  • ボタンはドラッグして移動され、指を離すと中央に戻る。中央に戻ったとき、勢いでボタンがはねるような動きをする。
  • ボタン以外の部分をダブルクリックすると、メッセージの言語が変わる。

Viewの構成

iPhone版ではメインの親であるMoveMeView上のタッチされた位置に、子であるPlacardView(ボタン)を表示する。PlacardViewは親画面内の座標で位置指定される。Androidで小画面(コントロールも含む)の位置指定はLayoutManagerに依存する。LayoutManagerもViewを継承するので、これが親画面といえる。座標で位置指定するにはLayoutManagerとしてAbsoluteLayoutを使用する必要があるが、実はこのAbsoluteLayoutの使用は推奨されていない。これはAndroid(だけでなく一般的なJavaプログラムにもいえることだが)ではデバイスにより画面サイズが異なるため、位置を座標で指定すると画面からはみ出たり、逆に小さ過ぎたりする可能性があるため。一般にLayoutManagerは親画面に対する小画面の相対位置を指定し、デバイスの画面サイズにあわせて、小画面やコントロールを自動的に最適な場所に配置する。ただしこのプログラムでは、小画面は画面のタッチで位置指定されるので、画面サイズの影響を気にする必要はなく、AbsoluteLayoutでも問題なかった。

クラスの構成

iPhone版で定義されたClassと、Android版のClassの対応は以下のようになった。

  • MoveMeAppDelegate → なし(Delegateの仕組みがない)
  • MoveMeView(メインの画面) → MoveMe内で使用されるAbsoluteLayoutクラス。
  • PlacardView(ボタン) → PlacardView

Animationの使用

ボタンを最初にクリックした際にボタンがふくらむ動作と、ドラッグされたボタンから指を離すと中心に戻り、反動で少し揺れる動作はアニメーションを使用した。SDKのサンプルではXMLファイルで定義するアニメーションの例が多いが、今回はアニメーションの位置が動的に変わるため、XMLだけでなく、プログラムによる定義も使用した。

↓↓↓Animation定義のコード↓↓↓

	//animate moving to center
	final long DURATION_ANIM1 = 300;
	TranslateAnimation move_center = new TranslateAnimation(
			TranslateAnimation.ABSOLUTE, x - mCenter.x,
			TranslateAnimation.RELATIVE_TO_SELF, 0,
			TranslateAnimation.ABSOLUTE, y - mCenter.y,
			TranslateAnimation.RELATIVE_TO_SELF, 0);
	move_center.setDuration(DURATION_ANIM1);
	move_center.setStartTime(Animation.START_ON_FIRST_FRAME);
	move_center.setInterpolator(new LinearInterpolator());
	//animate bouncing
	TranslateAnimation bounce = new TranslateAnimation(
			(float)0,
			(float)(mCenter.x - (mPtEnd.x + WIDTH/2))/20,
			(float)0,
			(float)(mCenter.y - (mPtEnd.y + HEIGHT/2))/20);
	bounce.setDuration(200);
	bounce.setStartTime(Animation.START_ON_FIRST_FRAME);
	bounce.setStartOffset(DURATION_ANIM1);
	bounce.setInterpolator(new CycleInterpolator((float) 2.75));
	//AnimationSet consist of above two animation
	AnimationSet go_center_bounce = new AnimationSet(false);
	go_center_bounce.addAnimation(move_center);
	go_center_bounce.addAnimation(bounce);
	this.setAnimation(go_center_bounce);
	go_center_bounce.startNow();

イベントハンドラ

iPhone版では親画面であるMoveMeViewにイベントハンドラが定義されているが、Android版では、親画面となるAbsoluteLayoutにListenerを追加し、そのListener内にイベントハンドラを定義することになる。1つよくわからないのが、ダブルクリックの判定方法で、今回は前回クリックされてから何ms以内に次のクリックがあればダブルクリックと判定している。あまりスマートでない感じがするので、もっといい判定方法を調べなければ。

AbsoluteLayoutによるボタンの位置指定

AbsoluteLayoutのLayoutParamsが位置の属性を持つ。ということは、このLayoutParamsの参照を保持しておき、属性を変更することで位置を変更できるかと思いきや、位置を指定するたびにAbsoluteLayoutのsetLayoutParams()を呼び出す必要があった。

まとめ

今回のサンプルは非常に簡単だったので、アニメーションの使用を除けば、一般的なJavaプログラムとそれほど変わらず、Androidだからということで特別に意識するところはなかった。Javaが使えるので、iPhoneよりは敷居が低そうだ。

Android SDK のHello, World! ・・・あれ?動かない・・・

2011年1月29日

Android SDKのTutrialを試してみた。

http://developer.android.com/resources/tutorials/hello-world.html

指示通りにプロジェクトを作成し、ソースを編集して、実行。

“Hello, World!”って文字を表示するだけだから、まず大丈夫だと思っていたら・・・

あれ?? 動かない・・・と思っていたら

画面が変わった! やっと起動したらしい。でも”Hello,World!”は?

焦っていろいろボタンを押してみると

“MENU” ボタンで出てきた!