View のレイアウト (ViewGroup)

 複数のView を重ねたい、ひとつのグループとして扱いたい。
 そんなときに使うのが、ViewGroup だね。

 ViewGroup は、View を子として内包し、親子関係を作り出せるんだ。
 代表的なところでListView なんかが、これを基礎に作られたりする。
 いってみれば、Android の土台といったところかね。
 また、ViewGroup はView の派生なので、他のViewGroup に含ませることもできるよ。

Layout シリーズ

 ViewGroup には、View を画面にレイアウトするためのclass がいくつかある。
 Layout class というものはないようなんで、オイラはそれらを勝手に、Layout シリーズと呼んでいるよ。

 具体的な使い方は他の方に任せるとして。
 ここでは特徴や違いなんかをまとめてみることにする。

LinearLayout

 子View を縦並び、あるいは横並びにレイアウトする。
 セル画やフォトショップのレイヤーみたいに、重ね合わせることはできない。
 setGravity で左端合わせ、センター合わせなんかの設定ができる。
http://developer.android.com/reference/android/widget/LinearLayout.html

TableLayout

 子View を、行や列で、格子上にレイアウトする。
 setGravity で左端合わせ、センター合わせなんかの設定ができる。
http://developer.android.com/reference/android/widget/TableLayout.html

RelativeLayout

 子View を重ね合わせてレイアウトする。
 セル画やフォトショップのレイヤーみたいな感じ。
 setGravity で左端合わせ、センター合わせなんかの設定ができる。
 レイアウト位置は座標ではなく、addRuleを使って、相関関係で設定するらしい。
 抽象的に例えて、3つのViewがあるとすると…
 View01があって。View02はその右隣。View03はその下。
 …といった具合。
 位置はそれぞれのViewの大きさが関係するので、表示イメージをなにかに下書きしないと苦労しそう。
 ※.設定しなければ、単純に重ね合わせされる。
http://developer.android.com/reference/android/widget/RelativeLayout.html

FrameLayout

 子View をひとつだけ登録できる。
 別のView を加えると置き換えらてしまう…

 って、解説を見たんだけど、やってみると、RelativeLayout のように重ね合わせされちゃうんだよね。(^_^;
 ただし他のLayout と違い、setGravity はなくて、代わりにsetForegroundGravity がある。
 setGravity のようにセンターを指定しても、そのとおりに配置されなくて、その効力未確認…。
 それに気づくまで、RelativeLayout のつもりで使ってたよ。(笑
 FrameLayout は、単純に左上合わせで重ねるだけのレイアウトなのかもしれないね。
http://developer.android.com/reference/android/widget/FrameLayout.html

 Layout に限らず、Andorid での位置指定は、なんかHTML的だね。
 どうも個人的に使い勝手がイマイチ。
 画面座標の指定があってもいいと思うのだけどね…。

レイアウトの注意

 setGravity を設定しているのに、なんか効いてないなぁと思ったら…。
 どうも、ViewGroup の中に FILL_PARENT設定がいると無効になるみたい。
 CENTER などはWRAP_CONTENT 用のものらしく、そのせいのようだ。

Posted in View, レイアウト. Tags: , , , , , . View のレイアウト (ViewGroup) はコメントを受け付けていません »

ボタンの外観を変える

 ボタンの外観を変えるには、xmlで設定し、それをsetBackgroundResource() method で適用することになる。
 ※.「xmlナシ」については→XMLなしで、ボタンの外観を変える

setBackgroundResource

 引数に、設定xmlを指定するだけ。
 たとえばこんな感じ。

	but.setBackgroundResource( R.drawable.button_style );

 ※.xmlファイル名は任意

XMLの設定

 ただ単に外観を変えるだけなら、xmlの設定は必要ない。
 setBackgroundDrawable()やsetBackgroundResource() を使えばいい。
 設定xmlが必要になるのは、状態によって変化させたいとき。
 たとえば、ボタンにフォーカスが当たった、ボタンを選択された。
 これらの「状態」と、その時の「色・画像」を設定したものが、設定内容となる。

 単純に選択/非選択だけの設定ならこんな感じになる。

<?xml version="1.0" encoding="utf-8" ?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

	<item android:state_focused="true">
		<color android:color="#ff00ff00" />
	</item>
	<item>
		<color android:color="#ff0000ff" />
	</item>

</selector>

 全てを設定すると、こんな感じ。

<?xml version="1.0" encoding="utf-8" ?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
	<item android:state_enabled="false" >
		<color android:color="#00ffffff" />
	</item>
	
	<item android:state_pressed="true" >
		<color android:color="#80ff0000" />
	</item>
	<item android:state_focused="true">
		<color android:color="#8000ff00" />
	</item>
	<item>
		<color android:color="#800000ff" />
	</item>
</selector>

 上から順に…

  • 選択できない(非活性) … 透明(白)
  • 押された瞬間 … 赤(半透明)
  • 選択された … 緑(半透明)
  • 選択されていない(通常) … 青(半透明)

 実行すると、「clickしたのに、緑色になる…」なんて風に思うかもしれない。
 でもよく見てほしい。
 clickした瞬間は赤になるハズだ。
 どうもstate_pressed は、clickした瞬間を表しているらしい。
 決定状態を作るには、リスナーのonClickでやる以外はなさそうだ。

設定は優先順位順で、itemタグのパラメータは状態を現す

 プログラム言語に読み替えると、こんな感じになる。

	if ( state_enabled == false ){
		color="#00ffffff";
	}
	else if ( state_pressed == true ){
		color="#80ff0000";
	}
	else if ( state_focused == true ){
		color="#8000ff00";
	}else{
		color="#800000ff";
	}

 なので、表記の順番には気をつけなくてはいけない。

 また、パラメータは複数つけることもできる。
 たとえば

	<item android:state_enabled="true"
		 android:state_pressed="true"
		 >
		<color android:color="#80ff0000" />
	</item>

 選択できる状態で、押された … 半透明・赤
 といった感じ。

by the way…

 色の指定には、他のxml から引用することもできる。

	<color android:color="@color/blue_t" />

 color.xml の中に記述されている、blue_t の値
 といった感じだね。
 仮設定や、色の名前でつけたい、色を統一したい、なんていうときに便利だね。

 色ではなく画像を指定したい、という場合は…
 すまないけど、他の方の解説を見てほしい。(^_^;

Posted in ボタン. Tags: , . ボタンの外観を変える はコメントを受け付けていません »

XMLなしで、ボタンの外観を変える

 ボタンの外観を変えるには、

void setBackgroundColor(int color)
void setBackgroundDrawable(Drawable d)
void setBackgroundResource(int resid)


 なんかを使う。
 ただし、これらで画像や色を指定をした場合、カーソル表示や決定の反応なんかはなくなってしまう。
 それは寂しいし、第一、なにを選択しているのかわからず、ユーザーライクではない…。
 それじゃ、どうするかっていうと、xml指定することになる。

 でも、動的に変えたい場合もあるよね?
 たとえば、ユーザーに色変更させたい、Webからダウンロードしたものにしたい、etc…。
 そんなときはどうするか?
 結論からいうと、Button class をベースに新規class を作るのが早道みたいだ。
 でも一応、調べてみたことを書いておくよ。
 それと、サンプルのソースも。

外観設定の仕組み(xml)

 おおざっぱにいうと、仕組みはこんな感じみたい。

	button.xml (ファイル名任意)
	android:background
		↑
		style.xml (ファイル名任意)
		<item
			android:state_focused="true"
			android:color="@color/color1" />
		<item
			android:state_pressed="true"
			android:state_enabled="false"
			android:color="@color/color2" />
		……

 で、android:background に相当するmethod が、先のsetBackgroundになる。
 focuse やpress を設定するmethod はない。
 それじゃ、style.xml に相当するものを用意し、設定すればよいのだろうか…?

StateListDrawable

 StateListDrawable については、実は確かめてない。
 だからこの項目は、推測のものになるので、読みとばしてくれていいよ。(^_^;

 ざっと見のリファレンスからすると、StateListDrawableは、xmlみたいな設定を作成・編集するものみたいだ。
 DrawableContainer の継承で、大元はDrawable だから、Drawable指定の引数に使用できるハズ。
 きっと、setBackgroundDrawable(Drawable d) に渡せば、xml指定と同じことができると思う。

 StateListDrawable にあるmethod の…

void	 addState(int[] stateSet, Drawable drawable)
	Add a new image/string ID to the set of images.

 の第一引数・stateSet はおそらく、Button 内で定義されている↓なんかだろう。

(Button)
int[]	ENABLED_FOCUSED_SELECTED_STATE_SET	Indicates the view is enabled, focused and selected.

 おそらく、↓みたいな指定をすればいいのかな?

stateListDrawable.addState( 
	Button.ENABLED_FOCUSED_SELECTED_STATE_SET,
	drawable );

 そんで最終的に、mutate()でDrawable として出力するんじゃないかな?

Drawable	 mutate()
	Make this drawable mutable.
(StateListDrawable)

 そのDrawable をsetBackgroundDrawable した後に、

(Button)
void	 refreshDrawableState()
	Call this to force a view to update its drawable state.

 …は実行しなくてもいいのかな…?

 ちなみに、テキストカラーではColorStateList がStateListDrawable に相当するんじゃないかな?

 …と。調べてみたのはココまで。
 ここから先は実証実験ってことになるんだけど…。
 その試行錯誤のコストは、結果に見合わない気がしたんだ。(^_^;
 なぜなら、色々やってみて失敗するより、任意のButton class を作ってしまう方がてっとり早く確実だから。
 iアプリなんかだと、アプリ容量が懸念されるところだけど、Android はそんな心配さらさらないからね。
 StateListDrawable については、ココで打ち切ることにした。

任意のButton class を作る

 結局のところ、xml指定しない場合、この方法がよいみたいだ。
 そんなに難しいことでもないしね。
 classを初めてイジる人には、ちょうどいいお題じゃないかな?

 サンプルのソースはこんな感じで作ってみた。
 素のボタンとそう変わりないから、Buttonを置き換えるだけで使えるよ。

package com.migimaki.android;

import android.widget.Button;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Rect;
import android.view.animation.AlphaAnimation;
import android.view.animation.CycleInterpolator;
import android.view.animation.TranslateAnimation;

import android.util.Log;


public class MyBut extends Button {

	public MyBut ( Context c ){
		super( c );
		//--
		// 背景色設定
		setBackgroundColor(Color.argb(128, 0, 0, 255));	// 青
		//--
	}

	// Event : Focus Changed
	public void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect){

		if ( isFocused() ){
			// 背景色設定
			setBackgroundColor(Color.argb(128, 0, 255, 0));	// 緑
			
			////
			TranslateAnimation translate = new TranslateAnimation( 0, 100, 0, 0 );
			translate.setDuration(4000);
			translate.setInterpolator(new CycleInterpolator(1));
			startAnimation(translate);
			////--
		} else {
			// 背景色設定
			setBackgroundColor(Color.argb(128, 0, 0, 255));	// 青

			////
			AlphaAnimation alpha = new AlphaAnimation( 1, 0.75f );
			alpha.setDuration(4000);
			alpha.setInterpolator(new CycleInterpolator(1));
			startAnimation(alpha);
			////--
		}
	}
}

 選択されていない状態は青。
 選択されると、緑。

 と、ボタンの背景色が変わる。

 決定された状態は、リスナー側のonClick()内でやることになる。
 class内でやる方が美しいんだけど、イマイチ、その意味を見いだせなかった。
 それと、onTouchEvent なんかでやってみたら、onClickが発生しなくなってしまったんだ。
 色々イジくるより、onClick でやる方がてっとり早い。

 オマケで、Animation のエフェクトをつけてみた。
 フォーカスが外れると、半透明で点滅。
 選択されると、横方向に揺れる。
 縦にボタンを連ねた状態で、カーソル・キーでフォーカスを連続移動させると、階段を登るみたいでちょっとおもしろい。

Posted in ボタン. Tags: , , , , . XMLなしで、ボタンの外観を変える はコメントを受け付けていません »

選択肢メニューを作ってみた

タイトル画面には、それぞれのモードへ行くためのボタンが必要だね。
フツウにボタンを配置してもいいんだけど、それだとタイトル画面専用になっちゃう。
別にかまわないんだけど、せっかくなんで、汎用選択肢メニューとして作ってみた。

仕 様

  • 選択肢ボタンは、選択肢専用 ViewGroup に属する。
  • ボタン生成と共に、それぞれへユニークなIDがふられる。
  • ボタンを押されると、それぞれのIDをハンドラ へ送る。
  • ハンドラはすぐにViewGroup とボタンを非表示にする。


 で、メニュー(ハンドラ) が保持するIDを見れば、なにが選択されたかわかる。
 もしくは、メニューからリスナーへの通知にしてもいいね。

 …って、ListView そのものじゃん! Σ
 じゃ、ListView をベースに作ればいいか…と、ちょっとやってみたがうまくいかない。
 どうもXMLを使わないと面倒らしい…。

「AndroidでListView」
 XMLを使わない場合だと、自前でBaseAdapterクラスを拡張して、getView()の中でList内の要素を生成しないといけないらしい

 おそらく、BaseAdapter がボタンからの通知を統括してたりするんだろうね。
 当初の予定どおり、自前で作るとするか。
 まぁ、Open & Close のエフェクトとかを考えたら、その方が融通効きそうだし。

プロトタイプ

 で、こんな感じで作ってみた。

package com.migimaki.android;

import android.content.Context;
import android.widget.LinearLayout;
import android.view.Gravity;
import android.graphics.Color;
import android.widget.TextView;
import android.widget.Button;
import android.view.View;
import android.view.View.OnClickListener;

import android.util.Log;


public class SelectMenu extends LinearLayout implements OnClickListener{

	private Context context = null;
	private onSelectListener _listener = null;		//リスナー

	//
	public int chois = 1;	// 選択回数カウンター。残り値分、選択可能。
	
	public boolean selected = false;	// 選択されたか?
	public int select_id = -1;	// 選択されたボタンID
	//--
	
	//==
	
	
	public SelectMenu ( Context c ){
		super( c );
		context = c;
		//--
		setOrientation(LinearLayout.VERTICAL);		// View配置設定 : 縦並び
	}


	// init & make Menu
	public void init( String menuMes, String butName[] ){
		chois = 1;
		selected = false;
		select_id = -1;
		//--
		setGravity(Gravity.CENTER);		// センター配置
		
		// Padding
	//	setPadding( 100, 100, 200, 200 );
	//	setPadding( -1, -1, -1, -1 );	// Padding 未設定の状態に初期化
		//--
		
		// メニュー・メッセージ
		addMes( menuMes );
		
		// ボタン作成
		for ( int i=0; i<butName.length; i++ ){
			addButton( i, butName[i] );
		}
		
		//	setVisibility( View.VISIBLE );
	}

	
	// make Text Mes
	public void addMes( String mesStr ){
		TextView mes = new TextView( context );
		mes.setText( mesStr );
		
		mes.setBackgroundColor(Color.argb( 128, 0, 0, 255 ));	// 背景色設定
		mes.setHeight(40);		// 高さ設定
		mes.setTextSize(20.0f);	// フォントサイズ
		mes.setGravity(Gravity.CENTER);		// センター表示
		
		addView(mes);
	}
	
	// make Button
	public void addButton( int id, String butName ){
		Button but = new Button( context );
		but.setId( id );
		but.setText( butName );

		//	mes.setBackgroundColor(Color.argb( 128, 0, 0, 255 ));	// 背景色設定
		mes.setHeight(40);		// 高さ設定
		mes.setTextSize(20.0f);	// フォントサイズ
		mes.setGravity(Gravity.CENTER);		// センター表示

		addView(but);
		but.setOnClickListener( this );	// onClick の設定
		
//	Log.d("TEST", "add but(" +id +")"+" : " +but.getId() );
	}
	
	// close : remove All Views
	public void close( ){
		removeAllViews();
	}

	// Event : click
	public void onClick( View but ){
		
		if ( chois > 0 ){
			selected = true;
			select_id = but.getId();
			
			if ( _listener != null ){
				_listener.onMenuSelected( select_id );	// イベントの通知( -> Activty )
			}
			chois--;
			//--
			
			// 選択されたボタン以外を非表示にする。
			if( chois <= 0 ){
				int child = getChildCount();
				for ( int i=1; i<child; i++ ){
					if( i != ( select_id +1 ) ){
						getChildAt( i ).setVisibility( View.INVISIBLE );
					}
				}
			}
			//--
		}
		//--
//	Log.d("TEST", "Who click? : " +but.getId() +"  select_id : " +select_id );
	}
	
	
	
	////////////////////////////////////////////////////////////////

	// イベントの通知先
	public interface onSelectListener{
		public void onMenuSelected( int select_id );
	}

	// リスナーの登録
	public void setOnSelectListener( onSelectListener listener ){
		_listener = listener;
	}
	////////////////////////////////////////////////////////////////

}

●SelectMenu のオブジェクトを生成後、表示したいViewGroup にadd すれば使用できる。

●表示位置とボタンの横幅は、setPadding で設定する。
 setPadding はLinearLayout に元々あるmethod なので、オブジェクトに対しても設定できるよ。

●init() で、メニュー・メッセージと各ボタン名の設定。
 method を実行すると、メッセージのTextViewとボタンを生成して、メニューを表示する。

●選択肢が決定されると、ボタンのIDがselect_id に保持される。
 また、リスナー登録しておくと、select_id を通知してくれる。

●close() で、メニューを非表示にする。
 すべてのメッセージとボタンをLinearLayout から削除する。
 オブジェクトは生きてるので、init() すれば新しいメニューが表示されるよ。

●ちょっとお遊びで、chois という変数をつけてみた。
 chois回数分だけ、ボタンを押せる。
 正解を選ぶとか、正しい順番を押させるとか、…そんな使い方。

課 題

・ボタンの外観
	今はデフォなので味気なし。
	カーソルと、押された時の反応も変えるべし。
・ボタン・サイズ
	文字サイズと共に、今は固定。
	文字列に合わせて変わる、指定設定できるようにする。
・Open & Close エフェクト
	パッと表示されるだけじゃ味気ない。
	なにかエフェクトをつけよう。

 それと、ソースの洗練もね。(w

Posted in メニュー, 選択肢. Tags: , , , . 選択肢メニューを作ってみた はコメントを受け付けていません »

設定モードの作り方 (設定画面)

 アプリの動作設定等を行う画面。
 なんとなくわかってきたので、必要手順等、作成方法をまとめておく。
 なお、「設定モード」としたのは、画面のみの作成に止まらない、全体的なものであるから。

 以下の作業に、特に順番はない。

◆設定画面の作成

[ AndroidManifest.xml ]
●Activity の追加

 PreferenceActivity を追加する。
●↓のように、の中に記述。

 AndroidManifest.xml

1
2
3
<application>
    <activity android:name="MyPrefs"></activity>
</application>

 ※.は、既存のもので新設はしない。
 ※.”MyPrefs” は、PreferenceActivity のclass名。(任意)

[ MyPrefs.java ] extends PreferenceActivity
●PreferenceActivity の作成
 PreferenceActivity を継承したclassを作成する。

●PreferenceActivity の役割
 有体にいえば、「設定画面の起動(表示)」。
 画面内容自体は、別のxmlに記述する。
●xmlの指定
 MyPrefs.java

1
addPreferencesFromResource(R.xml.prefes);

※.prefes は、画面内容のxml名。(任意)

[ prefes.xml ]
● prefes.xml の作成
 ファイル名に特に決まりはない。
 PreferenceActivity から引用されるので、それの記述に合わせる必要がある。

・作成場所
  /res/xml/

● prefes.xml の役割
 有体にいえば、設定画面の内容。
 記述内容がそのまま画面に表示される。
 ※.記述内容についてはここでは解説しない。

◆設定画面の実行(表示)

●概要
 設定画面の実行は、Intent によって行う。
 Intent を作成し、そのIntent に PreferenceActivity を割りつける、ことになる。
 例えばボタンであれば、onClick()で↓を実行する。

 <例>

1
2
Intent intent = new Intent(this, com.migimaki.android.MyPrefs.class);
startActivity(intent);

 ※.Intent の第二引数は、パッケージ名となることに注意。

 ざっと、こんなところだろうかね。
 動作から推察するに、「アプリmainのActivityから、別のActivityを実行する」といったところかな。
 フツウのclassとちがって、呼び出し側・実行側に内包されない。

 そこでちょっとした問題。
 「Activity の遷移」なので、”戻る”ボタンで戻れてしまうのだ。
 便利といえば便利なのだが、ゲーム系だと予期しない動作を引き起こしかねない。
 ちょっと注意が必要だね。

参考
Androidアプリの設定画面を作成する

Posted in アプリ設定. Tags: . 設定モードの作り方 (設定画面) はコメントを受け付けていません »

Listener ~リスナーってなによ?

 てっとりばやくいうと、onDraw()とかがソレ。
 正確にはイベント・リスナーというらしい。

 class 外部でイベントが発生すると、それに対応したmethod が実行される…と。
 onDraw() でいえば、

	1. 画面更新イベントが発生
	2. OSがclass のonDraw() を実行

 で、onDraw()の実行処理が「イベントハンドラ」。
 こんなトコだろうかね。

 ボタンなんかもそうだね。
 押されたら、その処理をbutton.classの中で行うんじゃなくて、別のclass でやってもらう。

	button.class
	「ボタン」
	    ↓押された
	View.class
	    onClick()
	    メッセージ表示
	    「押された」

リスナーが「通知先」で、その処理が「イベントハンドラ」。

 こういう仕組みが、Android にはそこかしこにある。
 おそらく、ViewのonDraw() のような、よく使うもの、必須となるようなものはあらかじめclassに登録されているのだろうね。
 では、登録されていないものは…?
 implements でそれを埋め込むことになる。
 つまり、「このclass で、○○イベントを受け取ります」って「宣言」するってことやね。

で? その構造はどうやって作るのよ?

 自前classでも作りたくなることは多々あるよね。
 例えば、スレッドで処理をしていて、その処理が終わったとか、結果を別classへ送りたいとか。
 複数スレッドを動かしてると、特に必要性を感じるね。

 ということで。
 「ボタン」を例に、サンプルを作ってみた。

	[クリック]
		↓
	MyButton.onTouchEvent()
		↓[通知]
	_listener.onClick()
		↓
	[メッセージ更新]

	◆listener_Test
		・2つのオブジェクトを生成。
		・MyButton のリスナーに、ListenerViewを登録
		  _listener = ListenerView
	■MyButton
		onTouchEvent()
		・クリック・イベントを受信したら、リスナーに通知。
		  _listener.onClick()
	■ListenerView
		 onClick()
		・イベントを受信すると、メッセージを更新

listener_Test.java

package com.migimaki.android;

import android.app.Activity;
import android.os.Bundle;
import android.widget.FrameLayout;
import android.view.ViewGroup;

import com.migimaki.android.MyButton.onClickListener;

public class listener_Test extends Activity {

	private final int WC = ViewGroup.LayoutParams.WRAP_CONTENT; 
	
	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		FrameLayout frameLayout = new FrameLayout(this);

		// オブジェクトを生成
		ListenerView LV = new ListenerView(this);
		MyButton myButton = new MyButton( this );
		
		// リスナー登録
		myButton.setOnClickListener( (onClickListener)LV );
		
		
		// レイアウト追加&表示
		frameLayout.addView( LV, createParam(WC, WC));
		frameLayout.addView( myButton, createParam(WC, WC));
		setContentView(frameLayout);
	}
	
	private ViewGroup.LayoutParams createParam(int w, int h){
		return new ViewGroup.LayoutParams(w, h);
	}

}

MyButton.java

package com.migimaki.android;

import android.content.Context;
import android.widget.ImageView;
import android.view.MotionEvent;

public class MyButton extends ImageView {
	
	public MyButton( Context c ){
		super( c );
		setImageResource( R.drawable.icon );
	}

	private onClickListener _listener = null;		//リスナー

	// リスナーの登録
	public void setOnClickListener( onClickListener listener ){
		_listener = listener;
	}

	// click イベント
	public boolean onTouchEvent( MotionEvent event ){
		_listener.onClick();	// イベントの通知
		return true;
	}

	// イベントの通知先
	public interface onClickListener{
		public void onClick();
	}

}

ListenerView.java

package com.migimaki.android;

import android.content.Context;
import android.widget.TextView;
import android.graphics.*;

import com.migimaki.android.MyButton.onClickListener;

public class ListenerView extends TextView implements MyButton.onClickListener {

	public ListenerView( Context c ){
		super( c );

		setPadding( 50, 50, 200, 300);	//文字表示エリア
		setTextColor( Color.WHITE );
		setText("Listenerテスト");
	}

	// イベントの受信
	private int count=0;
	public void onClick(){
		count++;
		setText( ""+count+ "回、押された?!" );
	}

}

 作ってみたものの…イマイチなサンプルだなぁ。(^_^;
 本当は、2つのclassで納めたかったんだけど…。
 ボタンじゃなく、スレッドを例にすればよかったかな。

 ちなみに、interface 宣言したものは、implements 先で設置が求められる。
 設置されていないと、eclipse がエラー出してくれるよ。

Posted in Listener. Tags: , . Listener ~リスナーってなによ? はコメントを受け付けていません »

setPadding の引数

View のsetPadding はけっこう便利だね。
 表示位置を自由に設定できるし、ボタンの大きさも切り揃えられる。
 でも、設定する値がイマイチややっこしい。

	setPadding(int left, int top, int right, int bottom)

 引数はそれぞれ、Viewの端からの値になる。
 left なら、Viewの左端から、XX dotという具合。

 下図の黒四角がViewだとして、青にPadding設定したいとする。
 その場合、それぞれピンク線の長さが、setPadding の引数となる。

 引数がマイナス値だと、緑のようにViewの表示外からの設定となる。

 ここらへん、イマイチ感覚的にしっくりこないんだなぁ。
 原点x, 原点y, 横幅w, 縦幅h って設定なら、計算なんかもラクなんだけど。
 まぁ、利点も多いんだけどね。(^_^;

Posted in Padding, View. Tags: , . setPadding の引数 はコメントを受け付けていません »

SharedPreferencesモドキを作ろう

 XmlSerializer なんかをイジって、xml 関係がだいたい飲み込めた。
 しかし、データ・フォーマットを考えるのはめんどくさい。読み込み部が専用になるのも、なんかアレよね。
 読み込みは遅いが、やっぱ融通の効くSharedPreferences は便利だ。
 しかし、SharedPreferences は外部ファイルを読み込めない…。
 なら作ってしまえ、というワケ。
 どうせint とString しか使う予定もないし。
 そんなに面倒でもないだろう。

package com.migimaki.android;

import android.content.Context;

import java.io.FileInputStream;
import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;

import android.util.Log;


/*
 * Preferences Reader クラス
 * 
 */
public class PrefReader {

	private Context context;
	public String fPath = "/";

//====================
//初期化
//====================
	/**
	 * コンストラクタ
	 */
	public PrefReader( Context c, String fPath ){
		context = c;
		this.fPath = fPath;
		//--
	}


//====================
// read method
//====================

	////////////
	/// Read Int
	public int getInt( String key, int default_i ){

		int result = default_i;
		//--

		try{
			FileInputStream is = new FileInputStream( fPath );
			XmlPullParser xmlPullParser = Xml.newPullParser();
			xmlPullParser.setInput( is, "UTF-8" );

			
			int i = xmlPullParser.getEventType();
			do{
				if( i == XmlPullParser.START_TAG 
						&& xmlPullParser.getName().equals( "int" )
							&& xmlPullParser.getAttributeValue( null, "name" ).equals( key )
					){

						result = Integer.parseInt( xmlPullParser.getAttributeValue( null, "value" ) );
						break;
				}
				i = xmlPullParser.next();
			}while ( i != XmlPullParser.END_DOCUMENT );

			is.close();

		}catch( Exception ex ){
			Log.d( "Err", "PrefReader : getInt" );
		}
		//--
	//	Log.d( "TEST", "PrefReader " +key +":" +result );
		return result;
	}
	///==
	
	////////////
	/// Read String
	public String getString( String key, String default_s ){

		String result = default_s;
		//--

		try{
			FileInputStream is = new FileInputStream( fPath );
			XmlPullParser xmlPullParser = Xml.newPullParser();
			xmlPullParser.setInput( is, "UTF-8" );

			
			int i = xmlPullParser.getEventType();
			do{				
				if( i == XmlPullParser.START_TAG 
						&& xmlPullParser.getName().equals( "string" )
							&& xmlPullParser.getAttributeValue( null, "name" ).equals( key )
					){

						result = xmlPullParser.nextText();
						break;
				}
				i = xmlPullParser.next();
			}while ( i != XmlPullParser.END_DOCUMENT );

			is.close();
			
		}catch( Exception ex ){
			Log.d( "Err", "PrefReader : getString" );
		}
		//--
	//	Log.d( "TEST", "PrefReader " +key +":" +result );
		return result;
	}
	///==
	
}

 できた。int とString だけだけど。(w

 各method でFileInputStream を設定しているのは、そうしないと読み込み位置が保持されてしまうため。

 SharedPreferences には、int とString の他に、boolean, float などなどがある。
 それらはおそらく、int とほぼ変わりがないだろうと思う。
 必要になったら、作るとしよう。

Posted in File, XML. Tags: , . SharedPreferencesモドキを作ろう はコメントを受け付けていません »

任意のXMLファイルの作成

 Androidアプリから、任意フォーマットのxmlを作成してみた。
 使用するのは、XmlSerializer

XmlSerializer って?

 XMLの作成には、XmlSerializerを使用しなくても行える。
 しかし、XML規格に沿って作成するには、それなりの知識も必要だし、ヘッダー等を整備するのも面倒くさい。
 XmlSerializer はそこらへんの面倒を引き受けて、XML の編集を行えるものらしい。
 また、書き込みの他に、読み込みmethod も用意されているようだ。

 ここでは書き込みのみXmlSerializer で行い、読み込みはXmlPullParser で行った。

XMLの書き出し

 書き出す内容は、以下の内容とすることにした。

	<xml? …>
	<gdat id="1">
	<Int>
	0
	</Int>
	<key>
	Kanon
	</key>
	</gdat>

 ※.xmlヘッダーは面倒なので略している。

 ソースでは以下のようになる。

//====================
// save method
//====================

	public void save( String fPath ){

		int i = 0;
		String key = "Kanon";
		//--
		
		XmlSerializer serializer = Xml.newSerializer();
		try {
			FileOutputStream os = new FileOutputStream( fPath );
			serializer.setOutput( os, "UTF-8" );
			
			serializer.startDocument("UTF-8", true);	// ヘッダー

			//<gdat id="1">
			serializer.startTag("", "gdat");
			serializer.attribute("", "id", "1" );
			//--

			//
				serializer.startTag("", "Int");	//<Int>
					serializer.text( ""+i );
				serializer.endTag("", "Int");	//</Int>
				
				serializer.startTag("", "key");	//<key>
					serializer.text( key );
				serializer.endTag("", "key");	//</key>
			//--

			serializer.endTag("", "gdat");	//</gdat>
			serializer.endDocument();	// フッター
			
			serializer.flush();	// 出力
			os.close();
		} catch (Exception e) {
		}
	}
	

 XmlSerializer は、それ自身でファイルにする能力はないようだ。
 そのため、FileOutputStream を出力先として指定している。( setOutput )
 また、出力先には、StringWriter 等も指定できる。

 編集自体は単純なので、ソースからわかるかと思う。

 編集が終われば、flush() で出力。
 FileOutputStream の出力先にファイルが作られる。

 なお、出力されたファイルを見てみると、改行コードが一切省かれていた。
 それでも機能するし、データも小さくなるからいいんだけど。(^_^;

XMLの読み込み

 読み込み方は、それぞれの効率性などから、色々とやり方が考えられる。
 サンプルでは、単純な順番読み込みをやってみた。

//====================
// load method
//====================

	public void load( String fPath ){
		
		try{
			FileInputStream is = new FileInputStream( fPath );

			XmlPullParser xmlPullParser = Xml.newPullParser();
			xmlPullParser.setInput( is, "UTF-8" );
			
			String buf_s = "";
			int buf_i = 0;
			
			Log.d( "TEST", "---- load start ----" );

			int i = xmlPullParser.next();
			if( i == XmlPullParser.START_TAG ){

				Log.d( "TEST", "Parser.getName : " +xmlPullParser.getName() );	// gat

				if ( xmlPullParser.getName().equals("gdat") ){
						buf_s = xmlPullParser.getAttributeValue( null, "id" );	// idの値
						buf_i = Integer.parseInt( buf_s );

						Log.d( "TEST", "" +buf_i );
				}
				xmlPullParser.next();

				if ( xmlPullParser.getName().equals("Int") ){	//Int
						buf_s = xmlPullParser.nextText();
						buf_i = Integer.parseInt( buf_s );

						Log.d( "TEST", "" +buf_i );
				}
				xmlPullParser.nextTag();	// -><END_TAG>
				xmlPullParser.nextTag();	// -><START_TAG>
			
				if ( xmlPullParser.getName().equals("key") ){	//key
						buf_s = xmlPullParser.nextText();

						Log.d( "TEST", "" +buf_s );
				}

			}
			Log.d( "TEST", "---- load over ----" );

			is.close();
		}catch( Exception ex ){
			Log.d( "Deb", "load error...(game data)" );
		}
		//--

	}

 非常にお莫迦なサンプルなので、実用的ではないね。(笑

 XmlPullParser は一行ごとに読み込みを行うようだ。
 next…とついているmethod は、「行送りをする」と考えていい。

	next()  … 一行送り。
	nextText()  … タグのtextを読み込み、一行送る。
	nextTag()  … 次の START_TAG か END_TAG まで送る

 getAttributeValue でタグのパラメータの値を取り出せる。
 パラメータ名の他にも、要素位置で読む方法もある。

	getAttributeValue(0)

 getName でタグの名前を取得。
 .equals で、文字列の比較を行える。
 .equals(“gdat”) だとしたら、==”gdat” と読み替えると理解しやすい。


 ここで取り上げた使用方法はほんの一例。
 他にも色々なmethod ややり方があるので、それぞれ調べてみてほしい。

Posted in File, XML. Tags: , , . 任意のXMLファイルの作成 はコメントを受け付けていません »

プレリファレンスを置き換えてみるテスト

 セーブデータを扱うには、SharedPreferences がお手軽でお気軽。
 だけど、格納場所がdataディレクトリと、固定なのが難点。
 というのも。
 いま作成中のアプリでは、dataディレクトリに作らないから。

 作成中のアプリは、ノベル・リーダー。
 複数の作品データを切り替えることになる。
 そのため、各作品ごとに、セーブデータが必要になり、その場所は作品データのある場所に置こうと考えている。

	1. 作品ごとにデータを作る。
	2. 場所は作品データと同じ。( not dataディレクトリ )

 なので、SharedPreferences の仕様は、ちと困るのである。

置き換えてみよう

 格納場所が固定なら、置き換えてしまえばいいんじゃない?
 しかし、そんなことが可能なのだろうか…?

 ということで、このテストをやってみた。
 単純にこういう実験である。

	1. pref.xml を記録
	2. pref.xml をSDへコピー
	3. pref.xml のデータ変更
	4. SDからpref.xml をコピー
	5. pref.xml を読み込む
 5.で元データの内容が読み込めれば、置き換え成功!

 さて、その結果はというと…失敗である。
 読み込んだ内容は、3で書き換えたものであった。
 なにが原因だろう?

仮説 a. 読み込みmethod に不具合がある。
 これはない。
 まず、1の直後に記録内容のチェックに使用し、正常動作している。
 それと単純に失敗している場合、デフォルト値が返ってくるハズなのだが、それとは異なり、3で記録した値である。

仮説 b. ファイルのコピーに失敗している。
 まぁ、コレであろう。
 そう思って、ターミナルから/data/data へ潜ってみる。
 pref.xml は存在し、more で中身を表示したところ、それは1の時の内容だった。
 はて?
 これはどういうことだろう?
 読み込みmethod に原因はなく、ファイルもちゃんと置き換わってる。
 なのに、値は元に戻らない…。
 摩訶不思議である。
 Android、おまえはドコから、ナニを読んでいるのだ?

消してみよう

 pref.xml を読んでいないことはまず確実である。
 では、その値はドコから?

 そこで4の時点で、pref.xml を消してみることにした。
 読み込めないので、デフォルト値が返ってくるハズだ。
 しかし、結果は変わらず、3の時の内容だ。
 まったくもって面妖ナリ。
 ファイルがないのに、その値をひっぱってきていることになる。
 まるで、
「あなたの後ろに幽霊がいますよ?
 私には見えるんです…ククク…」

 なんていわれた気分。
 う~む…。
 ファイルの消し方がマズイのだろうか?

 ならばと、Editerから値をクリアすることにしてみた。
 Editerとはオブジェクトのひとつで、値を記録するときに使用する。
 先程はファイルごとを削除する方法。
 今回は内容を消してしまう方法。
 さて、結果はというと…成功である。
 いや、読み込みには失敗、値はデフォルト値を返してきた。
 つまり想定した動作だ。

 では、今度は書き込まず、いきなり読んでみよう。
 つまり再起動直後にはどうなるか?
 結果は再起動前に、コピーした内容が正常に読み込めた。
 なるほど。
 なんとなくわかりかけてきた…。

ということは、どういうことなのだろう?

 ここから先は確かめるつもりもないので、推論の域である。

推論 a. Androidが整合性をチェックしている。
「メモリー上のなにかとファイルが異なる場合、メモリー上のデータを信頼する」
 セキュリティからするとありそうな話しではある。
 しかし大げさなので、ちと眉唾な気も。

推論 b. なんらかのlockがかかっている。
 ファイルは削除や置き換えが可能なので、メモリー上のlockだろう。
 手続き上のミスか、またはキャッシュの類かもしれない。
 aよりはありえそうな話しだね。

 ともかくも。
 確実な結論はただひとつ。
 SharedPreferences を使う計画は見直し。
 手間をかけて読み込むしかなさそう…くすん。

by the way…

 ついでに、色々と見て回っての発見を書いておこう。

 SharedPreferences は/data/data/%Package Name%/shared_prefs/ に格納される。
 でも、ファイル・マネージャーの類で見ても、/data/data はないのである…。
 そんじゃと、ターミナルから入ってsuしてみたら…
 あった!!
 なるほど。 /data/data のオーナーはsystemで、ユーザーには不可視になってる。
 で、/shared_prefs のオーナーは、app_29。
 おそらく、作ったアプリなんだろうね。
 中のxmlも、同じくapp_29 だった。
 ちなみに、/shared_prefs と同列に /lib なんてのがある。
 オーナーは system。中身はカラ。
 他のアプリと共有するようなclassが入るんだろうかね。

Posted in テスト. Tags: , . プレリファレンスを置き換えてみるテスト はコメントを受け付けていません »