概要
Fragment間の画面遷移を知る。Android Studioでいつのまにか (ver 3.3から?)、プロジェクト生成画面で Fragment + ViewModelの雛形が選択できるやうになつてゐたのでそれも試す。ただし、ViewModelらしきことは一切しない。
まづ、Fragmentを2つ用意し、それぞれにボタンを持たせる。ボタンを押したら Fragment を切り替へる。第一のFragmentのボタンを押したら、Activityでイベントを受け取るまでを作る。その続きはあとで。
使ふているバージョンは次。
Android Studio : 3.5.2
Kotlin : 1.3.61
まづ、Fragmentを2つ用意し、それぞれにボタンを持たせる。ボタンを押したら Fragment を切り替へる。第一のFragmentのボタンを押したら、Activityでイベントを受け取るまでを作る。その続きはあとで。
使ふているバージョンは次。
Android Studio : 3.5.2
Kotlin : 1.3.61
プロジェクトの作成
プロジェクトを生成する
- Choose your project画面で Fragment + ViewModel を選択
- Configure your project画面で、Name: TestFragmentVMとし、Use androidx.* artifacts を選択
生成されるファイル
以下の5つのファイルが生成されてゐることを確認する。
| ファイル | 説明 |
|---|---|
| main_activity.xml | Activityのレイアウト。idはcontainer。fragment要素は無い。 |
| main_fragment.xml | fragmentのレイアウト。idはmain。 文字列MainFragmentを表示するTextViewが1つある |
| MainActivity.kt | Activityのコード。onCreate()の中で MainFragmentクラスのインスタンスをActivityのレイアウトに表示させてゐる |
| MainFragment.kt | レイアウト main_fragment.xmlを レイアウト containerに吹き込んでゐる(inflate)。 ViewModelのオブジェクトも生成済。 |
| MainViewModel.kt | VieModelクラス派生のクラスMainViewModelを生成済 |
ビルドする。 TextViewに MainFragmentと表示されるアプリが起動することを確認する。
フラグメントの追加
2つ目のFragmentを追加する。SecondFragmentとする。
- Android Studio 画面左側のproject tool windowで、app → java → com.example.testfragment を選び右クリック
- New → Fragment → Fragment (Blank) を選択
- Configure Component ダイアローグが現れる
- そのダイアローグで次の設定をする
- Fragment Name: SecondFragment
- Create lyaout XML? : チェックつける
- Fragment Layout Name: fragment_second
- include fragment factory methods? : チェックはずす
- include interface callback? : チェックはずす
- 言語はKotlin
- Finish
次の2つのファイルができてゐることを確認する。
- fragment_second.xml - レイアウトファイル
- SecondFragment.kt - クラス SecnodFragmentができてゐる。 Fragment()の派生として。 onCreateView( )の中で、レイアウトファイル fragment_second.xmlを吹き込んでゐる。つまり、クラスとレイアウトとの関係づけは既にできてゐる。
ビルドする。まだ何も実装してゐないので何も変わらない。
MainFragmentにボタン追加
まづ、レイアウトファイル main_fragment.xmlにボタンを追加する。つぎに、そのボタンを押したら、SecondFragmentに遷移するためのイベントリスナーを登録するために、MainFragment.ktを変更する。
ボタン コンポーネントの追加 - main_fragment.xml
main_fragment.xmlのデザインモードで次をする。
- PaletteからButtonコンポーネントを選択してイメージビューにドロップ。
- Buttonの配置を適当に制約づけする。たとへばMainFragmentのTextViewの下あたり。
- そのButtonコンポーネントのAttributesをつぎのやうにする
- id: buttonMain
- text: To Second Fragment
ボタン クリックのイベントリスナー登録 - MainFragment.kt
Fragment間は相互に通信しないことが基本。このため、画面遷移のイベントはすべてActivityに任せる。Fragmentがやることは、次のことだけ。
- ボタンクリックのイベントを受けて行う処理の interfaceだけを用意すること。(処理本体の実装はActivityが行う)
- ボタンクリックのイベントを受けること (リスナーを登録する)
- イベントを受けて行うActivityの処理本体を登録すること。
interfaceの用意
クラス MainFragmentで定義する interface は次のやう。
interface OnButtonClickListener {
fun onButtonClicked()
}
ボタンクリックのリスナー登録とActivityの処理本体の登録
関数 onCreateView( )の中で次を書く。
val view = inflater.inflate(R.layout.main_fragment, container, false)
val button = view.findViewById<Button>(R.id.buttonMain)
button.setOnClickListener {
val listener = context as? OnButtonClickListener
listener?.onButtonClicked()
}
return view
- 1行目:
- Android Studioが準備したコード部分。 元々は、main_fragment.xmlレイアウトを吹き込んだ(inflateした) Viewをreturnしてゐるが、そのViewを使うので変数viewに格納。
- 2行目:
- レイアウトからbuttonMain部品を取得。
- 3行目:
- そのbuttonMain部品が持つメンバー関数の setOnClickListnerを使って、ボタンがクリックされた時のこのFragmentでの処理を登録する。
- 4行目:
- contextは、この MainFragmentを受け持つActivityのこと。それを、 OnButtonClickListnerに型変換して取りだしてゐる。上位のクラスから下位のクラスへの型変換なので、明示的に as を使ふ。 OnButtonClickListenerが実装されていないかもしれないので、null許容するために、asに ?をつける。
OnButtonClickListenerは、さきほど、このMainFragmentで interface定義したもの。
ここで、contextを使ふのは、どうもきれいではないやうに見える。グローバル変数を使かふているやうで。 Android Developers Guideを見ると、Activityが thisを引数にして、Fragmentの関数を呼び出すことでイベントリスナーを登録する例になつてゐる。そのはうが、ActivityとFragmentとが分離されているやうであるが、コードが増える。あかんかなあ。 - 5行目:
- interfaceとして定義したOnButtonClickListenerの中の関数を呼び出す。contextの中の、つまり、Activityの中のonButtonClicked()を実行することになる。
- 6行目、7行目:
- viewを returnしている。(そのままや)
ここまでで、ManFragment.ktの編集はおしまい。4行目あかんかなあ。
まずは、MainFragmentで定義したinterfaceの実装をする。コードは次のやう。onButtonClicked ()の中で Fragmentの切り替えを実装するがそれはあとまはし。
Activityでボタンイベントを受ける - MainActivity.kt
class MainActivity : AppCompatActivity(), MainFragment.OnButtonClickListener {
〜 中略 〜
override fun onButtonClicked() {
Log.i("MainActivity", "onButtonClicked")
}
}
- 1行目:
- MainFragment.OnButtonClickListenerからの派生。
- 3行目〜5行目:
- interfaceの実装。ログを表示させてイベントが到達していることを確認するだけ。
ここまででビルドする。動作させてみる。ボタンを押したら、Logcatに、onButtonClickedが表示されてゐることがわかる。 MainFragmentのボタンを押して、Activityに通知されてゐる。
つづく。
ここまでのコード
MainFragment.kt
class MainFragment : Fragment() {
companion object {
fun newInstance() = MainFragment()
}
private lateinit var viewModel: MainViewModel
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val view = inflater.inflate(R.layout.main_fragment, container, false)
val button = view.findViewById<Button>(R.id.buttonMain)
button.setOnClickListener {
val listener = context as? OnButtonClickListener
listener?.onButtonClicked()
}
return view
}
interface OnButtonClickListener {
fun onButtonClicked()
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)
// TODO: Use the ViewModel
}
}
MainActivity.kt
class MainActivity : AppCompatActivity(), MainFragment.OnButtonClickListener {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity)
if (savedInstanceState == null) {
supportFragmentManager.beginTransaction()
.replace(R.id.container, MainFragment.newInstance())
.commitNow()
}
}
override fun onButtonClicked() {
Log.i("MainActivity", "onButtonClicked")
}
}
(了)
0 件のコメント:
コメントを投稿