2011年12月25日日曜日

「Zusaar プラグイン for twicca」の作り方


twiccaプラグインとして「Zusaar プラグイン for twicca」を作ったのでその備忘録。

Zusaar プラグイン for twicca - Android マーケットのアプリ
<https://market.android.com/details?id=com.miquniqu.android.twiccaplugins.zusaar>

現時点で一通りやりたいことは実装したのでここでまとめておきます。
基本的にネットで収集した情報のみで作れますので、たいしたことは書けません。

■作ってみての感想

いつか作ってみようと思っていたtwiccaプラグインですが、ネタが振ってきて作るぞと思ってから実働半日ぐらいで作れました。(これでもプロからしたら時間がかかっているでしょう、、

プラグイン作ってみてようやくAndroidすげー、インテントの仕組みが簡単便利!って思いました。
(もちろんtwiccaのプラグイン仕様策定が絶妙なのでしょうね。)

Android開発初心者さんはHello Worldとか表示するより、Hello "ScreenName" twicca Worldとか作ったほうがIntentの便利さがわかっていいんじゃないでしょうか。

■参考にしたカッコイイサイトの皆様

twiccaのプラグイン仕様
<http://twicca.r246.jp/plugins/documents/>
→インテントの内容とかランチャーアイコンテンプレートとか

twicca Twilog プラグイン - shisashi.net
<http://www.shisashi.net/android/twiccaplugins_twilog>
→Twilogプラグインのソースが置いてあって参考になる。onCreateでインテント読んでるのが気になるけど。URL飛んだらfinishしてるからいいのか。

Androidアプリの間違った作り方 - たていすのメモ
<http://d.hatena.ne.jp/tateisu/20100629/1277814950>
→onCreateでインテント読んでる件の指摘(onStartで書けと書いてあるけどonResumeで実装してしまった、、

八角研究所 : Android で再開する Java プログラミング(14) - ダイアログを制するものがAndroidを制する! <http://www.hakkaku.net/articles/20090924-581>
→ダイアログ表示

画面の向きを切り替えた時の問題 - hyoromoの日記
<http://d.hatena.ne.jp/hyoromo/20090712/1247385249>
Y.A.M の 雑記帳: Android Configuration Change
<http://y-anz-m.blogspot.com/2010/10/androidconfiguration-change.html>
→画面の向き切り替えたときに再生成しないように対処。

ニクログ: FrameLayoutの利用方法まとめ
<http://miquniqu.blogspot.com/2011/12/framelayout.html>
→自分のサイトなのでかっこよくないけど。イベントリストのtwicca風アイコン配置。

1 Entry per Day: Androidアプリで使えるJSONライブラリ比較
<http://mstssk.blogspot.com/2011/12/androidjson.html>
→JSONライブラリの種類。proguardを考えるとJSONICはアレらしい。でも今回はJSONIC使った。(※proguardしてない)

覚え書き: JSONICの使い方
<http://y-sugasawa.blogspot.com/2010/06/jsonic.html>
→タイトルのまま。

[Android] ISO-8601 形式の日付文字列を解析(parse)するには - adakoda
<http://www.adakoda.com/adakoda/2010/02/android-iso-8601-parse.html>
→タイトルのまま。Apache Commons Langの利用方法。

 

■使用ライブラリ

JSONIC - simple json encoder/decoder for java
<http://jsonic.sourceforge.jp/>
→Zusaarから返却されたJSONデータをPOJO変換

Apache Commons Lang
<http://commons.apache.org/lang/>
→ISO-8601形式日付文字列の解析用

 

■Zusaarの仕様

APIリファレンス|参加費の決済もできるイベント開催支援サービス「Zusaar」
<http://www.zusaar.com/doc/api.html>

■実装時のメモ

・Twilog プラグイン のソースを読む

これで大体わかる。あとはプラグインの内容によってなので、、、。
これ以外でZusaar向けにやったことは、非同期アクセス、リスト表示、リスト切り替え、サブ画面遷移、縦横切り替え時の再生成解除ぐらいです。

・Zusaar APIのレスポンスの取得方法

http://www.zusaar.com/api/event/」でアクセスすると

{"results_start":1,"event":[{"limit":1000,"lon":139.6913395,"owner_nickname":"CROSSPARTY2012","waiting":0,"catch":"カードをお持ちでないなど事前払いができない方向けになります。現金取扱のリスク軽減のためカードをお持ちの方は公式サイトからチケットご購入お願いいたします。","event_id":"193151","url":"http:\/\/tech.nifty.co.jp\/party\/2012","title":"~(省略)

みたいなJSONデータが返ってくる。
http://www.zusaar.com/api/event/?nickname=miquniqu」でアクセスすると「miquniqu」というニックネームが参加するイベント一覧が返ってくる。(実際に実装するときは「"http://www.zusaar.com/api/event/?nickname=" + URLEncoder.encode(nickname, "UTF-8");」とかやってクエリをURLエンコードしておく。)

これをJSONICを利用してPOJOに変換する。POJOはうまい手の抜き方がわからなかったので手で書いた。
イベントサーチAPI向けのPOJOなら以下みたいな感じにgetter/setterが書いてあれば良いはず。
複数件のデータは「List<下位層のクラス>」にする。指定するクラスはその下の階層を別にPOJOで書く。(インナークラスでも可能?)とりあえずget「XXXX」set「XXXX」があっていれば実際のメンバー名はなんでもいい。たとえばAPIのレスポンスフィールドにある「catch」はJavaの予約語だけどgetCatch、setCatchとしておいて中身はcatchcopyとかでいい。

  1: 
  2: public class EventData {
  3: 
  4:   private int results_returned;
  5:   private int results_start;
  6: 
  7:   private List<Event> event;
  8: 
  9:   public int getResults_returned() {
 10:     return results_returned;
 11:   }
 12: 
 13:   public void setResults_returned(int results_returned) {
 14:     this.results_returned = results_returned;
 15:   }
 16: 
 17:   public int getResults_start() {
 18:     return results_start;
 19:   }
 20: 
 21:   public void setResults_start(int results_start) {
 22:     this.results_start = results_start;
 23:   }
 24: 
 25:   public List<Event> getEvent() {
 26:     return event;
 27:   }
 28: 
 29:   public void setEvent(List<Event> event) {
 30:     this.event = event;
 31:   }
 32: 
 33: }
 34: 

・twicca風のアイコン表示


主催と参加のリスト切り替えはタブ切り替えにしようかともおもったんですがtwiccaプラグインなのでtwicca風にしといたほうがいいかなってことで今の形になってます。(タブの実装がめんどいともいう。


とりあえず、雰囲気だけ合わせるなら以下の手順でできます。

  1: <?xml version="1.0" encoding="utf-8"?>
  2: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3:     android:layout_width="fill_parent"
  4:     android:layout_height="fill_parent"
  5:     android:orientation="vertical" >
  6:   <LinearLayout
  7:       android:id="@+id/layout_info"
  8:     android:layout_width="fill_parent"
  9:     android:layout_height="wrap_content"
 10:     android:orientation="horizontal"
 11:     android:background="#FF317BC7"
 12:     >
 13:     <TextView
 14:       android:id="@+id/text_info"
 15:       android:layout_width="fill_parent"
 16:       android:layout_height="wrap_content"
 17:       android:layout_margin="5dp"
 18:       android:layout_gravity="left|center_vertical"
 19:       android:textSize="14sp"
 20:         android:textColor="#FFFFFFFF"
 21:         android:shadowColor="#FF404040"
 22:       android:shadowDx="1.5"
 23:       android:shadowDy="2.0"
 24:       android:shadowRadius="1.3"
 25:         android:text="xxxxxxが参加するイベント一覧"
 26:       />
 27:     </LinearLayout>
 28:   <!-- リストビュー -->
 29:   <FrameLayout
 30:     android:layout_width="fill_parent"
 31:     android:layout_height="fill_parent"
 32:     >
 33:     <LinearLayout
 34:       android:layout_width="fill_parent"
 35:       android:layout_height="fill_parent">
 36:            <TextView
 37:         android:id="@+id/text_none"
 38:         android:layout_width="fill_parent"
 39:         android:layout_height="wrap_content"
 40:         android:layout_margin="10dp"
 41:         android:gravity="center_horizontal|center_vertical"
 42:         android:textSize="18sp"
 43:           android:textColor="#FFFFFFFF"
 44:           android:text="イベント情報がありません"
 45:         />
 46:       <ListView
 47:         android:id="@+id/list_event"
 48:         android:layout_width="fill_parent"
 49:         android:layout_height="fill_parent"
 50:         android:choiceMode="singleChoice"
 51:         android:divider="#FF808080"
 52:         android:dividerHeight="1dp"
 53:         />
 54:     </LinearLayout>
 55:     <LinearLayout
 56:       android:layout_width="fill_parent"
 57:       android:layout_height="50dip"
 58:       android:orientation="horizontal"
 59:       android:layout_gravity="bottom"
 60:       android:gravity="center"
 61:       android:background="@drawable/menu_back_alpha"
 62:       >
 63:       <LinearLayout
 64:           android:id="@+id/layout_owner"
 65:         android:layout_width="0dip"
 66:         android:layout_height="wrap_content"
 67:         android:layout_weight="1"
 68:         android:gravity="center"
 69:         android:background="@drawable/select_field_back"
 70:         >
 71:         <ImageView
 72:             android:id="@+id/image_owner"
 73:           android:layout_width="54dip"
 74:           android:layout_height="54dip"
 75:           android:layout_gravity="center"
 76:           android:src="@drawable/ic_menu_owner"
 77:           />
 78:       </LinearLayout>
 79:       <LinearLayout
 80:           android:id="@+id/layout_user"
 81:         android:layout_width="0dip"
 82:         android:layout_height="wrap_content"
 83:         android:layout_weight="1"
 84:         android:gravity="center"
 85:         android:background="@drawable/select_field_back"
 86:         >
 87:         <ImageView
 88:             android:id="@+id/image_user"
 89:           android:layout_width="54dip"
 90:           android:layout_height="54dip"
 91:           android:layout_gravity="center"
 92:           android:src="@drawable/ic_menu_users"
 93:           />
 94:       </LinearLayout>
 95:     </LinearLayout>
 96:   </FrameLayout>
 97: </LinearLayout>

まず、リストの上にメニューアイコン配置エリアとしてLinerLayoutをおきます。
この背景をmenu_back_alphaとしてますが、これは黒背景のグラデーションです。
(アイコンとリスト表示がかぶると見えずらいので。中身は以下。

  1: <?xml version="1.0" encoding="utf-8"?>
  2: <shape xmlns:android="http://schemas.android.com/apk/res/android"
  3:     android:shape="rectangle">
  4:     <gradient
  5:         android:startColor="#00000000"
  6:         android:endColor="#FF000000"
  7:         android:angle="270" />
  8: </shape>

layout_ownerとlayout_userのselect_field_backは何をしてるかというと、選択時に背景色を半透明にしています。

  1: <?xml version="1.0" encoding="utf-8"?>
  2: <selector xmlns:android="http://schemas.android.com/apk/res/android">
  3:     <item android:drawable="@drawable/select_field_back_pressed"
  4:         android:state_focused="true"
  5:         android:state_pressed="true" />
  6:     <item android:drawable="@drawable/select_field_back_pressed"
  7:         android:state_focused="false"
  8:         android:state_pressed="true" />
  9:     <item android:drawable="@drawable/select_field_back_selected" android:state_focused="true" />
 10: </selector>
 11: 

selectとpressedで呼び出しを分けていますが、中身は以下です。

  1: <?xml version="1.0" encoding="utf-8"?>
  2: <shape xmlns:android="http://schemas.android.com/apk/res/android">
  3:   <corners
  4:     android:bottomRightRadius="5dp"
  5:     android:bottomLeftRadius="5dp"
  6:     android:topLeftRadius="5dp"
  7:     android:topRightRadius="5dp"
  8:     />
  9:   <!-- 枠線 -->
 10:   <!-- <stroke
 11:       android:width="2dp"
 12:       android:color="#FF808080"
 13:     />
 14:   -->
 15:   <!-- 中抜き(半透明) -->
 16:   <solid
 17:     android:color="@color/field_back_select_alpha"
 18:     />
 19:   <padding
 20:     android:left="5dp"
 21:     android:top="5dp"
 22:     android:right="5dp"
 23:     android:bottom="5dp"
 24:     />
 25: </shape>
 26: 

strokeで枠線指定にすると、2chMateのようなフィールド枠だけ色変更になります。


あ、ちなみに上記で背景色を変更させるには、実装側でonClickを受け取れないと効果がでないのでonCreateで以下のようなリスナー登録しておきます。

  1:     ClickListener clicklistener = new ClickListener();
  2:     mLayoutOwner = (LinearLayout) findViewById(R.id.layout_owner);
  3:     mLayoutUser = (LinearLayout) findViewById(R.id.layout_user);
  4:     mLayoutOwner.setOnClickListener(clicklistener);
  5:     mLayoutUser.setOnClickListener(clicklistener);
  6: 
  1:   public class ClickListener implements OnClickListener {
  2:     @Override
  3:     public void onClick(View v) {
  4: 
  5:       if (v == mLayoutOwner) {
  6:         // 主催者検索
  7:         mSearchTarget = ApConst.SEARCH_EVENT_OWNER;
  8: 
  9:         mEventTask = new EventTask(EventActivity.this, mSearchTarget, mScreenName);
 10:         mEventTask.execute();
 11: 
 12:       } else if (v == mLayoutUser) {
 13:         // 参加者検索
 14:         mSearchTarget = ApConst.SEARCH_EVENT_USER;
 15: 
 16:         mEventTask = new EventTask(EventActivity.this, mSearchTarget, mScreenName);
 17:         mEventTask.execute();
 18:       }
 19:     }
 20:   }
 21: 

ひとまず、これでZusaar関連はひと段落させます。
次は「あにすと」に手をつけていこうかな。

0 件のコメント:

コメントを投稿