ArrayAdapterを利用する
EkiListFragmentにデータをセットするタイミングは、Web APIから結果を受信した後です。ですから、MainActivityのonLoadFinishedメソッドに、次のようなコードを追加しましょう。
@Override public void onLoadFinished(Loader<String> loader, String body) { if (body == null) return; switch (loader.getId()) { case 0: // APIの結果を解析する ParseMoyori parse = new ParseMoyori(); parse.loadJson(body); ~中略~ // 駅情報のアダプターを作成する(1) ArrayAdapter<EkiInfo> adapter = new ArrayAdapter<EkiInfo>(this, android.R.layout.simple_list_item_1, parse.getEkiinfo()); try { ListFragment listFragment = (ListFragment)fm.findFragmentById(R.id.eki_list); // ListFragmentに駅情報のアダプターを設定する(2) listFragment.setListAdapter(adapter); } catch (Exception e) { } break; } }
受信したデータから、ArrayAdapterオブジェクトを生成します(1)。ArrayAdapterのコンストラクタはいくつかありますが、ここでは次のコンストラクタを適用しています。
public ArrayAdapter (Context context, int resource, List<T> objects)
- context コンテキスト
- resource リソースID(TextView)
- objects セットしたいオブジェクト
第2引数で指定するリソースIDとは、ListViewウィジェットの1行を表示しているTextViewウィジェットのものです。ListFragmentのデフォルトでは、simple_list_item_1という名前のIDになっています。
第3引数には、Listコレクションのオブジェクトを指定します。(1)で記述しているParseMoyoriクラスのgetEkiinfoメソッドは、フィールドのList<EkiInfo>オブジェクトを参照するものです。
作成したアダプターをListFragmentに設定するには、ListFragmentクラスに用意されたsetListAdapterメソッドを実行します(2)。これだけで、一覧表示されるようになります。
なお、EkiInfoオブジェクトから、テキスト表示へ変換するために、toStringメソッドをオーバーライドしておきます。これで、駅名(路線名)という表示になります。
//最寄駅情報クラス public class EkiInfo { ~中略~ @Override public String toString() { return name + "(" + line + ")"; } }
フラグメントにクリックのコールバックメソッドを追加する
次に、最寄り駅名をタップしたときの処理を追加しましょう。これは、コールバックされるonListItemClickメソッドをオーバーライドするだけです。オーバーライドすれば、リストの項目がタップされたときの処理を記述することができます。
@Override public void onListItemClick(ListView l, View v, int position, long id) { super.onListItemClick(l, v, position, id); try { // クリックした行の駅情報を取得(1) EkiInfo e = (EkiInfo)getListAdapter().getItem(position); MyMapFragment mapFragment = (MyMapFragment)getFragmentManager().findFragmentById(R.id.map); // 駅情報に合致するマーカーの情報ウィンドウを表示し地図を移動する(2) mapFragment.moveEkiToCenter(e); } catch (Exception e) { } }
onListItemClickメソッドの第3引数には、クリックされた項目が上から何番目なのかという情報がセットされています。この情報をもとに、該当の駅のEkiInfoオブジェクトを取得しています(1)。
(2)のmoveEkiToCenterメソッドは、後述するMyMapFragmentに追加するメソッドです。駅情報に合致するマーカーの情報ウィンドウを表示して、地図の中心をその駅に移動する処理となっています。
moveEkiToCenterメソッドを実装する
では最後に、MyMapFragmentにmoveEkiToCenterメソッドを追加しましょう。また、このメソッドの追加にともない、前回のコードの変更とフィールドの追加があります。
public class MyMapFragment extends MapFragment { ~中略~ // API実行の抑制フラグ(1) private Boolean noCameraChange = false; @Override public void onActivityCreated(Bundle savedInstanceState) { try { // 地図を移動したときのリスナー googleMap.setOnCameraChangeListener(new OnCameraChangeListener() { @Override public void onCameraChange(CameraPosition cameraPosition) { // noCameraChangeがtrueならWeb APIを呼び出さない(2) if (0.5 < calcDistance(centerPosition,cameraPosition) && !noCameraChange) { execMoyori(cameraPosition); centerPosition = cameraPosition; } noCameraChange = false; // デフォルトに戻す } }); } ~中略~ } // 駅情報からマーカーを求める(4) public Marker getKeyByValue(EkiInfo value) { for (Entry<Marker, EkiInfo> entry : ekiMarkerMap.entrySet()) { if (value.equals(entry.getValue())) { return entry.getKey(); } } return null; } // 駅情報に合致するマーカーの情報ウィンドウを表示し、地図の中心にする public void moveEkiToCenter(EkiInfo value) { Marker marker = getKeyByValue(value); // 駅情報からマーカーを取得(3) marker.showInfoWindow(); // 情報ウィンドウを表示(5) // マーカーの位置に地図の中心を移動する(6) CameraPosition cameraposprev = googleMap.getCameraPosition(); CameraPosition camerapos = new CameraPosition.Builder(cameraposprev) .target(marker.getPosition()).build(); noCameraChange = true; googleMap.animateCamera( // (7) CameraUpdateFactory.newCameraPosition(camerapos)); } ~後略~ }
フィールドに、 API実行の抑制フラグを追加しています(1)。これは、コードで地図の中心を移動させたときに、意図せずWeb APIが実行されないようにするためです(2)。また、自分で地図を移動させた場合(フラグがfalseのとき)のみ、最寄り駅情報が更新されるようにしています。
moveEkiToCenterメソッドでは、まずEkiInfoオブジェクトから、マーカーオブジェクトを取得しています(3)。EkiInfoオブジェクトとマーカーオブジェクトは、ekiMarkerMapというHashMapコレクションに保存していますので、getKeyByValueメソッドのなかで、forループを使って1つずつEkiInfoを比較し、マーカーオブジェクトを検索しています(4)。
マーカーオブジェクトが取得できれば、showInfoWindowメソッドで情報ウィンドウを表示し(5)、地図を移動させます(6)。
地図の中心をマーカーの位置に移動させるには、CameraPositionオブジェクトを作成します。これは、GoogleMapクラスのanimateCameraメソッドを利用しています。animateCameraメソッドは、瞬時に切り替わるmoveCameraメソッドとは異なり、地図の移動をアニメーションしながら行うものです。
最後に
今回は、最寄り駅の一覧を表示するFragmentを追加して、2ペイン表示する方法を解説しました。次回は、地図表示の上に、最寄り駅の一覧をオーバーラップさせるスマートフォン用の画面を解説します。