Contents
Activity-Fragment画面遷移について
KotlinでActivity-Fragmentの画面遷移を勉強します。主にFragmentの新規追加と編集が今回の肝です。
教科書はnyanさんのJavaの解説コードを自分で勉強しながら、Kotlinに変換して、勉強を進めていきます。ここでは、3つ紹介されていますが、本ページでは主に先の二つを解説します。3つ目は先の2つを理解して実践できれば、自ずとできるかと思います。
またこちらの【Android学習】FragmentをKotlinでやってみるコードも参考にさせていただきました。
ActivityにFragmentを貼り付け
nyanさんのJavaの解説コード [Android] Fragment コードで記述するを参考に、レイアウトの中にFragmentを貼り付けて、Activityの作成段階からFragmentは貼り付けられています。プロジェクトでFragmentを初めてKotlinで追加するのが初めの難関かと思います。それ以外は特に難しいところはないかと。
ActivityからFragmentを『動的』に貼り付け
nyanさんのJavaの解説コード [Android] Activity と Fragment の画面遷移 を参考に、activity_main.xmlの中の”@+id/container”となっている部分FrameLayoutに、ボタンを押した際にFragmentを動的に貼り付けます。(説明のために点線で書きましたが、イメージです。)
戻るボタンで戻ります。
Fragment間の遷移
先ほどの例では、戻るボタンで遷移を戻しましたが、Fragment間の遷移は以下を参考にするとよいかと思います。
- [Android] Fragment から別の Fragment に画面遷移させてみる
- 「ほんきで学ぶAndroidアプリ開発入門」(寺園 聖文さん著)のChapter05-Lesson23「Fragmentを利用する」
このページでは解説等をしませんが、FragmentManagerを使用して、popBackStack(), addToBackStack(null)を使用して、遷移させることになります。上で述べた2例ができていれば、意外に簡単に実装できるのではと考えています。
ActivityにFragmentを貼り付け・実践編
MainActivity.kt
何も触りません。いつも通りEmptyActivityを作成する手順で作成します。
activity_main.xml
ポイントとしては、fragmentのプロパティの中に”android:name”があるので、これから追加するFragmentの名前を追加します。下記のように追加してください。
android:name=”com.example.プロジェクト名の名前.TestFragment”
TestFragmentをプロジェクトに追加する
ここが今回の山場です。
-
- プロジェクトのapp→java(MainActivity.ktの入っているフォルダ)で右クリック→New
-
- 先ほどの続きで、下の方のFragment→Fragment(Blank)を選択 下記画像の赤囲みの部分
-
- FragmentNameを”TestFragment”に変更して、Finishボタンを押してください。
- TestFragment.ktが追加されます。ちなみにコードとしては以下のような感じです。これを編集していきます。
package com.example.XXXXXXX import android.content.Context import android.net.Uri import android.os.Bundle import android.support.v4.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup // TODO: Rename parameter arguments, choose names that match // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER private const val ARG_PARAM1 = "param1" private const val ARG_PARAM2 = "param2" /** * A simple [Fragment] subclass. * Activities that contain this fragment must implement the * [TestFragment.OnFragmentInteractionListener] interface * to handle interaction events. * Use the [TestFragment.newInstance] factory method to * create an instance of this fragment. * */ class TestFragment : Fragment() { // TODO: Rename and change types of parameters private var param1: String? = null private var param2: String? = null private var listener: OnFragmentInteractionListener? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) arguments?.let { param1 = it.getString(ARG_PARAM1) param2 = it.getString(ARG_PARAM2) } } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { // Inflate the layout for this fragment return inflater.inflate(R.layout.fragment_test, container, false) } // TODO: Rename method, update argument and hook method into UI event fun onButtonPressed(uri: Uri) { listener?.onFragmentInteraction(uri) } override fun onAttach(context: Context) { super.onAttach(context) if (context is OnFragmentInteractionListener) { listener = context } else { throw RuntimeException(context.toString() + " must implement OnFragmentInteractionListener") } } override fun onDetach() { super.onDetach() listener = null } /** * 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. * * * See the Android Training lesson [Communicating with Other Fragments] * (http://developer.android.com/training/basics/fragments/communicating.html) * for more information. */ interface OnFragmentInteractionListener { // TODO: Update argument type and name fun onFragmentInteraction(uri: Uri) } companion object { /** * 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 TestFragment. */ // TODO: Rename and change types and number of parameters @JvmStatic fun newInstance(param1: String, param2: String) = TestFragment().apply { arguments = Bundle().apply { putString(ARG_PARAM1, param1) putString(ARG_PARAM2, param2) } } } }
- 追加したTestFragmentを編集します。コメント部分は残しておいてもよいのですが、見やすさのために削除しておきます。 onCreateView()関数以外は削除しました。private変数も削除しています。
package com.example.activity_fragment_transition2 import android.os.Bundle import android.support.v4.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import kotlinx.android.synthetic.main.fragment_test.* class TestFragment : Fragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { // Inflate the layout for this fragment return inflater.inflate(R.layout.fragment_test, container, false) } }
-
- 以上で編集は終わりです。これでBuildを行い、実行すると以下のような画像が出てくるかと思います。
ActivityからFragmentを『動的』に貼り付け・実践編
activity_main.xml
nyanさんのJavaの解説コード [Android] Activity と Fragment の画面遷移 を参考にして作成してください。
MainActivity.kt
ポイントは、setOnClickListenerの中ですが、
- supportFragmentManagerを使用して開始すること
- R.id.containerに、TestFragment.newInstance(“Fragment”)を設定すること。
かなと思います。
import android.support.v7.app.AppCompatActivity import android.os.Bundle import kotlinx.android.synthetic.main.activity_main.* class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) if(savedInstanceState == null) { button.setOnClickListener{ val fragmentManager = supportFragmentManager val fragmentTransaction = fragmentManager.beginTransaction() // BackStackを設定 fragmentTransaction.addToBackStack(null) // パラメータを設定 fragmentTransaction.replace( R.id.container, TestFragment.newInstance("Fragment") ) fragmentTransaction.commit() } } } }
TestFragmentをプロジェクトに追加する
先ほどの章を参照にプロジェクトに追加してください。レイアウトファイルも参考もとと同じように編集してください。
- 追加したTestFragmentを編集します。コメント部分は残しておいてもよいのですが、見やすさのために削除しておきます。private変数, onButtonPressed(), onAttach(), onDetach(),OnFragmentInteractionListener{}を削除しています。
package com.example.XXXXXXX import android.os.Bundle import android.support.v4.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import kotlinx.android.synthetic.main.fragment_test.* class TestFragment : Fragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { // Inflate the layout for this fragment return inflater.inflate(R.layout.fragment_test, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) val args = arguments if (args != null) { val str = args.getString("Message") text_fragment.text = str } } companion object { @JvmStatic fun newInstance(str: String) : TestFragment = TestFragment().apply { arguments = Bundle().apply { putString("Message", str) } } } }
- text_fragment.text = strで生成した際に入れた、文字列を取得します。
- Javaをコピー&ペーストで変換すると以下のようになりますが、newInstanceの部分はデフォルトで用意された関数をそのままで用いることにしました。.applyは変数を少なくするために用意されている仕組みのようです。
fun newInstance(str: String): TestFragment { // Fragemnt01 インスタンス生成 val fragment = TestFragment() // Bundle にパラメータを設定 val barg = Bundle() barg.putString("Message", str) fragment.arguments = barg return fragment }
- こちらはこれで終了です。
そのほか気になったこと
.applyについて
applyは変数を少なくするために用意されている仕組みのようです。少しずつ、覚えていきたいと思います。
Kotlinでスコープ関数「apply」を使えば、一時変数を書かなくてすむの巻
KotlinのRun, Let, Apply, Alsoを使い分け
Bundleについて
Key-Valueペアでデータを放りこんで、取り出す仕組みであると理解しています。
こちらのBundleの解説を参照すると分かりやすいかと思います。