こんにちは。TechBoosterのメンバーのひとり、ふるしんです。
Android Advent Calendar
このエントリは、Android Advent Calendar 2011という企画の裏エントリです。
毎日1人ずつAndroid関係の記事を書いていく、というものです。
他にもたくさん面白い記事があるので、是非読んでみてくださいね。
みんなのクオリティがめちゃくちゃ高くてgkbr…
本題
さて、ここからが本題
私事ですが、11月12日に、Androidアプリ「ディズニー待ち時間」をリリースしました。
午前3時半にリリースしたから、実質11日ってなってるんですよ。
ということで、これからは11月11日は
「ポッキーとプリッツとディズニー待ち時間の日」
ってことにしましょう。えぇ。そうしましょう。
さて。
まず、このアプリを開発する事になった経緯から。
ボクはディズニーが大好きです。
えぇ。2日分6度の飯よりディズニーが好き。
ミッキーさんって稀に呼ばれます。
けど一番好きなキャラクターはドナルドです。
ミニーちゃん可愛いです。
で、だ。
ボクは、ディズニーが好きだ。
ボクは、Androidも好きだ。
そこで、だ。
ディズニー好き && Android好き
そんな人はなかなか居ないでしょう。
Answer:ボクがディズニーのアプリ作っちゃえばいいじゃないですか。
Android Advent Calendarのエントリーのひとつで、@gabu さんの記事が、本当にリアルタイムでぴったりな内容でした。
きっと不便を便利にするためにコードを書き始めた僕たちへ
先日、ディズニーへ友達と一緒に遊びに行った時の会話
ふるしん「正確な待ち時間を表示するアプリ無いの?」
友人「無いよ、超不便だよ、作れる?」
ふるしん「おうよ」
はい。それでできました。ディズニー待ち時間
今日現在では、ついに7万DL超えてます。本当にありがとうございます。
ここでは、ディズニー待ち時間を開発するに使った、けどめんどくさかったコードを幾つか紹介しようと思います。
1.AlertDialogを次々に重ねる
AlertDialogとは、なんか、あのーあれ、ピョコンッって出てくる箱みたいなん。
TechBoosterでも紹介してます。こちらも御覧ください
ダイアログを表示する / Getting Started
で、そんな事できんの?
って思いながらも実験
できなくはないです。
けど何度か同じ動作をすると落ちる。なるほど。
なるほどわからん。
やり方がイマイチわからなくて悩んでたら、@crimsonwoods様が助けて下さいました。
教えてくださったサイトはこちら
[TIPS]アクティビティの見た目をダイアログにする方法
なるほど、ただのActivityをDialogのように表示することができるんですね。
具体的にはイカのようにするようです。
■AndroidManifest.xml
<activity android:name=".ShowMap" android:theme="@android:style/Theme.Dialog" > </activity>
このように、マニフェストにActivityを登録する際にandroid:theme=”@android:style/Theme.Dialog”とやってあげるだけで、簡単にActivityをDialogとして表示することが可能のようです。
Dialogとして表示するように作成されたActivityを呼び出すには、普段Activityを呼び出す方法と同様にIntentを使います。
イカのような感じですね。
■src/MainActivity.java
Intent intent = new Intent(); intent.setClassName( "com.furusin.www.volunteer.disney.disneywaittime", "com.furusin.www.volunteer.disney.disneywaittime.ShowMap"); startActivity(intent);
IntentについてはTechBoosterの記事をご参考に。
Intentで画面遷移する(明示的Intent)/Getting started
上記コードは、ディズニーの各エリアを表示するために作ったActicity(ShowMap.java)を呼び出す部分です。
本当に、普通にIntentを使ったstartActivityをやってあげるだけ。
アプリ内ではこんな感じで動いてます。
非常に簡単にできました。
2.ExpandableListViewのカスタマイズ
ExpandableListViewとは、なんか、あのーあれ、ただのリストではなく、属性ごとに分けてミョーンと展開ができるリストのことです。
TechBoosterでも使い方を紹介していますので、是非御覧ください。
ExpandableListViewクラスで折り畳めるリストを表示する
ExpandableListViewクラスの表示をカスタマイズする
こいつがなかなか厄介。
Mapを使ったらいいらしいんですが、そもそもMapが理解出来てない。
で、色々と調べました。
結局、Mapの1つ目の要素に当たるものをString[]で、2つ目の要素をString[][]で宣言して作っちゃいました。
上記画像のようにカスタマイズしたかったので、独自クラスを作っちゃいました。
重要なクラスはイカのものです。
■src/MyExpandableListAdapter.java
public class MyExpandableListAdapter extends BaseExpandableListAdapter { // Sample data set. children[i] contains the children (String[]) for // groups[i]. private LayoutInflater layoutInflater_; private String[] parent; private String[][][] children; private int id = 0; Context context; public MyExpandableListAdapter(Context cxt, String[] parentID, String[][][] childID, int ID) { //コンストラクタ id = ID; parent = parentID; children = childID; context = cxt; layoutInflater_ = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); } public String getChild(int groupPosition, int childPosition) { //子要素を返す return children[groupPosition][childPosition][0]; } public long getChildId(int groupPosition, int childPosition) { //子要素のIDを返す return childPosition; } public int getChildrenCount(int groupPosition) { //子要素の数を返す return children[groupPosition].length; } public LinearLayout getGenericView() { //親要素のLayoutを返す LinearLayout layout = new LinearLayout(context); return layout; } public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { // convertViewは使い回しされている可能性があるのでnullの時だけ新しく作る if (null == convertView) { convertView = layoutInflater_.inflate(R.layout.expandchildview, null); } LinearLayout layout = (LinearLayout)convertView.findViewById(R.id.expandChildLayout); //子要素のViewを決める処理 } return convertView; } public Object getGroup(int groupPosition) { //リストのグループを返す return parent[groupPosition]; } public int getGroupCount() { //リストのグループの数を返す return parent.length; } public long getGroupId(int groupPosition) { //グループのIDを返す return groupPosition; } public View getGroupView(int groupPosition, boolean isExpanded, //グループのViewを返す View convertView, ViewGroup parent) { //グループのViewを作る処理 return layout; } public boolean isChildSelectable(int groupPosition, int childPosition) { return true; } public boolean hasStableIds() { return true; } }
ソースコードが長くなっちゃってごめんなさい。
重要なのは、色が変わっている37, 49, 84行目です。
37行目のgetGenericView()でグループのレイアウトの土台を生成し、
72行目のgetGroupView()でグループのレイアウトの中身を作っています。
そして、42行目のgetChildView()でグループの子要素のレイアウトを作っています。
ここがなかなか理解にしくくて、各関数の頭にLog.d()を入れまくりました。
大変でした…
上記コードで作った独自Adapterを、ActivityでExpandableListViewにセットしてあげるだけです。
具体的にはイカのようにします。
■src/MainActivity.java
MyExpandableListAdapter mAdapter = new MyExpandableListAdapter( context, area_name, attrs, 0); ExpandableListView lv = (ExpandableListView) findViewById(R.id.expandableListView1); lv.setAdapter(mAdapter);
これだけ。本当に普通にセットするだけ。
苦労した場所はもっともっとたくさんありますが、書き切れないのでここらへんで止めておきましょう。
以上、「シェフのアプリ開発秘話~技術的要素を添えて~」でした。
最後に
このアプリのアイコンをデザインしてくださった@xxxmako さん、本当に可愛いアイコンを作っていただきありがとうございました!
本当に可愛いんですよねこれ…
もうこのデザインとなら心中してもいいくらい。しないけど。
また、Android Advent Calendarで記事を書く、という非常に貴重な経験をくださった@youten_redo さん、ありがとうございました。
皆さま、これからも「変態多きAndroider達」を生温かい目で見守ってあげてください。