Fragmentを使ったレイアウトの切り替え|Android開発

フラグメントを使うと、アクティビティの切り替えなしに画面レイアウトの変更が可能になります。
ビューに依存する処理をフラグメントに実装し、アクティビティには共通のキー処理などを実装することで再利用化などが期待できます。
以下はフラグメントによる画面レイアウト切り替えのサンプルになります。

Fragmentクラス

Activityに設定するためのFragmentクラスを2つ用意します。

レイアウトファイル

fragment_first.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
             xmlns:tools="http://schemas.android.com/tools"
              android:orientation="vertical"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             tools:context=".fragment.FirstFragment">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="first fragment."/>

</LinearLayout>
fragment_second.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
             xmlns:tools="http://schemas.android.com/tools"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             tools:context=".fragment.SecondFragment">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="second fragment"/>

</FrameLayout>

ソースコード

newInstance()メソッドを使ってインスタンス生成します。パラメータがある場合はBundle.put...()メソッドを使って保持し、onCreate()内でBundle.get...()メソッドを使って取得・処理をします。

FirstFragment

コールバックを使ってアクティビティとやりとりができるクラスのサンプルです。
※下記はコールバック設定のみで、実際にコールする処理は実装していません。

import android.support.v4.app.Fragment;

/**
 * A simple {@link Fragment} subclass.
 * Activities that contain this fragment must implement the
 * {@link FirstFragment.OnFragmentInteractionListener} interface
 * to handle interaction events.
 * Use the {@link FirstFragment#newInstance} factory method to
 * create an instance of this fragment.
 */
public class FirstFragment extends Fragment {
    private static final String ARG_PARAM1 = "param1";
    private static final String ARG_PARAM2 = "param2";

    private String mParam1;
    private String mParam2;

    // コールバック通知先.
    private OnFragmentInteractionListener mListener;

    public FirstFragment() {
        mListener = new OnFragmentInteractionListener() {
            @Override
            public void onFragmentInteraction(Uri uri) {
                // NOP.
            }
        };
    }

    /**
     * Use this factory method to create a new instance of
     * this fragment using the provided parameters.
     *
     * @param param1 Parameter 1.
     * @param param2 Parameter 2.
     * @return A new instance of fragment FirstFragment.
     */
    public static FirstFragment newInstance(String param1, String param2) {
        FirstFragment fragment = new FirstFragment();
        Bundle args = new Bundle();
        args.putString(ARG_PARAM1, param1);
        args.putString(ARG_PARAM2, param2);
        fragment.setArguments(args);
        return fragment;
    }

    public static FirstFragment newInstance() {
        return new FirstFragment();
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // setArguments() で設定したパラメータを取得する.
        if (getArguments() != null) {
            mParam1 = getArguments().getString(ARG_PARAM1);
            mParam2 = getArguments().getString(ARG_PARAM2);
        } else {
            mParam1 = StringUtils.EMPTY;
            mParam2 = StringUtils.EMPTY;
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment.
        return inflater.inflate(R.layout.fragment_first, container, false);
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        onAttachContext(context);
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) {
            return;
        }
        onAttachContext(activity);
    }

    protected void onAttachContext(Context context) {
        if (context instanceof OnFragmentInteractionListener) {
            mListener = (OnFragmentInteractionListener) context;
        } else {
            throw new RuntimeException(context.toString()
                    + " must implement OnFragmentInteractionListener");
        }
    }

    @Override
    public void onDetach() {
        super.onDetach();
        mListener = new OnFragmentInteractionListener() {
            @Override
            public void onFragmentInteraction(Uri uri) {
                // NOP.
            }
        };
    }

    @Override
    public void onResume() {
        super.onResume();
    }

    @Override
    public void onPause() {
        super.onPause();
    }

    /**
     * This interface must be implemented by activities that contain this
     * fragment to allow an interaction in this fragment to be communicated
     * to the activity and potentially other fragments contained in that
     * activity.
     * <p>
     * See the Android Training lesson <a href=
     * "http://developer.android.com/training/basics/fragments/communicating.html"
     * >Communicating with Other Fragments</a> for more information.
     */
    public interface OnFragmentInteractionListener {
        void onFragmentInteraction(Uri uri);
    }
}
SecondFragment

表示のみ行うクラスのサンプルです。

import android.support.v4.app.Fragment;

/**
 * A simple {@link Fragment} subclass.
 * Use the {@link SecondFragment#newInstance} factory method to
 * create an instance of this fragment.
 */
public class SecondFragment extends Fragment {

    public SecondFragment() {
    }

    public static SecondFragment newInstance() {
        return new SecondFragment();
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment.
        return inflater.inflate(R.layout.fragment_second, container, false);
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        onAttachContext(context);
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) {
            return;
        }
        onAttachContext(activity);
    }

    protected void onAttachContext(Context context) {
    }

    @Override
    public void onDetach() {
        super.onDetach();
    }
}

Activity

レイアウトファイル

activity_main_base.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <FrameLayout android:id="@+id/activity_main_root"
                 android:layout_width="match_parent"
                 android:layout_height="match_parent" />

</LinearLayout>

ソースコード

ActivityFragmentを追加するには、FragmentTransaction.replace()メソッドなどを使います。

下記はreplace()メソッドを使ってactivity_main_base.xmlactivity_main_rootにフラグメントを挿入しています。
処理としては画面が表示される時にmMode1ならFirstFragmentを、mMode2ならSecondFragmentを挿入します。画面が非表示になると挿入しているフラグメントを一旦削除します。

public class MainActivity extends AppCompatActivity
    implements FirstFragment.OnFragmentInteractionListener {

    private Fragment mCurrentFragment;

    @Override
    public void onFragmentInteraction(Uri uri) {
        // コールバック処理を書く.
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_base);
        mCurrentFragment = null;
    }

    int mMode;

    @Override
    public void onResume() {
        super.onResume();

        if (mMode == 1) {
            mCurrentFragment = FirstFragment.newInstance();
        } else if (mMode == 2) {
            mCurrentFragment = SecondFragment.newInstance();
        }
        getSupportFragmentManager()
            .beginTransaction()
            .replace(R.id.activity_main_root, mCurrentFragment)
            .commit();
    }

    @Override
    public void onPause() {
        super.onPause();
        if (mCurrentFragment != null) {
            getSupportFragmentManager()
                .beginTransaction()
                .remove(mCurrentFragment)
                .commit();
            mCurrentFragment = null;
        }
    }
}

実行例

mMode=1の場合
FirstFragment
mMode=2の場合
SecondFragment

Fragment使用時の注意点

パッケージ

Fragmentクラスはandroid.support.v4.app.Fragmentにします。android.support.v4.app.Fragmentandroid.app.Fragmentの不具合に対応したもので、使用が推奨されています。
同様にFragmentManagerFragmentTransactionについてもandroid.support.v4.appパッケージを使用します。

android.app.Fragmentを使う場合は、フラグメントの挿入は以下のようになります。

getFragmentManager().beginTransaction().replace(R.id.activity_main_root, FirstFragment.newInstance()).commit();

Viewのリスナ登録

レイアウトファイルに書かれたonClickActivity側のソースコード参照になります。Fragment側のソースコードで受け取りたい場合はソースコードで直接リスナ登録します。

findViewById({ID}).setOnClickListener({OnClickListener});

レイアウトファイルを使用しないケース

アクティビティでsetContentView(View)を使って画面生成する方法と同様のことをフラグメントを使って実装する場合は以下のようになります。

アクティビティで実装していた方法

public class SampleActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        TextView textView = new TextView(this);
        setContentView(textView);

        textView.setText("sample activity");
    }
}

フラグメントを使った実装方法

Activity
public class SampleActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_base);

        getSupportFragmentManager()
                .beginTransaction()
                .replace(R.id.activity_main_root, TextViewFragment.newInstance())
                .commit();
    }
}
Fragment

onCreateView()で生成したビューを戻り値として返します。

public class TextViewFragment extends Fragment {

    public TextViewFragment() {
    }

    public static TextViewFragment newInstance() {
        return new TextViewFragment();
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        TextView textView = new TextView(getActivity());
        textView.setText("sample activity");
        return textView;
    }
}

Fragmentのライフサイクル

 Fragmentのライフサイクル
このエントリーをはてなブックマークに追加
にほんブログ村 IT技術ブログへ

コメント

メールアドレスが公開されることはありません。 が付いている欄は必須項目です