ステップ5−1:パレット〜色の自作

=前置き=

 ここまでのステップでお絵かき処理はなんとなくできた。ただ、色の指定とかができないので、まずは「色」の挙動が一通りできるところまで作ることにする。
 ここでは自分が詰まった部分だけ書く。そのため、グリッド表示のような特に問題がなかったところは省略する。基本的に、省略してるような部分は以下の本に書いてあるし。

 ということで、ここからしばらくは細かいTips的なことばかり書いていく。

=接続=

 例えばカラーパレットのボタンを押したらキャンバスの描画色を変更したい。ここらへんの接続方法は、AS3の時と同じ感じで実現できた。ただAS3よりはムダな感じのものが一つ必要だった。

 今のところ、GUIのパーツの接続に関しては「端子」の概念を使うようにしている。つまり、パーツの出力を他のパーツの入力につなぐ、という風に考えている。

 AS3の時は「入力側の関数を出力側に渡して、出力があればそれを呼んでもらう」という風にできたものの、Javaではそもそも「関数を渡す」ということができないらしい。それっぽいことを実行しようとするといちいちインターフェースを実装したものを作る必要がある。「ちゃんと型指定したもの」であれば全てのインターフェースをわざわざ書かないといけないし、「型指定がないもの」であれば毎回キャストする必要がある。ただ、Javaには新しくGenericsというテンプレートみたいなものが入ったので、これによって「インターフェースは一つだけ用意しておいて、型は外部から指定する」という風なコードが書ける。


 具体的には以下のような感じ。接続用のクラスはたった3行。

public interface IConnector<ValType>{
	public void send(ValType in_Val);
}

 これを以下のようにして使う。

button.Out_Color(//出力端子
	new IConnector<Integer>(){//コネクタ
		public void send(Integer in_Val){//送信
			canvas_color.In_Color(in_Val);//入力端子
		}
	}
);

 この例では「buttonのOut_Color」と「canvas_colorのIn_Color」を「IConnector」で接続している。「in_Val」が渡したい色の値になっている。
 「In_Color」の方は色が渡されるので、これを描画色に設定すれば良い。
 「Out_Color」の方は、このタイミングではまだ出力が実行されるわけではないので、このIConnectorを保持しておき、出力の段階になってからsendを呼ぶようにする。
 いくつでも登録できるように、IConnectorはListとして保持しておくと良い。


 ただ、今回の例のようなただの整数であっても、プリミティブ型(int)ではなくクラス(Integer)を使う必要があるのが多少気にかかる。おそらくJavaだと仕方がないことだと思うけど。


=高速なピクセル操作=

 HLSで1ピクセルずつ計算していく部分が重いので、まずは以下のページを参考に「毎回ピクセルをセットする」のではなく「一括でセットする」ようにした。少しだけ早くなった。
 http://www.adakoda.com/adakoda/2009/01/android-bitmapgetpixels-setpixels.html

 あとは素直にループの外に出せる部分は出すようにした。

 さらに、ケータイの解像度で律儀に1ピクセルをちゃんと計算するのもムダっぽいので、8ピクセルごとまとめて計算するようにした。見た目はちょっと悪くなったけど、8x8ピクセル、つまり64ピクセルの計算を一度にやることになるので、速度は単純に64倍くらいになるので効果は高かった。もう少し見た目と速度のバランスを考えるなら、「1mm」のような距離指定からピクセルを逆算すれば良いはず。ここらへんは前回の拡大と同じくhttp://handalab.com/android/dev-2/device/149/を参考にすればOK。

=高さだけ固定したい=

 画面の下に高さだけ固定して横は可変なViewを用意したい。できればXMLの設定だけで。

 これはわりと簡単で、「android:layout_height="100dip"」という風に指定すれば良い。普通は右側は"wrap_content"のような感じになっていて文字列を指定しているように見えるが、内部的には数値の定数でマイナスがセットされているだけらしい。幅だけ固定する場合も同様に「android:layout_width="100dip"」という風に設定すれば良い。

=Spacer=

 パーツごとに隙間を設定したい場合がある。あるいは外枠との距離を空けたい場合がある。
 mxmlではそのまま「Spacer」というものがあったが、AndroidではLinearLayoutを使って「android:layout_width="wrap_content"」「android:minWidth="100dip"」のような感じで設定できる。上のような高さ固定でも良いかもしれない。
 ただ、レイアウトの計算は意外とコストが高いようなので、できるだけPaddingなどで隙間を設定するように今はしている。

=Mapの初期化=

 配列のようにマップ(HashMap)も初期化したい。mxmlのような簡潔な書き方ではないものの、以下のページのように「初期化子の上書き」で対応できるっぽい。

Mapの初期化 - traih.log

 Eclipseにてメンバ変数の初期化に使うと警告が出るので、それを抑えるために以下のように書いた。

public Map<String, Float> m_Val = new HashMap<String, Float>(){
	{//Init
		put("H", 0.f);
		put("L", 0.5f);
		put("S", 1.f);
	}
	private static final long serialVersionUID = 1L;//Eclipseの警告対応
};