Fragmentを使ったレイアウトの切り替え|Android開発
フラグメントを使うと、アクティビティの切り替えなしに画面レイアウトの変更が可能になります。
ビューに依存する処理をフラグメントに実装し、アクティビティには共通のキー処理などを実装することで再利用化などが期待できます。
以下はフラグメントによる画面レイアウト切り替えのサンプルになります。
Fragmentクラス
Activity
に設定するためのFragment
クラスを2つ用意します。
レイアウトファイル
<?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>
<?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...()
メソッドを使って取得・処理をします。
コールバックを使ってアクティビティとやりとりができるクラスのサンプルです。
※下記はコールバック設定のみで、実際にコールする処理は実装していません。
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);
}
}
表示のみ行うクラスのサンプルです。
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
レイアウトファイル
<?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>
ソースコード
Activity
にFragment
を追加するには、FragmentTransaction.replace()
メソッドなどを使います。
下記はreplace()
メソッドを使ってactivity_main_base.xml
のactivity_main_root
にフラグメントを挿入しています。
処理としては画面が表示される時にmMode
が1
ならFirstFragment
を、mMode
が2
なら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;
}
}
}
実行例
Fragment使用時の注意点
パッケージ
Fragment
クラスはandroid.support.v4.app.Fragment
にします。android.support.v4.app.Fragment
はandroid.app.Fragment
の不具合に対応したもので、使用が推奨されています。
同様にFragmentManager
・FragmentTransaction
についてもandroid.support.v4.app
パッケージを使用します。
android.app.Fragment
を使う場合は、フラグメントの挿入は以下のようになります。
getFragmentManager().beginTransaction().replace(R.id.activity_main_root, FirstFragment.newInstance()).commit();
Viewのリスナ登録
レイアウトファイルに書かれたonClick
はActivity
側のソースコード参照になります。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;
}
}