はじめに
既存のプロジェクトでは、複数のアクティビティによる画面遷移の構成となっておりましたが、Androidアプリとしてデファクトスタンダードな構成とするため
- Single Activity, Multiple Fragments化
- Navigationによる画面遷移
- SafeArgsによるパラメータの引き渡し
を適用しました。
なので、この記事では上記の適用方法について紹介していきたいと思います。
プロジェクトの設定
NavigationとSafeArgsのために、
Projectのapp/build.gradle
に以下を設定
buildscript {
dependencies {
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.5.3"
}
}
appのbuild.gradle
に以下を設定
apply plugin: 'androidx.navigation.safeargs.kotlin'
apply plugin: 'kotlin-parcelize'
dependencies {
implementation 'androidx.navigation:navigation-fragment-ktx:2.5.3'
implementation 'androidx.navigation:navigation-ui-ktx:2.5.3'
}
Single Activity, Multiple Fragments化
ActivityをFragmentに変換する
これまでActivityとして作成したクラスはAppCompatActivity
の継承からFragment
の継承に変更する修正が基本になります。
以下のようにアクションバーにタイトルの設定や戻るボタンを設定している場合は以下のように変換します。
変換前のActivity
class LicenseActivity : AppCompatActivity() {
@SuppressLint("ResourceType")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_license)
// タイトルの設定
title = getString(R.string.license)
// 戻るボタンの設定
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
}
}
変換後のFragment
class LicenseFragment : Fragment() {
/** ライセンス画面のビュー */
private var rootView: View? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Fragmentのメニューを有効にする
setHasOptionsMenu(true)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
rootView = inflater.inflate(R.layout.fragment_license, container, false)
return rootView
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// タイトルの設定
requireActivity().title = getString(R.string.license)
// 戻るボタンの設定
(requireActivity() as AppCompatActivity).supportActionBar?.setDisplayHomeAsUpEnabled(true)
}
}
Single Activityを用意
Fragment
全体を管理するActivity
を以下のように1つ用意します。
class PasswordMemoActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setTheme(R.style.AppTheme)
setContentView(R.layout.activity_password_memo)
}
}
xml
ファイルの中で、後述するNavigationのファイルを設定します。
<?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:id="@+id/loginView"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.highcom.passwordmemo.PasswordMemoActivity">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/passwordmemo_fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="androidx.navigation.fragment.NavHostFragment"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph"/>
</androidx.constraintlayout.widget.ConstraintLayout>
Navigation Editorで画面遷移を設定
nav_graphの設定
res/navigation/nav_graph.xml
を作成して、以下のようにDesignタブでグラフィカルに画面遷移を設定します。
-
passwordListFragment
→inputPasswordFragment
-
inputPasswordFragment
→passwordListFragment
の遷移についてxml
ファイルの設定は以下となります。
<?xml version="1.0" encoding="utf-8"?>
<navigation 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:id="@+id/passwordmemo_nav_graph"
app:startDestination="@id/loginFragment">
<fragment
android:id="@+id/passwordListFragment"
android:name="com.highcom.passwordmemo.ui.fragment.PasswordListFragment"
android:label="fragment_password_list"
tools:layout="@layout/fragment_password_list" >
<action
android:id="@+id/action_passwordListFragment_to_inputPasswordFragment"
app:destination="@id/inputPasswordFragment"
app:popUpTo="@id/passwordListFragment"
app:enterAnim="@anim/slide_in_left"
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_in_right"
app:popExitAnim="@anim/slide_out_right" >
<argument
android:name="editData"
app:argType="com.highcom.passwordmemo.ui.PasswordEditData" />
</action>
</fragment>
<fragment
android:id="@+id/inputPasswordFragment"
android:name="com.highcom.passwordmemo.ui.fragment.InputPasswordFragment"
android:label="InputPasswordFragment"
tools:layout="@layout/fragment_input_password" >
<action
android:id="@+id/action_inputPasswordFragment_to_passwordListFragment"
app:destination="@id/passwordListFragment"
app:popUpTo="@id/passwordListFragment"
app:popUpToInclusive="true"
app:enterAnim="@anim/slide_in_right"
app:exitAnim="@anim/slide_out_right"
app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_left" />
<argument
android:name="editData"
app:argType="com.highcom.passwordmemo.ui.PasswordEditData" />
</fragment>
</navigation>
Animationの設定
app:enterAnim="@anim/slide_in_left"
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_in_right"
app:popExitAnim="@anim/slide_out_right"
上記の設定に対するAnimationファイルを設定します。
res/anim
フォルダ配下に以下のファイルを設定。
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="@android:integer/config_shortAnimTime"
android:fromXDelta="100%"
android:toXDelta="0%" />
</set>
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="@android:integer/config_shortAnimTime"
android:fromXDelta="0%"
android:toXDelta="-100%" />
</set>
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="@android:integer/config_shortAnimTime"
android:fromXDelta="-100%"
android:toXDelta="0%" />
</set>
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="@android:integer/config_shortAnimTime"
android:fromXDelta="0%"
android:toXDelta="100%" />
</set>
この設定をすることで、Navigationによる画面遷移時に、左から右にスライドするような画面遷移の挙動になります。
SafeArgsによるパラメータの引き渡し
NavigationにSafeArgsを設定
<argument
android:name="editData"
app:argType="com.highcom.passwordmemo.ui.PasswordEditData" />
action
タグの中にargument
を設定する事でデータの受け渡しが実現できます。
app:argType
に設定するのは基本的にはプリミティブ型なのですが、データクラスのような値を渡したい場合には、以下のようなParcelable
を継承したデータクラスを作成します。
package com.highcom.passwordmemo.ui
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
@Parcelize
data class PasswordEditData(
val edit: Boolean = false,
val id: Long = 0,
val title: String = "",
val account: String = "",
val password: String = "",
val url: String = "",
val groupId: Long = 1,
val memo: String = "",
val inputDate: String = "",
) : Parcelable
Navigationを利用した画面遷移の呼び出し
val passwordEditData = PasswordEditData()
findNavController().navigate(PasswordListFragmentDirections.actionPasswordListFragmentToInputPasswordFragment(editData = passwordEditData))
上記のようにfindNavController().navigate
で必要な画面遷移のアクションを呼び出して、引数にSafeArgsで設定したデータクラスの値を設定して呼び出す事で画面遷移が実現できます。
また、受け取る際には以下のような実装になります。
/** Navigationで渡された引数 */
private val args: InputPasswordFragmentArgs by navArgs()
val passwordEditData = args.editData
さいごに
対応について以上となります。
全体のコードについては、以下のリポジトリで公開しておりますので、参考になれば幸いです。