2013年6月18日火曜日

SurfaceViewでの画像のタイル描画(繰り返し)

SurfaceViewを扱うとき背景のところを1枚絵で描画しているときはいいですが、小さい画像の繰り返しで済むような場合は、リソースの節約のためにもタイル(繰り返し)描画をしたほうがいいかと思います。
ロジック的には下のような感じ、while分の中で描画したい大きさに達するまで位置を変えて繰り返し描くだけです。

//描画領域Rect
Rect r = new Rect(left, top, left + width, top + height);
//画像幅取得
int imgWidth = background.getWidth();
//画像高さ取得
int imgHeight = background.getHeight();
switch (layout) {
case BACK_FIT : //領域全体
    canvas.drawBitmap(background, imgRect, new Rect(r.left, r.top, r.width(), r.height()), paint);
    break;
case BACK_VREPEAT : //縦の繰り返し
    int sh = 0;
    while (sh < height) {
        canvas.drawBitmap(background, imgRect, new Rect(r.left, r.top + sh, r.width(), imgHeight), paint);
        sh += imgHeight; //画像の高さ分足す
    }
    break;
case BACK_HREPEAT : //横の繰り返し
    int sw = 0;
    while (sw < width) {
        canvas.drawBitmap(background, imgRect, new Rect(r.left + sw, r.top, imgWidth, r.height()), paint);
        sw += imgWidth; //画像の幅分足す
    }
    break;
}

最後の描画で描画領域を考慮していないのではみ出すことがありますが、それで困る場合は先日書いたSurfaceViewで描画範囲を限定するを利用するとよいでしょう。

2013年6月17日月曜日

AndroidのSerializableクラスでのtransient指定の落とし穴

Androidのと付けましたがJava全般の話ですね。
先日Serializableなクラスを継承したクラスの落とし穴という話を書きましたが、またしてもSerializeではまってしまいました。
落とし穴というか自分が無知だっただけなんですが、Serializableクラスでフィールドへtransient指定した場合、宣言と同時に値を入れていてもデシリアライズ時には反映されません。
具体的にはこんな感じ

class S implements Serializable {
    public final int x;
    public transient int t = 20;
    public S(int x) {
        this.x = x;
    }
    public String toString() { return "X=" + x + ",T=" + t; }
}

S s = new S(400);
oout.writeObject(s);
Log.v("LOG", (s + ":オブジェクトを書き込みました"));
ObjectInputStream oinp = new ObjectInputStream(finp);
Log.v("LOG", (oinp.readObject() + ":オブジェクトを読み込みました"));

[結果]
06-18 16:26:18.990: V/N(21976): X=400,T=20:オブジェクトを書き込みました
06-18 16:26:18.990: V/N(21976): X=400,T=0:オブジェクトを読み込みました

初期値で与えているt=20が反映されていません。
デシリアライズ時はコンストラクタも通りませんので気を付けましょう。

2013年6月14日金曜日

Factoryがアプリゲットでレビューされていました

全然気づいていなかったんですが、なんとなく検索してみたらFactoryが5月22日にアプリゲット様で今日のおしゲー「ゲームウォッチ風単純ゲーム」という感じでレビューしていただいてました。

  ありがとうございました。

2013年6月13日木曜日

SurfaceViewで描画範囲を限定する

SurfaceViewは描画時の座標指定で画面をはみ出して指定しても、きちんとその指定で描いてくれるので、普段はみ出し部分を気にしたりしないんですが、
今作っている新作アプリで1枚のSurfaceViewを上下に分けて使っているところがあって、いつも通りやってたら上の部分の描画が下の所にはみ出してしまう…
上の画面では等間隔のグリッドを透視投影して描いてる(赤い部分)んですが、下のほうがはみ出してしまっています。
こんなときは描画範囲を限定したい描画のところでCanvas.clipRect(Rect rect)するといいようです。
//限定したい範囲のRect作成
Rect clip = new Rect(0, 0, 640, 320);
canvas.save();
canvas.clipRect(clip);
//描画範囲限定の描画処理

canvas.restore();
ソースはこんな感じ。 
clipRectの指定が限定したくない描画に影響しないように、clipRectする前にcanvas.save()、終わった後にcanvas.restore()するのを忘れないようにしましょう。
結果はこんな感じ。
ちゃんとはみ出し部分が消えています。

2013年6月10日月曜日

AndroidでSerializableなクラスを継承したクラスの落とし穴

なんかよくわからんタイトルになってしまいましたが、Serializableなクラスを継承したクラスはSerializableをimplementsしなくてもSerializeすることができます。

public class S implements Serializable {
  private static final long serialVersionUID = 6105608118246672383L;
}

public class Hoge extends S {
  //serialVersionUIDなし、SをextendsしてるのでSerializeはできる
}

ところがこの継承したクラスはserialVersionUIDがないため、コンパイラが自動生成したserialVersionUIDを与えてしまうのです。
そうなると継承クラスをちょっと変えようものなら、変更前にSerializableしたファイルはserialVersionUIDが違うためInvalidClassExceptionを起こしてしまいます。
そうならないために、serialVersionUIDをきちんとつける習慣をつけましょう。
Serializableは拍子抜けするほど簡単にクラスをファイルに落とすことが出来て大変便利なんですが、適当に使うと大変な目にあいますね。
後々の変更も検討してよく考えて使いましょう。この辺もよく読んでおくといいかも。

Serializationの実装
http://book.geocities.jp/bits_of_java/java/io/serializable/index.html#contents

Java セキュアコーディングスタンダード CERT/Oracle 版 シリアライズ (SER)
https://www.jpcert.or.jp/java-rules/#c13

2013年6月4日火曜日

Factoryがアンドロイダー公認アプリに、そしてデイリーランク2位に!

拙作Factoryがアンドロイダー公認アプリになりました。
 そしてなんと、デイリーランキングで2位に!
 こ、これは本当か!?これで勢いが出たらいいなぁー

2013年6月3日月曜日

間取りー図がSony Selectでレビューされましたー

間取りー図がSony Selectでレビューされましたー


間取りー図は公開したのは半年以上前ですが、同アプリが4月に雑誌掲載して頂いたことといい、ツール系のアプリは息が長いのが特徴ですね。