アプリ

2010/02/28

ブレゼンハムはいらん

  • 組込み
  • 直線

というだけで、無条件にブレゼンハムを使わねば!と思い込んでいた。

が、よく考えてみると、全然高速で計算する必要がない。
そうならば、実装が軽くなるように作る方がいいよな。

何というか、金槌を持ったら全部釘に見える、という言葉があるが、まさにそんな状況であった。
あぶないあぶない。

2010/02/26

AbsoluteLayoutしかない

いや、他に方法はあるのかもしれんが・・・。

私がやりたいのは、AnimationDrawableと自前のViewの併用。
ただそれだけ。
まあ、自前のViewで好きな座標にAnimationDrawableで描画させたい、というようなことを考えている。
それが全然解決できない。

最初は自前のViewを全面に貼り、そこにちんまりAnimationDrawableさせようとしていた。
が、ViewをFILL_PARENTにしておくと、キャラクターが全面に広がって表示されてしまうのだ。
描画のタイミングを遅らせたり、一時的に非表示にしてみるなどしたけど、表示させたときには大キャラクターが表示されていた(あ、キャラクターはPNGで作った画像ね)。
これを仕様としてアプリを作ろうかとも思ったけど、さすがにそれは技術者的に嫌だった。

昨日は、Marginを設定することでWRAP_CONTENTのまま描画位置を変更することができた。
では、この方向で・・・と思ったけど、Marginを動的に変更することができていない。
やり方が悪いのかもしれんが、もうわからん!


というわけで、今まで避けてきたAbsoluteLayoutに手を染めてみた。
非推奨だったから、わざわざ覚えなくとも・・・と思っていたのだ。

使ってみると、よかった。
何で最初に試さなかったの?というくらいに。
あっさり目的が達成できた。
私の1週間を返して・・・。

非推奨とはいえ、わかって使う分には問題がないと思う。
私だって、最初の方法がうまく行けばそっちの方がよかったのだしね。
AnimationDrawableは使い勝手が難しいわぁ。

2010/02/22

Themeでフルスクリーンにする

themeと書いてテーマと読む。
いつも心の中では「てーめ」と発音しているのだが・・・。


今作っているアプリは、フルスクリーンにしたい。
タイトルバーもなく、ステータスバーもなく。
すべてを我が手に置きたいのだ。

ネットで調べると、だいたいこんな手順だった。

  1. getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
  2. requestWindowFeature(Window.FEATURE_NO_TITLE);
  3. 上記をActivityのsetContentView()より前に置く

手順という感じではないな・・・。まあいい。

しかし、別のことを調べているとき、Themeというものがあることを知った。
よく使うスタイルを標準とする、みたいなものかしら。
スキン、というほどではないが、「こんなテーマで描画してね」というくらいのものだろう。

そのテーマの中に「NoTitleBar」とか「NoTitleBar.Fullscreen」などがあることを知った。
どうやら、それでもいいらしい。
ActivityのonCreate()で指定してみるとうまくいかなかったが、AndroidManifest.xmlに直接書くとうまくいった。

なんだ、これでいいやん。

続きを読む "Themeでフルスクリーンにする" »

2010/02/21

AnimationDrawableがうまくいかん

まだアニメーションをやってうまくいってない。
いかんなぁ。


私がやりたいのは、そんなに難しいことではない。

・キャラクターがアニメーションする(パタパタアニメ)
・キャラクターが移動する

これだけ。

前回は、パタパタの部分をAnimationDrawableで、移動をTranslateAnimationで実現しようとしたのだった。
が、失敗した(but, in vain)。

ならば、めんどくさいパタパタはAnimationDrawableをそのまま使い、移動は自分でやろうというのが前回までのあらすじ。


移動させるには、自分で描画しなくてはならない。
というわけで、Viewを継承したクラスを作り、それをonCreate()で生成してsetContentView()させることにした。
そうすれば、ViewはonDraw()を使って好き放題できる。

持っている本ではShapeDrawableの例があった。
自作のViewクラスのコンストラクタでShapeDrawableをnewし、なんやかや設定。
onDraw()でdrawable.draw(canvas)で描画させている。
位置は、setBounds()で設定している。
うん、簡単簡単。

・・・確かに指定した位置に描画はしてくれるのだが、パタパタしてくれない。
start()の位置やタイミングが悪いのかとあれこれ試してみたが、だめだ。

現在は、コンストラクタでもう1つViewを作り、それをアニメーションさせようとしている。
そのViewにsetBackgroundResource()してアニメーションリストを設定後、getBackground()でAnimationDrawableを取得している。
サンプルではコンストラクタでShapeDrawableをnewしているが、そこが違うのかなぁ。
でも、意味としては変わらないと思う。

ちなみに、コンストラクタで作るViewではなく、thisに対して操作するとアニメーションしてくれる。
なんかルールがあるんかねぇ。

アニメーションでゴミが残る

実家に帰るつもりだったけど、思った以上に体が疲れていたのでやめた。

歳ですな。


Androidのアニメーションを試しているが、Translationなどで動かしたときにゴミが残ってしまうのだ。

  

わかりにくいかもしれないが、左図は画面左上が黒と白で点滅しているのだ。
(まあ、ここに載せているのは静止画だが・・・)
TranslateAnimationで移動させると同時に、AnimationDrawableで動かしてもいる。
そのせいで、最初の表示位置がブリンクしているのか?

右図は移動中の様子だが、ゴミを残しながら移動しているのだ。
移動のアニメーションが終わると再描画が走るようで、ちゃんとなる。
なるけど、やはり移動中も見えてほしくないですな。。。

現在対処中なので、何かわかったら書こう。


AnimationDrawableを止めてTranslateAnimationだけでもゴミが残った。
ブリンクの方はなさそうである。

TranslateとDrawableの開始順序を入れ替えてみたけど、関係なし。


解決その1

右図の現象、足跡が残る件がなんとかなった。
PNG画像の端っこまで画像を描いていたので、1pixだけ削ってみたのだ。
そうすると、残らなくなった。

けどさ・・・なんか納得はできない。
Tipsってやつなのか?
invalidateの領域判定が1pix小さいってことなのだろうか。

Javaの座標って、確かピクセルとピクセルの間を数える、みたいなのを大昔勉強したときに読んだような気がする。AWTの勉強だったか。
探したけど、見つからん・・・。
(sx, sy)-(ex, ey)で直線を引くと、終点は(ex-1, ey-1)までしか描画されない、とかそんな内容だったような。

試しに、1pixの真四角をアニメーションで移動させてみた。
予想通り、右側と下側の線が消え残っている。

というわけで、アニメーションさせる場合は、画像の右端と下側は1pix残しておくようにするのが無難、としておこう。


残件

TranslateAnimationとAnimationDrawableの組み合わせ問題が残っている。
書いていなかったが、実はTranslateAnimationで移動中、黒い塗りつぶしが広がっているのだ。
これはおそらく、

・TranslateAnimationは移動している領域のinvalidate領域を設定
・AnimationDrawableは移動していない領域(すなわち左上の原点付近)のinvalidate領域を設定
・領域がORされて、黒い塗りつぶしが広がっている
・AnimationDrawableは描画位置を左上と認識しているがTranslateAnimationによって移動されていて実際には描画するものがないため、黒いブリンクになっている。

ということではなかろうか。

そうなると、AnimationDrawableはTranslateAnimationと組み合わせられないことになってしまう。
なぜなら、TranslateAnimationは自動的に(勝手に)フレームワークがアニメーションさせることになっているからだ。
残念だなぁ。

android.view.animationの系列は、視覚効果的なものに使い、キャラクターを動かしたいというような目的では使わない方がよさそうですな。
手抜きができればよい、というところだったので、納得して使うのをやめよう。

続きを読む "アニメーションでゴミが残る" »

2010/02/19

Android1.6ではonClickListenerがこう書ける

備忘録だ。

以前に読むだけ読んで、記憶にはあったけど何のことか忘れていた変更点。


Android1.6からは、XMLのレイアウトファイルに

<Button android:onClick="myClickHandler" />

などと書いておくと、ソース上で

class MyActivity extends Activity {
public void myClickHandler(View target) {
// やること
}
}

書くことができる

GUIのエディタはここまで吐きだしてくれるかしら?

2010/02/13

アニメーション中の座標はたぶん取得できない

前回の続きだ。

あれこれ調べているものの、情報がない。
それに、APIもそれっぽいのがない。
clearAnimation()させても変なところで終わるし。

で、ようやくそれっぽい記述を見つけた。
Android Developpersの、Viewクラスに関するReference
Animationの項に説明がある。

When an animation is started, the framework will take care of redrawing the appropriate views until the animation completes.

アニメーションが開始したら、フレームワークは完了するまで再描画し続ける、といったところか。再描画の面倒を見る、とか。
フレームワークが面倒を見るのだから、アプリではたぶん手が出せないよなぁ。
そういう解釈をした。

まあ、気が向いたらソースファイルを眺めてみよう。
「気が向いたら」と書くときは、あまり気が向かないことが多いのだが・・・。

2010/02/10

アニメーション中の座標を取得したい

またしてもアプリ関係だ。
どうしたんだ、私・・・。

まあ、解決していないので問題提起だけだ。


タッチパネルをタッチさせると、タッチした座標に画像を表示させようとした。
ただ表示させても寂しいので、アニメーションでじりじりと移動させようとしている。

タッチイベントを拾うのは簡単。
タッチした座標まで移動させるのも、TranslateAnimationみたいなのを使って移動させられる。
アニメーション後に座標を元に戻すか留まらせるかも、指定できる。

が、アニメーションしている間はどうすることもできない。
例えば、ボタンをアニメーションして移動させても、移動中のボタンは押しても反応しない。
記憶によると、移動前の座標にまだあると判断していたと思う(これも設定次第かもしれん)。

今回、ボタンみたいに押して動作させたいというのはない。
ないのだが、移動中の画像をタッチしたときに止めたいのだ。
そしてその位置からタッチした場所に向かうよう方向転換させたい。

させたいのだが、よくわからん。
作戦を休みに練ろう。
そして今日は寝よう。

2010/02/07

画面サイズとアプリ

実家に帰っている間、ごにょごにょとSupporting Multiple Screensを読んでいた。
ネット環境がないと仕事がはかどりませんなぁ。
幸い、英和辞典があったので助かった。
やはり、紙の媒体も置いておかないと、いざというときに不安だ。

最初に言っておくが、これは私が読んだものなので、正確さには欠けていると思う。
自分で読んでほしい。


用語

  • スクリーンサイズ(Screen size)
  • アスペクト比(Aspect ratio)
  • 解像度(Resolution)
  • 密度(Density)
  • DIP(Density Independent Pixel)

スクリーンサイズは、画面の対角線の物理的な長さ。
これは、large、normal、smallに分類する。
largeは5インチくらい、normalは3~4インチくらい、smallは2.5~3インチくらい。

アスペクト比は、longとnot long。
これは長方形か正方形か、という意味か?

解像度は、width x heightのピクセル値。
しかし、Androidアプリは解像度では動かない・・・という訳でいいのか。
  appli do not work directly with resolution。

密度は、ピクセル密度などと書いた方がわかりよいのかな。
以下densityと書きます。
同じ面積でも、densityが低ければピクセル数は少なくなるし、高ければ多くなる。
UI部品の大きさをピクセルで指定すると、densityによって見栄えが変わってくる。
これは、high(hdpi)、medium(mdpi)、low(ldpi)に分類する。
highは240dpi、mediumは160dpi、lowは120dpi。

Android1.5までは、スクリーンサイズ3.2インチ、解像度HVGA(320x480)、をベースとしている。
分類で言えば、normal-mdpi。


単位として、dipというものがある。
上に書いている、Density Independent Pixel、つまり密度非依存ピクセル。
ピクセル値を直接指定すると、端末によって見栄えが変わってしまう。
それをDIPで指定することで、システム側にうまくやってもらおうということだ。

dipの基準は、normal-mdpi。
もし320dpiの環境で動かしたら、2x2=4倍のピクセル数が必要になる。
ということだろう。


で、だ。

結局のところ1.5で作ったアプリをどうしたらいいんだろう?
それは、最初に書いたURLの「Strategies for Legacy Applications」に書いてある。
読んでないけど。

今のところは、その手前まで何となく把握しているつもり。
マルチ対応とリソースの関係について。


訳に自信がないので、そのつもりで。

まず、端末のdensityを元にしてアプリのリソースを自動的に選択し、スケーリングせずに画面表示させようとする。
スケーリングする、というのは、拡大縮小のことだろう。
当てはまるリソースがないならば、デフォルトのリソースを読み込んで、現在の画面の汎用的なdensityでスケーリングしようとする。
デフォルトのリソースは、densityがmediumとして考える。

これが「1. Pre-scaling of resources(such as image asserts)」の部分。
続いて「2. Auto-scaling of pixel dimensions and coordinates」があり、最後に「3. Compatibility-mode display on larger screen-sizes」となる。

pixel dimensions、は何だろう。
次元、と訳すと変なので、寸法、なのか。
densityによる計算をしたらピクセルの大きさが出てくるので、そのことだろうか。

例が書いてあるので、いつか訳したいところだ。


アプリが複数サイズの画面に対応するかどうかは、AndroidのバージョンとManifestファイルによって決まるようだ(リソースもあるけど)。

Manifestファイルに<supports-screens>を置き、そこに「android:smallScreens="true"」などと書いていくことで、対応するかしないかが決まる。

「android:xxxxScreens」は、small、normal、largeの3つ。
デフォルト値は、Android1.5までは全部false。それ以降は全部true。
あ、全部falseと書いたが、normalはtrue。
このパラメータがtrueだとその画面サイズをサポートする、つまり表示させようとすることになる。
Android 1.5以前では、デフォルトでnormalのみtrueとなるので、大きい画面要アプリだと表示されないことがあるのだろうか。
でも、SmartQ5は4.3インチでWVGAなので、large-hdpiに相当しそうな気がする。4.3なので、ぎりぎりnormal-hdpiかもしれんが。

表を見る感じでは、これからはnormalでmdpiとhdpiに対応するといいんではなかろうか。
ターゲットが決まっているのなら、そのリソースだけ用意すればいいと思う。
デフォルトのリソースさえ用意しておけば、少なくとも表示されないことはないだろう。


サンプルを見ている感じからすると、

  • layoutはport(縦長)とland(横長)
  • drawableはmdpiとhdpi

としておけばいいんでないかしら。
共通で使えるものは、デフォルトリソースへ。