2012年12月28日金曜日

drawable.xmlで遊んでみる #androidadvent2012

これはAndroid Advent Calendar 2012の12月28日<表>のエントリです。

@kinnekoさんの<裏>記事もどうぞ。
Supersonicで自前のGoogleMusicを実現する http://d.hatena.ne.jp/kinneko/20121228/p1



こんにちは。最近、公私共に全然Androidの開発やってない@mstsskです。

昨年のAndroid Advent Calendar 2011では、先にJPPの太鼓持ちjsonというテーマを決めていたので、「Androidアプリで使えるJSONライブラリ比較」という記事を書きました。

ですが、今回は記事に出来るような事がなーんにもない状態で、勢いでAdvent Calendarに参加を決めちゃいました。

ううむ。どうしよう…

そうだ! Androidと言えば、drawableがある。Shape Drawableを使えば、画像ファイルを用意せずともxmlの記述だけで画面解像度に依存しない図形を描画できる。 #小芝居
でも、描けるのはあくまでも簡単な図形だけらしい… そこで、drawable.xmlで絵が描けるか試してみました。


ドロイド君を drawable.xml だけで描いてみた



はい。読み飛ばした方、こんにちは。

いかかでしょうか。ドロイド君くらいならxmlの記述だけで描けてしまいます。
colors.xmlだけは作りましたが、1ソースで済ませるという縛りでやってみたので大分冗長になっちゃってるのはご愛嬌。
まぁ、ちゃんと分けたとしてもあまり綺麗にはならなそうだったというのもありますけど。




ふー。終わった終わった。これで肩の荷が降りたわー。あー良かった。

ん。そういえば、他にも同じ事やってる人いたりしないよな… まさかな…


………………

[drawable ドロイド君][検索]

…………

検索結果に…

……

XML Drawable onlyでドロイド君を描いてみた - ReDo



だだ被りじゃねぇか!!!!! ( Д ) ゜ ゜

XML Drawable onlyでドロイド君を描いてみた http://greety.sakura.ne.jp/redo/2011/12/xml-drawable-only.html via @youten_redo

しかも、Advent Calender主催者の、Advent Calender関係ない、1年も前のエントリと。


このままじゃヤバい。ヤクい。これは、何かしら差別化しないと…

そうだ! 以前にやったこれをdrawable.xmlでやってみたらどうだろう!


というわけで↓

わかめねこを drawable.xml だけで描いてみた


はい、結局いつものネタに走りました。
drawable.xmlになってもわかめねこのプリチーさは変わりませんね。



解説のようなもの

めんどくさい満足したので、これで終わりにしてもいいんですが、一応解説。

viewを内包せず、全部1つのdrawable.xmlの中でshapeで済ませるにあたって、ミソになったのが以下
  1. layer-listのitemの子要素として直接shapeを書ける
  2. 最も外側のitemを基準にしたpaddingによる相対的なサイズ・位置の指定
  3. itemとshapeの間にrotate要素を入れて回転を設定
  4. ovalのshapeはstrokeのdashGap,dashWidthを調整すれば円弧が描ける


layer-listのitemの子要素として直接shapeを書ける


item要素のandroid:drawable属性で別ファイルのdrawableを指定しなくても、子要素としてshapeを記述できます。


最も外側のitem要素を基準にしたpaddingによる相対的なサイズ・位置の指定


item要素のandroid:top,bottom,left,rightの各属性は、各辺ごとに一番外側の部分からの距離(padding)を指定します。
そこで、適当なsize指定をしたitem要素を外枠として、その内側に収まるように他のitem要素のpaddingを記述して位置や大きさを指定しました。
各itemのpaddingを、外枠にしたitem要素のsizeより大きくなるようにしてしまったり、item要素の大きさが負になるようなpadding指定をしてしまうと、全部のitemが思っきり崩れます。

これは、ソースからドロイド君の胴体部分と外枠部分の記述だけを抜き出したものです。


itemとshapeの間にrotate要素を入れて回転を設定


shapeを回転させるには、item要素の直下にshape要素を置かずに、 item → rotate → shape という具合にrotate要素を挟み、その属性で回転角度・回転軸(pivot)を指定します。


ovalのshapeはstrokeのdashGap,dashWidthを調整すれば円弧が描ける


shapeは本来は、矩形・丸・線・円の4つの簡単な図形しか描けませんが、無理やり円弧を描くこともできます。
stroke要素のdashGap属性,dashWidth属性の記述によって、ある程度は円の切れ方を指定できるので、それを利用します。

これは、わかめねこの鼻の部分のソースです。
2つの円弧をずらして配置し「ω」という形にしています。

これらの手段を組み合わせれば、わかめねこの様なイラストもdrawable.xmlで描けてしまう、という訳です。


Gingerbread以前では?

ちなみに、これらのコードはICS以降向けです。
Gingerbread以前のバージョンでも動きますが、rotate指定の回転の基準点が全く違う箇所になる様で、rotateを使っているshapeがずれてしまいます。※ Honeycombで試してない(てへぺろ


上記はレイアウトエディタのスクリーンショットですが実機でも同じ様な表示となります。
左アンテナは上にずれ、右アンテナは下にずれて胴体の下に隠れてしまっています(マウスカーソルのある辺りにあります)。

ちゃんと確認してはいないんですが、どうやら以下のような違いがあるのでは、と考えています。
ICS以降
paddingの内側の描画されている範囲の左上が回転軸の基点
Gingerbread以前
paddingの外側の一番大きい要素の左上が回転軸の基点



まとめ

勢いだけで、大分役に立たない記事と相成りました。

ただ、png画像など用意せずにxmlの記述だけでもここまで描けるというのがわかっていただけと思うので、今後アプリを作ったりデザインしたりする方々には是非覚えておいていただきたいです。上手く使えば様々な画面解像度への対応が捗るんではないでしょうか。今後もハードウェアの技術向上は続きますから、HTC J butterflyのxxhdpiみたいなショックが来るかも知れませんからね。

「Androidもうええねん」なんて声も聞こえますが、まだまだAndroidは続きますよ!
オレはようやくのぼりはじめたばかりだからな。このはてしなく遠いAndroid坂をよ…

さて、明日は @awwa500 さんと @takke さんの担当です。
何故か新年までカウントしていくAndroid Advent Calender 2012。どうぞ大晦日の大トリ記事までよろしくお願いします。



今回作ったもの