Android:Fragmentに値を渡す方法

XOOMでの開発やってると必ずFragmentをやらないといけなくなると思うんですが、こいつが何者か未だによく使い方を理解してないです。しかし、わかったことからすこしずつメモってわかるようになろうと思います。

今回は、Fragmentに値を渡す方法。Activityだったら、Intentに値を仕込んでstartActivity(intent)なわけですが、Fragmentでは以下のようにします。

FragmentManager fm = getFragmentManager();
FragmentTransaction t = fm.beginTransaction();
HogeFragment fragment = new HogeFragment();
Bundle bundle = new Bundle();
bundle.putExtra("test", "これはテストです。");
// フラグメントに渡す値をセット
fragment.setArguments(bundle);
t.add(R.id.hoge_fragment, fragment, "hoge_fragment");
t.commit();

で、受け取り方。
HogeFragment.onCreateViewにて、getArguemtns().getString(“****”)で取れる。

pubic View onCreateView(LayoutInflater inflater, ViewGroup container,
                     Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.hoge, container, false);
    // ここで値を受け取ってる
    String test = getArguments().getString("test");
    TextView txtHoge = (TextView) view.findViewById(R.id.txt_hoge);
    txtHoge.setText(test);
    return view;
}

以上です。


Android:Galleryのフリックで1つ分移動する方法

Galleryを全画面に表示したら、特にたいしたこともせずにタッチした指についてくるスライドもどきができるのですが、フリックしたらビューンと1つ以上移動してしまうので、どうしたもんかなーと頭を悩ませていたのですが、解決しました。

Galleryクラスを継承して、そのonFlingメソッドをオーバーライドしてfalseを返せばOKでした。

参照元URL:How can I limit fling in Android gallery to just one item per fling?

public class ExtendGallery extends Gallery {

    public ExtendGallery(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        // これだけ
        return false;
    }
}

Slim3:GAE開発入門の講師をしてきました。

2011/05/07(土)に、香川の高松でGAE開発入門の講師をしてきました。
講師は初めての経験だったので、ものすごく緊張しましたが、まぁなんとかうまくいったのかなぁと…。最初からいろんなトラブルがありましたが(自分のPCをプロジェクタに接続して説明するんだろうと思っていたら、据付のPCの画面が各テーブルの中央のディスプレイに表示されるシステムで作った資料がKeynoteだったから焦ったり、教室から外への接続がProxyでの接続でlocalhostが見れないとか)、なんとか。

参加者の人数はおそらく20人くらいだったのかなと思います。
最初になんでGAEを使うといいのか?ということと、Slim3使ってやる理由とか話したあとに、事前に作っておいたサンプルコードを駆け足で説明という方法でやったのですが、時間ぎりぎりでした。

スライドシェアに使ったスライドをアップしておいたので、貼りつけておきます。


Android:ItemizedOverlayで個別のアイコンを使う

Google Mapを使ったアプリで、画面上にOverlayを表示したいことがあります。単体のオーバーレイを表示する場合はOverlayを追加すればいいわけですが、複数のOverlayを追加する場合はItemizedOverlayを使うと便利です。しかし、ItemizedOverlayはデフォルトだと置かれるアイコンが全部同じものになってしまいます。

そこで、ItemizedOverlayを継承したクラスを作ると、アイコンを個別に表示することが可能です。

参考URLは以下。

普通に自分で作ったソースをまるっと貼付けます。
コンストラクタで渡しているJSONArrayの中身はfoursquareのスポットの配列です。

ちなみにOverlay.onTap(GeoPoint p, MapView map)はマップのスワイプと競合しますが、ItemizedOverlay.onTap(int index)は競合しませんでした。

private class VenueOverlays extends ItemizedOverlay<OverlayItem> {

    private JSONArray mItems;
        
    public VenueOverlays(JSONArray items) {
        // デフォルトのアイコンを指定
        super(getResources().getDrawable(R.drawable.icon));
        this.mItems = items;
        // アイテム数が変わったことを通知
        populate();
    }
        
    @Override
    protected OverlayItem createItem(int i) {
        try {
            JSONObject item = this.mItems.getJSONObject(i);
            JSONObject loc = item.getJSONObject("location");
            int lat = (int)(loc.getDouble("lat") * 1E6);
            int lng = (int)(loc.getDouble("lng") * 1E6);
            String title = item.getString("name");
            String snippet = "";
            for (String key:keys) {
                if (loc.has(key)) {
                    if (snippet.equals("")) {
                        snippet += loc.getString(key);
                    } else {
                        snippet += " " + loc.getString(key);
                    }
                }
            }

            OverlayItem oi = new OverlayItem(
                    new GeoPoint(lat, lng),
                    title,
                    snippet);
            JSONArray categories = item.getJSONArray("categories");
            Bitmap image = null;
            if (categories.length() > 0) {
                for (int j = 0; j < categories.length(); j++) {
                    JSONObject category = categories.getJSONObject(j);
                    if (category.has("primary") && category.getBoolean("primary")) {
                        String url = category.getString("icon");
                        // ImageCacheはオリジナルクラス。
                        // カテゴリーを表す画像を取得
                        image = ImageCache.getImage(url);
                        break;
                    }
                }
            }
            // 画像がなかったらデフォルトの画像を表示
            if (image == null) {
                image = BitmapFactory.decodeResource(getResources(), R.drawable.icon);
            }
            // 個別のマーカーを設定
            oi.setMarker(boundCenterBottom(new BitmapDrawable(image)));
            return oi;
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    protected boolean onTap(int index) {
        try {
            OverlayItem overlayItem = this.getItem(index);
            mMapController.animateTo(overlayItem.getPoint());
            // 選択したOverlayの情報をメンバに設定
            mSelectedVenue = this.mItems.getJSONObject(index);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return true;
    }

    @Override
    public int size() {
        return this.mItems.length();
    }
}

Android:Action Barにタブ表示(Android 3.0)

XOOM(Android 3.0)で開発やってます。タブレットは画面がでかいので、左右のペインを作って色々できるようなアプリをやろうとしていたわけですが、そのペインの片方でタブレイアウトを使いたかったのですが、TabHostはレイアウト上でRootViewでないといけないというルールがあるので、ペインを分けた時点でどうしたらいいんだろうか?と思い、数日悩んでいました。

フラグメントを使うのかなーと思ったのですが、ややこしくてわからんなぁと思っていて四苦八苦していたところ、@tama_eguchi さんに、API DemoのTargetSDKを11にしてインストールして、App > Action Bar > Action Bar Tabsというのがあることを教えて頂きました。

英語のサイトでも、タブはAction Barに置き換えられると書かれていて、普通にActionBarのメニューボタンにして使えという意味かと思っていたのですが、違いました。Action Barにタブが設置できるということでした。まさかAction Barがそんなに多機能になっていたとは!?

この下のソースだとタブを1つしか設定していないので、複数設定したときはどうかってのはまだわかりませんが、とりあえずAction Bar上にタブを表示し、タブを選択したら処理が走ることが確認できました。

参考にしたソースはAPI DemosのActionBarTabs.javaです。

// ActivityのonCreate
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    // Action Barにタブを追加する
    final ActionBar bar = getActionBar();
    bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
    bar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);
    bar.addTab(
        bar.newTab()
            .setText(R.string.tab_name)
            .setTabListener(new HogeTabListener(new HogeFragment()))
    );
}

private class HogeTabListener implements ActionBar.TabListener {

    private HogeFragment mFragment;
        
    public HogeTabListener(HogeFragment fragment) {
        mFragment = fragment;
    }
        
    public void onTabReselected(Tab tab, FragmentTransaction ft) {
        
    }

    /** タブが選択されたときの処理 */
    public void onTabSelected(Tab tab, FragmentTransaction ft) {
        // leftPaneにmFragmentのレイアウトを追加する
        ft.add(R.id.leftPane, mFragment, mFragment.getText());
    }

    /** タブの選択が移ったときの処理 */
    public void onTabUnselected(Tab tab, FragmentTransaction ft) {
        ft.remove(mFragment);
    }
}

private class HogeFragment extends Fragment {
    private String mText;
        
    public HogeFragment() {
        mText = "HogeFragment";
    }
        
    public String getText() {
        return mText;
    }
        
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View fragView = inflater.inflate(R.layout.hoge, container, false);
        // 色々なイベント設定とかここでやる。
        TextView text = (TextView) fragView.findViewById(R.id.text);
        text.setText(R.string.hoge);
        return fragView;
    }
}