FragmentはActivityと共に重要な機能を果たしていますが、いまいちわかりにくところがあります。最初に簡単なHello Worldを表示させるところから始めてみましょう。
2021.1.1 patch 2
Fragment
AndroidではActivityは重要な機能を司っていますが、勢いなんでもかんでもActivityに機能を入れてしまって巨大なActivityが出来上がってしまいます。これではメンテナンスがやりにくいコードになってしまい、チームでの開発がより困難になります。
Fragmentは「断片」という意味ですが、ActivityのUI部分を肩代わりでき、いくつものFragmentをActivityから開いたり閉じたりできます。
また、複数のActivityから使いまわすような再利用も可能です。
Activityには以下の役割があります
- Viewの生成と制御
- リソースを取得したりするContextのタスク
- コンポーネントとしてIntentを受け取る
ActivityにはActivityにしか出来ない事を担わせて、View生成と制御の部分はFragmentに任せようということです。
Fragmentの作成はXMLレイアウトファイルに静的に記述するやり方と
プログラマブルにダイナミックな動きができるように記述する方法があります。
1. XMLレイアウトファイルに記述
1.1 Activity のレイアウト
1.2 Fragment クラス
1.3 Fragment のレイアウト
1.4 MainActiviy
2. サンプルコード
XMLレイアウトファイルに記述
例えばレイアウトファイルにTextViewを貼っただけのような形でFragmentを生成します
Activity のレイアウト
activity_main.xml にFragmentContainerViewを追加します。
1 2 3 4 5 6 7 8 9 10 |
<androidx.fragment.app.FragmentContainerView android:id="@+id/fragment" android:name="com.example.testfragment.SampleFragment" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.5" /> |
android:nameには パッケージ名 + Fragmentクラス名 を入れます。
この例ではパッケージ名:com.example.testfragment
Fragmentクラス名:SampleFragment
なので
com.example.testfragment.SampleFragment
(このままコピペしないように)
Fragment クラス
次にFramentを継承したクラスを作成します。
例として、SampleFragment とします
SampleFragmentの空のクラスができました
以下のように記述
SampleFragment.kt
1 2 3 4 5 6 7 8 9 10 11 |
class SampleFragment : Fragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { // Inflate the layout for this fragment return inflater.inflate(R.layout.fragment_main, container, false) } } |
onCeateView():
ActivityのようにFragmentにもライフサイクルがありViewを生成するタイミングで呼ばれるのが onCeateView() です。
onCreateViewで渡される LayoutInfrater でFragmentのレイアウトを返します。
Fragment のレイアウト
Fragment用のレイアウトファイル fragment_main.xml を作成します
fragment_main.xml
これにTextViewを入れて Hello Fragment の文字列をリソースから呼びます。
1 2 3 4 5 6 7 8 9 10 11 12 |
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:text="@string/hello_fragment" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </LinearLayout> |
MainActivity
ActivityにはFragmentについての記述は何も必要ありません
MainActivity.kt
1 2 3 4 5 |
class MainActivity : AppCompatActivity(R.layout.activity_main) { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) } } |
サンプルコード
まとめてみますが、このままだとFragmentの大きさやActivityとの違いが分かりにくいので、サイズや背景色を設定してみます。
acitivity_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="20dp" android:background="#def" tools:context=".MainActivity"> <androidx.fragment.app.FragmentContainerView android:id="@+id/fragment" android:name="com.example.testfragment.SampleFragment" android:layout_width="match_parent" android:layout_height="300dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.5" /> </androidx.constraintlayout.widget.ConstraintLayout> |
SampleFragment.kt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
//package com.example.testfragment import androidx.fragment.app.Fragment; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; class SampleFragment : Fragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { // Inflate the layout for this fragment return inflater.inflate(R.layout.fragment_main, container, false) } } |
fragment_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#bcd" android:orientation="vertical" android:gravity="center" > <TextView android:text="@string/hello_fragment" android:textSize="40sp" android:textColor="#03f" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </LinearLayout> |
リソース
strings.xml
1 2 3 4 |
<resources> <string name="app_name">YourAppName</string> <string name="hello_fragment">Hello Fragment</string> </resources> |
MainActivity.kt
1 2 3 4 5 6 7 8 9 10 |
//package your.package.name; import android.os.Bundle import androidx.appcompat.app.AppCompatActivity class MainActivity : AppCompatActivity(R.layout.activity_main) { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) } } |
これで実行します。
<fragment>
以前はレイアウトに <fragment> タグを使っていたのですがFragmentContainerViewに変えるようにとワーニングがでるようになりました
ところが、
フラグメント | Android デベロッパー | Android Developers(2021-10-27 ) では
1 2 |
<fragment class="com.example.android.apis.app.FragmentLayout$TitlesFragment" ... /> |
を使う例が記載されています。
色々と新しい記事を探してみると
Create a fragment | Android Developers(2022-04-06) では
It is strongly recommended to always use a FragmentContainerView as the container for fragments, …
ということでFragmentContainerViewを使うことを強く推奨されています。
Googleの日本語翻訳版はいつも遅いので、と言ってもわずか半年のズレなので自分で気を付けるしかないでしょう
References:
androidx.fragment.app | Android Developers
フラグメント | Android Developers