@kinnekoさんの<裏>記事もどうぞ。
Supersonicで自前のGoogleMusicを実現する http://d.hatena.ne.jp/kinneko/20121228/p1
こんにちは。最近、公私共に全然Androidの開発やってない@mstsskです。
昨年のAndroid Advent Calendar 2011では、先に
ですが、今回は記事に出来るような事がなーんにもない状態で、勢いでAdvent Calendarに参加を決めちゃいました。
ううむ。どうしよう…
そうだ! Androidと言えば、drawableがある。Shape Drawableを使えば、画像ファイルを用意せずともxmlの記述だけで画面解像度に依存しない図形を描画できる。 #小芝居
でも、描けるのはあくまでも簡単な図形だけらしい… そこで、drawable.xmlで絵が描けるか試してみました。
ドロイド君を drawable.xml だけで描いてみた
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" > | |
<!-- for Android 4.0 or above --> | |
<!-- left antenna's stroke --> | |
<item | |
android:bottom="350dp" | |
android:left="85dp" | |
android:right="248dp" | |
android:top="0dp"> | |
<rotate | |
android:fromDegrees="-30" | |
android:pivotX="80%" | |
android:pivotY="0%" | |
android:toDegrees="00" > | |
<shape android:shape="rectangle" > | |
<solid android:color="@android:color/white" /> | |
<corners android:radius="50dp" /> | |
</shape> | |
</rotate> | |
</item> | |
<!-- right antenna's stroke --> | |
<item | |
android:bottom="350dp" | |
android:left="248dp" | |
android:right="85dp" | |
android:top="0dp"> | |
<rotate | |
android:fromDegrees="30" | |
android:pivotX="20%" | |
android:pivotY="0%" | |
android:toDegrees="00" > | |
<shape android:shape="rectangle" > | |
<solid android:color="@android:color/white" /> | |
<corners android:radius="50dp" /> | |
</shape> | |
</rotate> | |
</item> | |
<!-- head --> | |
<item | |
android:bottom="160dp" | |
android:left="60dp" | |
android:right="60dp" | |
android:top="25dp"> | |
<shape android:shape="oval" > | |
<solid android:color="@color/android" /> | |
<stroke | |
android:width="10dp" | |
android:color="@android:color/white" /> | |
</shape> | |
</item> | |
<!-- left antenna --> | |
<item | |
android:bottom="360dp" | |
android:left="100dp" | |
android:right="253dp" | |
android:top="10dp"> | |
<rotate | |
android:fromDegrees="-30" | |
android:pivotX="80%" | |
android:pivotY="0%" | |
android:toDegrees="0" > | |
<shape android:shape="rectangle" > | |
<solid android:color="@color/android" /> | |
<corners android:radius="50dp" /> | |
</shape> | |
</rotate> | |
</item> | |
<!-- right antenna --> | |
<item | |
android:bottom="360dp" | |
android:left="253dp" | |
android:right="100dp" | |
android:top="10dp"> | |
<rotate | |
android:fromDegrees="30" | |
android:pivotX="20%" | |
android:pivotY="0%" | |
android:toDegrees="0" > | |
<shape android:shape="rectangle" > | |
<solid android:color="@color/android" /> | |
<corners android:radius="50dp" /> | |
</shape> | |
</rotate> | |
</item> | |
<!-- left eye --> | |
<item | |
android:bottom="327dp" | |
android:left="120dp" | |
android:right="222dp" | |
android:top="76dp"> | |
<shape android:shape="oval" > | |
<solid android:color="@android:color/white" /> | |
</shape> | |
</item> | |
<!-- right eye --> | |
<item | |
android:bottom="327dp" | |
android:left="222dp" | |
android:right="120dp" | |
android:top="76dp"> | |
<shape android:shape="oval" > | |
<solid android:color="@android:color/white" /> | |
</shape> | |
</item> | |
<!-- left leg's stroke --> | |
<item | |
android:bottom="0dp" | |
android:left="104dp" | |
android:right="188dp" | |
android:top="300dp"> | |
<shape android:shape="rectangle" > | |
<solid android:color="@android:color/white" /> | |
<corners android:radius="50dp" /> | |
</shape> | |
</item> | |
<!-- right leg's stroke --> | |
<item | |
android:bottom="0dp" | |
android:left="188dp" | |
android:right="104dp" | |
android:top="300dp"> | |
<shape android:shape="rectangle" > | |
<solid android:color="@android:color/white" /> | |
<corners android:radius="50dp" /> | |
</shape> | |
</item> | |
<!-- body --> | |
<item | |
android:bottom="82dp" | |
android:left="60dp" | |
android:right="60dp" | |
android:top="136dp"> | |
<shape android:shape="rectangle" > | |
<solid android:color="@color/android" /> | |
<stroke | |
android:width="10dp" | |
android:color="@android:color/white" /> | |
<corners | |
android:bottomLeftRadius="22dp" | |
android:bottomRightRadius="22dp" /> | |
<!-- android:radius="50dp" --> | |
</shape> | |
</item> | |
<!-- left arm --> | |
<item | |
android:bottom="119dp" | |
android:left="0dp" | |
android:right="291dp" | |
android:top="130dp"> | |
<shape android:shape="rectangle" > | |
<solid android:color="@color/android" /> | |
<stroke | |
android:width="10dp" | |
android:color="@android:color/white" /> | |
<corners android:radius="50dp" /> | |
</shape> | |
</item> | |
<!-- right arm --> | |
<item | |
android:bottom="119dp" | |
android:left="291dp" | |
android:right="0dp" | |
android:top="130dp"> | |
<shape android:shape="rectangle" > | |
<solid android:color="@color/android" /> | |
<stroke | |
android:width="10dp" | |
android:color="@android:color/white" /> | |
<corners android:radius="50dp" /> | |
</shape> | |
</item> | |
<!-- left leg --> | |
<item | |
android:bottom="10dp" | |
android:left="114dp" | |
android:right="198dp" | |
android:top="300dp"> | |
<shape android:shape="rectangle" > | |
<solid android:color="@color/android" /> | |
<corners android:radius="50dp" /> | |
</shape> | |
</item> | |
<!-- right leg --> | |
<item | |
android:bottom="10dp" | |
android:left="198dp" | |
android:right="114dp" | |
android:top="300dp"> | |
<shape android:shape="rectangle" > | |
<solid android:color="@color/android" /> | |
<corners android:radius="50dp" /> | |
</shape> | |
</item> | |
<!-- base --> | |
<item> | |
<shape android:shape="rectangle" > | |
<solid android:color="@android:color/transparent" /> | |
<!-- | |
<stroke | |
android:width="1dp" | |
android:color="@android:color/background_light" /> | |
--> | |
<size | |
android:height="422dp" | |
android:width="360dp" /> | |
</shape> | |
</item> | |
</layer-list> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<resources> | |
<color name="android">#ffa4c639</color> | |
</resources> |
はい。読み飛ばした方、こんにちは。
いかかでしょうか。ドロイド君くらいならxmlの記述だけで描けてしまいます。
colors.xmlだけは作りましたが、1ソースで済ませるという縛りでやってみたので大分冗長になっちゃってるのはご愛嬌。
まぁ、ちゃんと分けたとしてもあまり綺麗にはならなそうだったというのもありますけど。
ふー。終わった終わった。これで肩の荷が降りたわー。あー良かった。
ん。そういえば、他にも同じ事やってる人いたりしないよな… まさかな…
………………
…………
……
…
だだ被りじゃねぇか!!!!! ( Д ) ゜ ゜
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 だけで描いてみた
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" > | |
<!-- for Android 4.0 or above --> | |
<!-- left leg --> | |
<item | |
android:bottom="0dp" | |
android:left="100dp" | |
android:right="160dp" | |
android:top="313dp"> | |
<shape android:shape="rectangle" > | |
<gradient | |
android:angle="90" | |
android:endColor="@color/vvakame_yellow" | |
android:startColor="@color/vvakame_orange" /> | |
<stroke | |
android:width="10dp" | |
android:color="@android:color/black" /> | |
<corners | |
android:bottomLeftRadius="20dp" | |
android:bottomRightRadius="20dp" | |
android:topLeftRadius="150dp" | |
android:topRightRadius="150dp" /> | |
</shape> | |
</item> | |
<!-- right leg --> | |
<item | |
android:bottom="0dp" | |
android:left="150dp" | |
android:right="110dp" | |
android:top="313dp"> | |
<shape android:shape="rectangle" > | |
<gradient | |
android:angle="90" | |
android:endColor="@color/vvakame_yellow" | |
android:startColor="@color/vvakame_orange" /> | |
<stroke | |
android:width="10dp" | |
android:color="@android:color/black" /> | |
<corners | |
android:bottomLeftRadius="20dp" | |
android:bottomRightRadius="20dp" | |
android:topLeftRadius="150dp" | |
android:topRightRadius="150dp" /> | |
</shape> | |
</item> | |
<!-- tail, end --> | |
<item | |
android:bottom="240dp" | |
android:left="200dp" | |
android:right="25dp" | |
android:top="130dp"> | |
<rotate android:fromDegrees="-35" > | |
<shape android:shape="rectangle" > | |
<stroke | |
android:width="10dp" | |
android:color="@android:color/black" /> | |
<solid android:color="@color/vvakame_yellow" /> | |
<corners android:radius="30dp" /> | |
</shape> | |
</rotate> | |
</item> | |
<!-- tail, inner --> | |
<item | |
android:bottom="120dp" | |
android:left="148dp" | |
android:right="65dp" | |
android:top="160dp"> | |
<rotate android:fromDegrees="-15" > | |
<shape android:shape="rectangle" > | |
<stroke | |
android:width="15dp" | |
android:color="@color/vvakame_yellow" /> | |
<solid android:color="@android:color/transparent" /> | |
<corners android:bottomRightRadius="30dp" /> | |
</shape> | |
</rotate> | |
</item> | |
<!-- tail, stroke, inside --> | |
<item | |
android:bottom="130dp" | |
android:left="135dp" | |
android:right="78dp" | |
android:top="150dp"> | |
<rotate android:fromDegrees="-15" > | |
<shape android:shape="rectangle" > | |
<stroke | |
android:width="10dp" | |
android:color="@android:color/black" /> | |
<solid android:color="@android:color/transparent" /> | |
<corners android:bottomRightRadius="30dp" /> | |
</shape> | |
</rotate> | |
</item> | |
<!-- tail, stroke, outside --> | |
<item | |
android:bottom="110dp" | |
android:left="135dp" | |
android:right="55dp" | |
android:top="150dp"> | |
<rotate android:fromDegrees="-15" > | |
<shape android:shape="rectangle" > | |
<stroke | |
android:width="10dp" | |
android:color="@android:color/black" /> | |
<solid android:color="@android:color/transparent" /> | |
<corners android:bottomRightRadius="50dp" /> | |
</shape> | |
</rotate> | |
</item> | |
<!-- body stroke --> | |
<item | |
android:bottom="70dp" | |
android:left="100dp" | |
android:right="110dp" | |
android:top="180dp"> | |
<shape android:shape="rectangle" > | |
<gradient | |
android:angle="90" | |
android:centerColor="@color/vvakame_yellow" | |
android:endColor="@color/vvakame_yellow" | |
android:startColor="@color/vvakame_orange" /> | |
<stroke | |
android:width="10dp" | |
android:color="@android:color/black" /> | |
<corners | |
android:bottomLeftRadius="35dp" | |
android:bottomRightRadius="35dp" | |
android:topLeftRadius="150dp" | |
android:topRightRadius="150dp" /> | |
</shape> | |
</item> | |
<!-- left ear --> | |
<item | |
android:bottom="190dp" | |
android:left="45dp" | |
android:right="150dp" | |
android:top="0dp"> | |
<rotate android:fromDegrees="-10" > | |
<shape android:shape="oval" > | |
<gradient | |
android:endColor="@color/vvakame_orange" | |
android:gradientRadius="250" | |
android:startColor="@color/vvakame_yellow" | |
android:type="radial" /> | |
<stroke | |
android:width="10dp" | |
android:color="@android:color/black" /> | |
</shape> | |
</rotate> | |
</item> | |
<!-- right ear --> | |
<item | |
android:bottom="187dp" | |
android:left="135dp" | |
android:right="60dp" | |
android:top="3dp"> | |
<rotate android:fromDegrees="20" > | |
<shape android:shape="oval" > | |
<gradient | |
android:endColor="@color/vvakame_orange" | |
android:gradientRadius="250" | |
android:startColor="@color/vvakame_yellow" | |
android:type="radial" /> | |
<stroke | |
android:width="10dp" | |
android:color="@android:color/black" /> | |
</shape> | |
</rotate> | |
</item> | |
<!-- head inner --> | |
<item | |
android:bottom="185dp" | |
android:left="38dp" | |
android:right="53dp" | |
android:top="40dp"> | |
<shape android:shape="rectangle" > | |
<solid android:color="@color/vvakame_yellow" /> | |
<stroke | |
android:width="15dp" | |
android:color="@android:color/transparent" /> | |
<corners | |
android:bottomLeftRadius="135dp" | |
android:bottomRightRadius="135dp" | |
android:topLeftRadius="90dp" | |
android:topRightRadius="100dp" /> | |
</shape> | |
</item> | |
<!-- head striped pattern, top left --> | |
<item | |
android:bottom="317dp" | |
android:left="118dp" | |
android:right="168dp" | |
android:top="47dp"> | |
<rotate | |
android:fromDegrees="2" | |
android:pivotX="0%" | |
android:pivotY="0%" | |
android:toDegrees="0" > | |
<shape android:shape="rectangle" > | |
<solid android:color="@color/vvakame_orange" /> | |
<corners | |
android:bottomLeftRadius="7dp" | |
android:bottomRightRadius="7dp" | |
android:topLeftRadius="0dp" | |
android:topRightRadius="0dp" /> | |
</shape> | |
</rotate> | |
</item> | |
<!-- head striped pattern, top center --> | |
<item | |
android:bottom="316dp" | |
android:left="141dp" | |
android:right="145dp" | |
android:top="48dp"> | |
<rotate | |
android:fromDegrees="2" | |
android:pivotX="0%" | |
android:pivotY="0%" | |
android:toDegrees="0" > | |
<shape android:shape="rectangle" > | |
<solid android:color="@color/vvakame_orange" /> | |
<corners | |
android:bottomLeftRadius="7dp" | |
android:bottomRightRadius="7dp" | |
android:topLeftRadius="0dp" | |
android:topRightRadius="0dp" /> | |
</shape> | |
</rotate> | |
</item> | |
<!-- head striped pattern, top right --> | |
<item | |
android:bottom="315dp" | |
android:left="163dp" | |
android:right="124dp" | |
android:top="49dp"> | |
<rotate | |
android:fromDegrees="2" | |
android:pivotX="0%" | |
android:pivotY="0%" | |
android:toDegrees="0" > | |
<shape android:shape="rectangle" > | |
<solid android:color="@color/vvakame_orange" /> | |
<corners | |
android:bottomLeftRadius="7dp" | |
android:bottomRightRadius="7dp" | |
android:topLeftRadius="0dp" | |
android:topRightRadius="0dp" /> | |
</shape> | |
</rotate> | |
</item> | |
<!-- head striped pattern, left top --> | |
<item | |
android:bottom="290dp" | |
android:left="50dp" | |
android:right="222dp" | |
android:top="97dp"> | |
<rotate | |
android:fromDegrees="2" | |
android:pivotX="0%" | |
android:pivotY="0%" | |
android:toDegrees="0" > | |
<shape android:shape="rectangle" > | |
<solid android:color="@color/vvakame_orange" /> | |
<corners | |
android:bottomLeftRadius="0dp" | |
android:bottomRightRadius="7dp" | |
android:topLeftRadius="0dp" | |
android:topRightRadius="7dp" /> | |
</shape> | |
</rotate> | |
</item> | |
<!-- head striped pattern, left middle --> | |
<item | |
android:bottom="267dp" | |
android:left="45dp" | |
android:right="223dp" | |
android:top="120dp"> | |
<rotate | |
android:fromDegrees="2" | |
android:pivotX="0%" | |
android:pivotY="0%" | |
android:toDegrees="0" > | |
<shape android:shape="rectangle" > | |
<solid android:color="@color/vvakame_orange" /> | |
<corners | |
android:bottomLeftRadius="0dp" | |
android:bottomRightRadius="7dp" | |
android:topLeftRadius="0dp" | |
android:topRightRadius="7dp" /> | |
</shape> | |
</rotate> | |
</item> | |
<!-- head striped pattern, left bottom --> | |
<item | |
android:bottom="245dp" | |
android:left="45dp" | |
android:right="224dp" | |
android:top="142dp"> | |
<rotate | |
android:fromDegrees="2" | |
android:pivotX="0%" | |
android:pivotY="0%" | |
android:toDegrees="0" > | |
<shape android:shape="rectangle" > | |
<solid android:color="@color/vvakame_orange" /> | |
<corners | |
android:bottomLeftRadius="0dp" | |
android:bottomRightRadius="7dp" | |
android:topLeftRadius="0dp" | |
android:topRightRadius="7dp" /> | |
</shape> | |
</rotate> | |
</item> | |
<!-- head striped pattern, right top --> | |
<item | |
android:bottom="285dp" | |
android:left="209dp" | |
android:right="58dp" | |
android:top="102dp"> | |
<rotate | |
android:fromDegrees="2" | |
android:pivotX="0%" | |
android:pivotY="0%" | |
android:toDegrees="0" > | |
<shape android:shape="rectangle" > | |
<solid android:color="@color/vvakame_orange" /> | |
<corners | |
android:bottomLeftRadius="7dp" | |
android:bottomRightRadius="0dp" | |
android:topLeftRadius="7dp" | |
android:topRightRadius="0dp" /> | |
</shape> | |
</rotate> | |
</item> | |
<!-- head striped pattern, right middle --> | |
<item | |
android:bottom="262dp" | |
android:left="208dp" | |
android:right="59dp" | |
android:top="125dp"> | |
<rotate | |
android:fromDegrees="2" | |
android:pivotX="0%" | |
android:pivotY="0%" | |
android:toDegrees="0" > | |
<shape android:shape="rectangle" > | |
<solid android:color="@color/vvakame_orange" /> | |
<corners | |
android:bottomLeftRadius="7dp" | |
android:bottomRightRadius="0dp" | |
android:topLeftRadius="7dp" | |
android:topRightRadius="0dp" /> | |
</shape> | |
</rotate> | |
</item> | |
<!-- head striped pattern, right bottom --> | |
<item | |
android:bottom="240dp" | |
android:left="207dp" | |
android:right="60dp" | |
android:top="147dp"> | |
<rotate | |
android:fromDegrees="2" | |
android:pivotX="0%" | |
android:pivotY="0%" | |
android:toDegrees="0" > | |
<shape android:shape="rectangle" > | |
<solid android:color="@color/vvakame_orange" /> | |
<corners | |
android:bottomLeftRadius="7dp" | |
android:bottomRightRadius="0dp" | |
android:topLeftRadius="7dp" | |
android:topRightRadius="0dp" /> | |
</shape> | |
</rotate> | |
</item> | |
<!-- head stroke --> | |
<item | |
android:bottom="185dp" | |
android:left="38dp" | |
android:right="53dp" | |
android:top="40dp"> | |
<shape android:shape="rectangle" > | |
<solid android:color="@android:color/transparent" /> | |
<stroke | |
android:width="10dp" | |
android:color="@android:color/black" /> | |
<corners | |
android:bottomLeftRadius="135dp" | |
android:bottomRightRadius="135dp" | |
android:topLeftRadius="90dp" | |
android:topRightRadius="100dp" /> | |
</shape> | |
</item> | |
<!-- body inner --> | |
<item | |
android:bottom="70dp" | |
android:left="100dp" | |
android:right="110dp" | |
android:top="180dp"> | |
<shape android:shape="rectangle" > | |
<gradient | |
android:angle="90" | |
android:centerColor="@color/vvakame_yellow" | |
android:endColor="@color/vvakame_yellow" | |
android:startColor="@color/vvakame_orange" /> | |
<stroke | |
android:width="20dp" | |
android:color="@android:color/transparent" /> | |
<corners | |
android:bottomLeftRadius="35dp" | |
android:bottomRightRadius="35dp" | |
android:topLeftRadius="150dp" | |
android:topRightRadius="150dp" /> | |
</shape> | |
</item> | |
<!-- left eye --> | |
<item | |
android:bottom="275dp" | |
android:left="103dp" | |
android:right="187dp" | |
android:top="81dp"> | |
<rotate | |
android:fromDegrees="6" | |
android:pivotX="0%" | |
android:pivotY="0%" | |
android:toDegrees="0" > | |
<shape android:shape="rectangle" > | |
<solid android:color="@android:color/black" /> | |
<corners | |
android:bottomLeftRadius="7dp" | |
android:bottomRightRadius="7dp" | |
android:topLeftRadius="7dp" | |
android:topRightRadius="7dp" /> | |
</shape> | |
</rotate> | |
</item> | |
<!-- right eye --> | |
<item | |
android:bottom="271dp" | |
android:left="181dp" | |
android:right="109dp" | |
android:top="85dp"> | |
<rotate | |
android:fromDegrees="-3" | |
android:pivotX="0%" | |
android:pivotY="0%" | |
android:toDegrees="0" > | |
<shape android:shape="rectangle" > | |
<solid android:color="@android:color/black" /> | |
<corners | |
android:bottomLeftRadius="7dp" | |
android:bottomRightRadius="7dp" | |
android:topLeftRadius="7dp" | |
android:topRightRadius="7dp" /> | |
</shape> | |
</rotate> | |
</item> | |
<!-- nose, left --> | |
<item | |
android:bottom="247dp" | |
android:left="113dp" | |
android:right="155dp" | |
android:top="121dp"> | |
<shape android:shape="oval" > | |
<stroke | |
android:dashGap="25dp" | |
android:dashWidth="60dp" | |
android:width="5dp" | |
android:color="@android:color/black" /> | |
<solid android:color="@android:color/transparent" /> | |
</shape> | |
</item> | |
<!-- nose, right --> | |
<item | |
android:bottom="247dp" | |
android:left="140dp" | |
android:right="128dp" | |
android:top="121dp"> | |
<shape android:shape="oval" > | |
<stroke | |
android:dashGap="25dp" | |
android:dashWidth="45dp" | |
android:width="5dp" | |
android:color="@android:color/black" /> | |
<solid android:color="@android:color/transparent" /> | |
</shape> | |
</item> | |
<!-- left arm --> | |
<item | |
android:bottom="116dp" | |
android:left="31dp" | |
android:right="229dp" | |
android:top="194dp"> | |
<rotate | |
android:fromDegrees="-70" | |
android:pivotX="0%" | |
android:pivotY="0%" | |
android:toDegrees="0" > | |
<shape android:shape="rectangle" > | |
<gradient | |
android:angle="90" | |
android:endColor="@color/vvakame_orange" | |
android:startColor="@color/vvakame_yellow" /> | |
<stroke | |
android:width="10dp" | |
android:color="@android:color/black" /> | |
<corners | |
android:bottomLeftRadius="150dp" | |
android:bottomRightRadius="150dp" | |
android:topLeftRadius="10dp" | |
android:topRightRadius="10dp" /> | |
</shape> | |
</rotate> | |
</item> | |
<!-- right arm --> | |
<item | |
android:bottom="150dp" | |
android:left="249dp" | |
android:right="11dp" | |
android:top="157dp"> | |
<rotate | |
android:fromDegrees="72" | |
android:pivotX="0%" | |
android:pivotY="0%" | |
android:toDegrees="0" > | |
<shape android:shape="rectangle" > | |
<gradient | |
android:angle="90" | |
android:endColor="@color/vvakame_orange" | |
android:startColor="@color/vvakame_yellow" /> | |
<stroke | |
android:width="10dp" | |
android:color="@android:color/black" /> | |
<corners | |
android:bottomLeftRadius="150dp" | |
android:bottomRightRadius="150dp" | |
android:topLeftRadius="10dp" | |
android:topRightRadius="10dp" /> | |
</shape> | |
</rotate> | |
</item> | |
<!-- base --> | |
<item> | |
<shape android:shape="rectangle" > | |
<solid android:color="@android:color/transparent" /> | |
<!-- | |
<stroke | |
android:width="1dp" | |
android:color="@android:color/background_light" /> | |
--> | |
<size | |
android:height="400dp" | |
android:width="300dp" /> | |
</shape> | |
</item> | |
</layer-list> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<resources> | |
<color name="vvakame_yellow">#fffff568</color> | |
<color name="vvakame_orange">#fff7941e</color> | |
</resources> |
はい、結局いつものネタに走りました。
drawable.xmlになってもわかめねこのプリチーさは変わりませんね。
解説のようなもの
viewを内包せず、全部1つのdrawable.xmlの中でshapeで済ませるにあたって、ミソになったのが以下
- layer-listのitemの子要素として直接shapeを書ける
- 最も外側のitemを基準にしたpaddingによる相対的なサイズ・位置の指定
- itemとshapeの間にrotate要素を入れて回転を設定
- ovalのshapeはstrokeのdashGap,dashWidthを調整すれば円弧が描ける
layer-listのitemの子要素として直接shapeを書ける
item要素のandroid:drawable属性で別ファイルのdrawableを指定しなくても、子要素としてshapeを記述できます。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> | |
<item> | |
<shape android:shape="rectangle"> | |
<solid android:color="@android:color/black"> | |
<size android:height="480dp" android:width="360dp"> | |
</size></solid></shape> | |
</item> | |
</layer-list> |
最も外側のitem要素を基準にしたpaddingによる相対的なサイズ・位置の指定
item要素のandroid:top,bottom,left,rightの各属性は、各辺ごとに一番外側の部分からの距離(padding)を指定します。
そこで、適当なsize指定をしたitem要素を外枠として、その内側に収まるように他のitem要素のpaddingを記述して位置や大きさを指定しました。
各itemのpaddingを、外枠にしたitem要素のsizeより大きくなるようにしてしまったり、item要素の大きさが負になるようなpadding指定をしてしまうと、全部のitemが思っきり崩れます。
これは、ソースからドロイド君の胴体部分と外枠部分の記述だけを抜き出したものです。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" > | |
... 胴体の下に置きたい要素 ... | |
<!-- body(ドロイド君の胴体): 外枠からのtop,bottom,left,rightを記述して位置・大きさを指定 --> | |
<item | |
android:bottom="82dp" | |
android:left="60dp" | |
android:right="60dp" | |
android:top="136dp"> | |
<shape android:shape="rectangle" > | |
<solid android:color="@color/android" /> | |
<stroke | |
android:width="10dp" | |
android:color="@android:color/white" /> | |
<corners | |
android:bottomLeftRadius="22dp" | |
android:bottomRightRadius="22dp" /> | |
<!-- top,bottom,left,rightが優先されるらしく、ここではsizeは意味がない --> | |
</shape> | |
</item> | |
... 胴体の上に置きたい要素 ... | |
<!-- base(外枠のための要素): sizeを指定して外枠を定義 --> | |
<item> | |
<shape android:shape="rectangle" > | |
<solid android:color="@android:color/transparent" /> | |
<size | |
android:height="422dp" | |
android:width="360dp" /> | |
</shape> | |
</item> | |
</layer-list> |
itemとshapeの間にrotate要素を入れて回転を設定
shapeを回転させるには、item要素の直下にshape要素を置かずに、 item → rotate → shape という具合にrotate要素を挟み、その属性で回転角度・回転軸(pivot)を指定します。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> | |
<!-- left antenna's stroke --> | |
<item | |
android:bottom="350dp" | |
android:left="85dp" | |
android:right="248dp" | |
android:top="0dp"> | |
<rotate | |
android:fromDegrees="-30" | |
android:pivotX="80%" | |
android:pivotY="0%" | |
android:toDegrees="00" > <!-- toDegreesはここでは意味がない --> | |
<shape android:shape="rectangle" > | |
<solid android:color="@android:color/white" /> | |
<corners android:radius="50dp" /> | |
</shape> | |
</rotate> | |
</item> | |
... その他のitem要素 ... | |
</layer-list> |
ovalのshapeはstrokeのdashGap,dashWidthを調整すれば円弧が描ける
shapeは本来は、矩形・丸・線・円の4つの簡単な図形しか描けませんが、無理やり円弧を描くこともできます。
stroke要素のdashGap属性,dashWidth属性の記述によって、ある程度は円の切れ方を指定できるので、それを利用します。
これは、わかめねこの鼻の部分のソースです。
2つの円弧をずらして配置し「ω」という形にしています。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> | |
... その他のitem要素 ... | |
<!-- nose, left --> | |
<item | |
android:bottom="247dp" | |
android:left="113dp" | |
android:right="155dp" | |
android:top="121dp"> | |
<shape android:shape="oval" > | |
<stroke | |
android:dashGap="25dp" | |
android:dashWidth="60dp" | |
android:width="5dp" | |
android:color="@android:color/black" /> | |
<solid android:color="@android:color/transparent" /> | |
</shape> | |
</item> | |
<!-- nose, right --> | |
<item | |
android:bottom="247dp" | |
android:left="140dp" | |
android:right="128dp" | |
android:top="121dp"> | |
<shape android:shape="oval" > | |
<stroke | |
android:dashGap="25dp" | |
android:dashWidth="45dp" | |
android:width="5dp" | |
android:color="@android:color/black" /> | |
<solid android:color="@android:color/transparent" /> | |
</shape> | |
</item> | |
... その他のitem要素 ... | |
</layer-list> |
これらの手段を組み合わせれば、わかめねこの様なイラストも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。どうぞ大晦日の大トリ記事までよろしくお願いします。
今回作ったもの
- mstssk/FunnyDrawables · GitHub https://github.com/mstssk/FunnyDrawables
- ↑のapk: http://dl.dropbox.com/u/4584093/apps/FunnyDrawables.apk