ステップ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_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のような簡潔な書き方ではないものの、以下のページのように「初期化子の上書き」で対応できるっぽい。
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の警告対応 };