Navigation Components を使ってみる
書いてあるがわかりにくい定期
これを読んで良さそうと思った
辞書的に見るのに良さそうな
dependencies {
def nav_version = "2.3.3"
// Java language implementation
implementation "androidx.navigation:navigation-fragment:$nav_version"
implementation "androidx.navigation:navigation-ui:$nav_version"
// Kotlin
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
// Feature module Support
implementation "androidx.navigation:navigation-dynamic-features-fragment:$nav_version"
// Testing Navigation
androidTestImplementation "androidx.navigation:navigation-testing:$nav_version"
// Jetpack Compose Integration
implementation "androidx.navigation:navigation-compose:1.0.0-alpha07"
}
これは全部書かないとだめなんだろうか
dependencies {
def nav_version = "【任意のバージョン】"
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
}
まずこれだけ
fragmentTransaction
とか intent
とか使ってたところから同移行するのかわからぬ
ここクリックしたら、既存のが選択肢にでてきた
遷移の矢印が出るらしいが出し方がわからない
矢印クリックしたところからdestination指定で追加できた
activity -> activity はこれではあんまり扱わんのかな
設定した時の挙動がよくわからぬ
fragment の遷移を定義しておいて、それを root の activity で呼び出して、セットすると、fragment の遷移ができるようになる、みたいなことだろうか
初期 fragment はどのタイミングで入るのか
空っぽのフラグメントに
private fun replaceFragment(fragment: Fragment) {
val fragmentManager = supportFragmentManager
val fragmentTransaction = fragmentManager.beginTransaction()
fragmentTransaction.replace(R.id.fragment_container, fragment)
fragmentTransaction.commit()
}
こんな感じで入れていたところ
setupActionBarWithNavController でセットされるのか、その後になんか呼ぶ必要があるのか
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity)
val navController = findNavController(R.id.main_nav_host)
val appBarConfiguration = AppBarConfiguration(navController.graph)
setupActionBarWithNavController(navController, appBarConfiguration)
}
override fun onSupportNavigateUp()
= findNavController(R.id.main_nav_host).navigateUp()
}
ここ書いたけど
java.lang.RuntimeException: Unable to start activity ComponentInfo{}: java.lang.IllegalArgumentException: ID does not reference a View inside this Activity
で落ちる
画面サイズごとに呼び出し先の activity を変えてるので、同じ名前のが複数あって、全部に適用できてなかった
val navController = findNavController(R.id.top_up_nav_host)
val appBarConfiguration = AppBarConfiguration(navController.graph)
setupActionBarWithNavController(navController, appBarConfiguration)
これで does not have a NavController set on
みたいなエラーが出た
val navController = supportFragmentManager.findFragmentById(R.id.top_up_nav_host) as NavHostFragment
setupActionBarWithNavController(navController.navController)
これもだめ
java.lang.RuntimeException: Unable to start activity ComponentInfo{}: java.lang.NullPointerException: Attempt to invoke virtual method 'void androidx.appcompat.app.ActionBar.setTitle(java.lang.CharSequence)' on a null object reference
val navController = supportFragmentManager.findFragmentById(R.id.top_up_nav_host) as NavHostFragment
setupActionBarWithNavController(navController.navController)
これもだめ
java.lang.RuntimeException: Unable to start activity ComponentInfo{}: java.lang.NullPointerException: Attempt to invoke virtual method 'void androidx.appcompat.app.ActionBar.setTitle(java.lang.CharSequence)' on a null object reference
github で探してみたけど良いのがでてこない
これ良さそうな気配
class MainFragment() : ContainerBaseFragment(R.layout.fragment_main) {
private lateinit var binding: FragmentTopBinding
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentMainBinding.inflate(inflater)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.nextButton.setOnClickListener {
findNavController().navigate(R.id.{action_id})
}
}
}
これだけでいけた
findNavController().navigate(R.id.{action_id})
これかいただけ
fragment に書かないといけなかった?
{action_id} は、navigation.xml で定義したものの action の id
最小構成で動いたので、Safe Args をいれてみる
class MainFragment() : ContainerBaseFragment(R.layout.fragment_main) {
private lateinit var binding: FragmentTopBinding
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentMainBinding.inflate(inflater)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.nextButton.setOnClickListener {
findNavController().navigate(MainFragmentDirections.actionMainFragmentToSecondFragment())
}
}
}
こんな感じで動くようになった
あとは fragment 間で値渡しがやりたい
findNavController().navigate({Fragment名}Directions.action())
Fragment名が自クラスと異なっていると、遷移発火時にエラーで落ちる
java.lang.IllegalArgumentException: Navigation action/destination
(ビルド時に検出できないものなのか)
<action
android:id="@+id/action_mainFragment_to_secondFragment"
app:destination="@id/secondFragment"
app:popUpToInclusive="false" />
app:popUpToInclusive="false"
にしても backstack 積まれてる
どうして
用語 | 説明 |
---|---|
Pop To |
Back ボタンを押したとき、どこの画面まで戻るか指定できる |
Inclusive |
Pop Up で指定した画面の1つ前に戻るようにする |
app:popUpToInclusive="false"
これは backstack を積まないとかそういうことではないっぽい
app:popUpTo={Root}
これすると、アプリ終了まで戻る
app:popUpTo="@id/MainFragment"
で複数遷移した後のどの位置にいても back すると Main までもどる
他の指定方法がありそうな気もするけど
一旦できたのでおわり
activity から activity 移動したい
activity の fragment -> activity はできても
activity 単体 -> activity はできなさそう