ボクココ

個人開発に関するテックブログ

ViewPager を DialogFragment で表示する

Android ではおなじみの ViewPager。 これを使えば、スワイプで画面切り替えを簡単に実装することができる。スマホアプリらしいアプリを作るなら、これはよく使うと思う。

さて、これをダイアログで出したいと思った時の手順をここにまとめよう。思いの外はまってしまった。。今回は DialogFragment を初めて使った。

DialogFragment とは

今まで自分は、AlertDialog.Builder でダイアログを表示していた。これとの違いをリファレンスで読んでみると、

A fragment that displays a dialog window, floating on top of its activity's window. This fragment contains a Dialog object, which it displays as appropriate based on the fragment's state. Control of the dialog (deciding when to show, hide, dismiss it) should be done through the API here, not with direct calls on the dialog.

ダイアログウィンドウを表示するフラグメントで、アクティビティウィンドウのトップに浮遊する。このフラグメントはフラグメントの状態に応じて適切に表示されるダイアログオブジェクトを含んでいる。ダイアログのコントロール(いつ表示し、いつ非表示にするか)は、そのAPIを通じて行われるべきであり、ダイアログに対して直接呼び出すべきではない。

要はこのフラグメント内で、AlertDialogを生成して、それをコントロールすべきであり、直接AlertDialog.Builderを使うべきではないということらしい。なので今後はカスタマイズしたダイアログ出すときはDialogFragmentを使っていく感じにしよう。

ViewPager を利用する

さて、ここからが本題。 FragmentDialog を使って ViewPager のスワイプを実装しよう。今回はシンプルに取得した画像 URLをそのままスワイプで表示させるサンプル。

ダイアログ内のスワイプ一つ一つのページ

PageFragment.java

public class PageFragment extends Fragment {
    private final static String URL = "url";

    public static PageFragment newInstance(String url) {
        PageFragment fragment = new PageFragment();
        Bundle args = new Bundle();
        args.putString(URL, url);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Bundle bundle = getArguments();
        String url = bundle.getString(URL);
        NetworkImageView networkImageView = new NetworkImageView(getActivity());
        networkImageView.setImageUrl(url, ApplicationController.getInstance().getImageLoader());
        return networkImageView;
    }
}

Fragment の値の受け渡しには、Bundleを利用する。引数やセッターではないことに注意。

各PageFragmentを管理するAdapter

public class PagePagerAdapter extends FragmentStatePagerAdapter {
    String[] detailUrls;

    public PagePagerAdapter(FragmentManager fm, String[] urls) {
        super(fm);
        this.detailUrls = urls;
    }

    @Override
    public Fragment getItem(int i) {
        return PageFragment.newInstance(detailUrls[i]);
    }

    @Override
    public int getCount() {
        return detailUrls.length;
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return "" + (position + 1);
    }

}

ダイアログクラスの定義

ここで今回の主役の DialogFragment の登場。

public class PageDialog extends DialogFragment {
    private final static String KEY_URL = "diaog_key_urls";

    public static PageDialog newInstance(String[] urls) {
        PageDialog fragment = new PageDialog();
        Bundle args = new Bundle();
        args.putStringArray(KEY_URL, urls);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        final View view = inflater.inflate(R.layout.page_dialog, container, false);
        String[] urls = getArguments().getStringArray(KEY_URL);

        final ViewPager viewPager = (ViewPager) view.findViewById(R.id.pager);
        final PagePagerAdapter adapter = new PagePagerAdapter(getChildFragmentManager(), urls);
        viewPager.setAdapter(adapter);

        getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE);
        getDialog().setCanceledOnTouchOutside(true);

        return view;
    }
}

レイアウトの生成

layout/page_dialog.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v4.view.ViewPager
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <android.support.v4.view.PagerTitleStrip
            android:id="@+id/pager_title_strip"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="top"
            android:paddingTop="4dp"
            android:paddingBottom="4dp" />
    </android.support.v4.view.ViewPager>

</RelativeLayout>

ダイアログの呼び出し

最後はお好きなタイミングでこれを呼び出すだけだ!

PageDialog newFragment = PageDialog.newInstance(getImagesURL());
newFragment.show(getSupportFragmentManager(), TAG);