【Android学習】FragmentをKotlinでやってみる
今更感がありますが先日、Udemyを眺めていたところ、以下のコースが目に留まったので、Android開発の学習を進めています。 ※セクション3:Java Deep Diveなど、自分には必用なさそうな部分は省いています。
レッスン自体はAndroid N向けの内容のため、最新のAndroid Studioなどではlayoutを作るときに若干勝手が違って苦労する部分もありますが、コース自体はよくできているなという印象です。
しかし、Fragmentを使いたくなったのですがコース内を選択してもヒットしなかったので、こちらの記事を参考に試してみました。
また、Javaでそのまま写経するのもな・・という感じだったので、Kotlinで書いてみました。
レイアウトファイルの作成
まずはFragmentを作成します。
HogeFragment
とかだと味気ないのでにQiitaの例にmaker
、brand
という項目を追加して、CarDetailFragment
という名前にしてみました。
Fragment作成はapp -> New -> Fragment -> Fragment(Blank)
で空のFragmentを作成しました。
レイアウト fragment_car_detail.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=".CarDetailFragment"> <!-- TODO: Update blank fragment layout --> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/helloText" android:layout_width="match_parent" android:layout_height="50dp" android:text="Hello Fragment" android:textAlignment="center" android:textSize="24sp" /> <Button android:id="@+id/numberButton" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="1" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <TextView android:id="@+id/makerText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="maker" /> <TextView android:id="@+id/brandText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="brand" /> </LinearLayout> </LinearLayout> </FrameLayout>
Fragmentのコード作成
CarDetailFragment.kt
になります。
デフォルトでいろいろメソッドが宣言されているのですが、一旦消して書き直しています。
Kotlinならではのイディオムがあったりしますが、難しいことはないと思います。
断片的に書いていって、最後に全体を書きます。
まずは変数宣言です。
lateinit
で後で初期化するよと明示しています。
private lateinit var mTextView: TextView private lateinit var maker: String private lateinit var brand: String
続いてcompanion object。
定数やJavaでいうところのstaticメソッドはここに定義しました。
createInstance
メソッドでは、インスタンス生成時にパラメーターを受け取って、Bundleに渡してFragmentのargumentsにセットしています。
companion object { private const val KEY_MAKER = "maker_name" private const val KEY_BRAND = "brand_name" fun createInstance(maker:String, brand:String): CarDetailFragment { val carDetailFragment = CarDetailFragment() val args = Bundle() args.putString(KEY_MAKER, maker) args.putString(KEY_BRAND, brand) carDetailFragment.arguments = args return carDetailFragment } }
あとはFragmentのライフサイクルメソッドを実装していきます。
ライフサイクルは公式の図がわかりやすいと思います。
今回は、
- onCreate ・・・ パラメータを受け取ってメンバ変数にセット
- onCreateView ・・・ Viewの生成
- onViewCreated ・・・ View生成後の操作
を実装しています。
全体は↓こんな感じになりました。
// packageは省略 import android.os.Bundle import android.support.v4.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.Button import android.widget.TextView class CarDetailFragment : Fragment() { private lateinit var mTextView: TextView private lateinit var maker: String private lateinit var brand: String companion object { private const val KEY_MAKER = "maker_name" private const val KEY_BRAND = "brand_name" fun createInstance(maker:String, brand:String): CarDetailFragment { val carDetailFragment = CarDetailFragment() val args = Bundle() args.putString(KEY_MAKER, maker) args.putString(KEY_BRAND, brand) carDetailFragment.arguments = args return carDetailFragment } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val args = arguments if (args == null) { maker = "" brand = "" } else { maker = args.getString(KEY_MAKER) brand = args.getString(KEY_BRAND) } } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { super.onCreateView(inflater, container, savedInstanceState) return inflater.inflate(R.layout.fragment_car_detail, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) mTextView = view.findViewById(R.id.helloText) view.findViewById<Button>(R.id.numberButton).setOnClickListener { mTextView.text = "${mTextView.text}!" } val makerText = view.findViewById<TextView>(R.id.makerText) makerText.text = maker val brandView = view.findViewById<TextView>(R.id.brandText) brandView.text = brand } }
Fragmentを呼び出すActivityの作成
こちらもFragmentと同じように app -> New -> Activity -> Blank Activity
で作成します。
LinearLayoutだけ定義し、中身は空っぽにしておきます。
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.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" tools:context=".CarDetailActivity"> <LinearLayout android:id="@+id/carDetailContainer" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"></LinearLayout> </android.support.constraint.ConstraintLayout>
CarDetailActivity.kt
は以下のような感じになりました。
パラメーターとして
という文字をFragmentに対して渡しています。
// packageは省略 import android.support.v7.app.AppCompatActivity import android.os.Bundle class CarDetailActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_car_detail) // コードからフラグメントを追加 if (savedInstanceState == null) { val transaction = supportFragmentManager.beginTransaction() transaction.add(R.id.carDetailContainer, CarDetailFragment.createInstance("TOYOTA", "プリウス")) transaction.commit() } } }
実際に実行して、CarDetailActivity
を開くと、以下のようにFragmentの内容が表示され、パラメータの受け渡しが行われていることが確認できました。
最初はなかなかとっつきにくいなーと思っていましたが、実際に触ってコードを書いていくと、「あーなるほど」という感じで少しづつ理解ができてきました。
引き続き時間を見つけて色々実装を試してみたいと思います。