Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Navigation Architecture Component 入門 / shibuya....

star_zero
December 13, 2018

Navigation Architecture Component 入門 / shibuya.apk #30

star_zero

December 13, 2018
Tweet

More Decks by star_zero

Other Decks in Programming

Transcript

  1. About Me • Kenji Abe • Cookpad Inc. • Android

    Developer • Twitter: @STAR_ZERO
  2. Navigation Architecture Component • XMLで画面遷移を定義できる • Android StudioでGUIが使える • 引数も定義できる

    (SafeArgs) • DeepLinkできる • Shared Element Transitionsできる • カスタマイズできる
  3. Navigation Architecture Component • 基本は Fragment -> Fragment • Fragment

    -> Activityはできる • Activity -> Activityは簡単にはできない
 (できないことはない)
  4. build.gradle // build.gradle buildscript { dependencies { classpath "android.arch.navigation:navigation-safe-args-gradle-plugin:1.0.0- alpha08"

    } } // app/build.gradle apply plugin: "androidx.navigation.safeargs" dependencies { implementation "android.arch.navigation:navigation-fragment-ktx:1.0.0-alpha08" implementation "android.arch.navigation:navigation-ui-ktx:1.0.0-alpha08" }
  5. Navigation Graph (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" android:id="@+id/nav_graph"

    app:startDestination="@id/firstFragment"> <fragment android:id="@+id/firstFragment" android:name="com.star_zero.samplenavigation.FirstFragment" android:label="FirstFragment"> <action android:id="@+id/action_firstFragment_to_secondFragment" app:destination="@id/secondFragment" /> </fragment> <fragment android:id="@+id/secondFragment" android:name="com.star_zero.samplenavigation.SecondFragment" android:label="SecondFragment"> <action android:id="@+id/action_secondFragment_to_thirdFragment" app:destination="@id/thirdFragment" /> </fragment> <fragment android:id="@+id/thirdFragment" android:name="com.star_zero.samplenavigation.ThirdFragment" android:label="ThirdFragment" /> </navigation>
  6. Navigation Graph (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" android:id="@+id/nav_graph"

    app:startDestination="@id/firstFragment"> <fragment android:id="@+id/firstFragment" android:name="com.star_zero.samplenavigation.FirstFragment" android:label="FirstFragment"> <action android:id="@+id/action_firstFragment_to_secondFragment" app:destination="@id/secondFragment" /> </fragment> </navigation> Fragmentの定義
  7. Navigation Graph (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" android:id="@+id/nav_graph"

    app:startDestination="@id/firstFragment"> <fragment android:id="@+id/firstFragment" android:name="com.star_zero.samplenavigation.FirstFragment" android:label="FirstFragment"> <action android:id="@+id/action_firstFragment_to_secondFragment" app:destination="@id/secondFragment" /> </fragment> </navigation> 最初に表示されるFragment
  8. Navigation Graph (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" android:id="@+id/nav_graph"

    app:startDestination="@id/firstFragment"> <fragment android:id="@+id/firstFragment" android:name="com.star_zero.samplenavigation.FirstFragment" android:label="FirstFragment"> <action android:id="@+id/action_firstFragment_to_secondFragment" app:destination="@id/secondFragment" /> </fragment> </navigation> 画面遷移の定義
  9. Code fun navigate() { val navController = findNavController() navController .navigate(R.id.action_firstFragment_to_secondFragment)

    } NavController取得 <action android:id="@+id/action_firstFragment_to_secondFragment" app:destination="@id/secondFragment" /> Nav Graphに設定した <action>のid
  10. 引数の型いろいろ <!-- boolean --> <argument android:name="flag" android:defaultValue="false" app:argType="boolean" /> <!--

    int array --> <argument android:name="integers" app:argType="integer[]" /> <!-- enum --> <argument android:name="type" android:defaultValue="Hoge" app:argType="com.star_zero.samplenavigation.Type" />
  11. <!-- Parcelable --> <argument android:name="user" app:argType="com.star_zero.samplenavigation.User" app:nullable="true" /> <!-- Parcelable

    array --> <argument android:name="users" app:argType="com.star_zero.samplenavigation.User[]" /> 引数の型いろいろ https://android.googlesource.com/platform/frameworks/support/+/ 6f59e3d74d0da5a4bf79c8480f56964e3af47f1c/navigation/safe-args-generator/src/main/kotlin/ androidx/navigation/safe/args/generator/Types.kt
  12. Code (ワタス側) val userId = getUserId() val userName = getUserName()

    val action = FirstFragmentDirections .actionFirstFragmentToSecondFragment(userId) action.setUserName(userName) findNavController().navigate(action)
  13. Code (ワタス側) val userId = getUserId() val userName = getUserName()

    val action = FirstFragmentDirections .actionFirstFragmentToSecondFragment(userId) action.setUserName(userName) findNavController().navigate(action) ワタス側のFragmentクラス名 + Directions
  14. Code (ワタス側) val userId = getUserId() val userName = getUserName()

    val action = FirstFragmentDirections .actionFirstFragmentToSecondFragment(userId) action.setUserName(userName) findNavController().navigate(action) <action>のidから生成されたメソッド これに引数をワタス(default値がないもののみ)
  15. Code (ワタス側) val userId = getUserId() val userName = getUserName()

    val action = FirstFragmentDirections .actionFirstFragmentToSecondFragment(userId) action.setUserName(userName) findNavController().navigate(action) default値が設定されてるものは setterにワタス
  16. Code (ワタス側) val userId = getUserId() val userName = getUserName()

    val action = FirstFragmentDirections .actionFirstFragmentToSecondFragment(userId) action.setUserName(userName) findNavController().navigate(action) 最後にnavigateメソッドにワタス
  17. Code (モラウ側) val args = SecondFragmentArgs.fromBundle(arguments) // Activityの場合 val args

    = SecondActivityArgs.fromBundle(intent.extras) Timber.d("user_id: ${args.userId}") Timber.d("user_name: ${args.userName}") fromBundleで引数を取得
  18. ActionBar class MainActivity : AppCompatActivity() { private lateinit var appBarConfiguration:

    AppBarConfiguration override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val navController = findNavController(R.id.nav_host_fragment) appBarConfiguration = AppBarConfiguration(navController.graph) setupActionBarWithNavController(navController, appBarConfiguration) } override fun onSupportNavigateUp(): Boolean { return findNavController(R.id.nav_host_fragment) .navigateUp(appBarConfiguration) || super.onSupportNavigateUp() } }
  19. ActionBar class MainActivity : AppCompatActivity() { private lateinit var appBarConfiguration:

    AppBarConfiguration override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val navController = findNavController(R.id.nav_host_fragment) appBarConfiguration = AppBarConfiguration(navController.graph) setupActionBarWithNavController(navController, appBarConfiguration) } override fun onSupportNavigateUp(): Boolean { return findNavController(R.id.nav_host_fragment) .navigateUp(appBarConfiguration) || super.onSupportNavigateUp() } } AppBarConfigurationを使って NavGraphとActionBarを連携
  20. ActionBar class MainActivity : AppCompatActivity() { private lateinit var appBarConfiguration:

    AppBarConfiguration override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val navController = findNavController(R.id.nav_host_fragment) appBarConfiguration = AppBarConfiguration(navController.graph) setupActionBarWithNavController(navController, appBarConfiguration) } override fun onSupportNavigateUp(): Boolean { return findNavController(R.id.nav_host_fragment) .navigateUp(appBarConfiguration) || super.onSupportNavigateUp() } } 左上の矢印ボタンを押したとき
  21. Toolbar class MainActivity : AppCompatActivity() { private lateinit var binding:

    ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = DataBindingUtil .setContentView(this, R.layout.activity_main) val navController = findNavController(R.id.nav_host_fragment) val appBarConfiguration = AppBarConfiguration(navController.graph) binding.toolbar .setupWithNavController(navController, appBarConfiguration) } }
  22. Toolbar class MainActivity : AppCompatActivity() { private lateinit var binding:

    ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = DataBindingUtil .setContentView(this, R.layout.activity_main) val navController = findNavController(R.id.nav_host_fragment) val appBarConfiguration = AppBarConfiguration(navController.graph) binding.toolbar .setupWithNavController(navController, appBarConfiguration) } } ActionBarの時と同様 onSupportNavigateUpは設定しなくて良い
  23. Navigation Graph - Menu Item <fragment android:id="@+id/menuFragment" android:name="com.star_zero.samplenavigation.MenuFragment" android:label="MenuFragment" />

    <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <item android:id="@+id/menuFragment" android:icon="@drawable/ic_star" android:title="@string/menu" app:showAsAction="ifRoom" /> </menu>
  24. Navigation Graph - Menu Item <fragment android:id="@+id/menuFragment" android:name="com.star_zero.samplenavigation.MenuFragment" android:label="MenuFragment" />

    <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <item android:id="@+id/menuFragment" android:icon="@drawable/ic_star" android:title="@string/menu" app:showAsAction="ifRoom" /> </menu> idを一致させる
  25. Code override fun onOptionsItemSelected(item: MenuItem): Boolean { val navController =

    findNavController() return item.onNavDestinationSelected(navController) || super.onOptionsItemSelected(item) }
  26. Navigation Graph <fragment android:id="@+id/menu_home" android:name="com.star_zero.samplenavigation.HomeFragment" android:label="HomeFragment" /> <fragment android:id="@+id/menu_favorite" android:name="com.star_zero.samplenavigation.FavoriteFragment"

    android:label="FavoriteFragment" /> <fragment android:id="@+id/menu_search" android:name="com.star_zero.samplenavigation.SearchFragment" android:label="SearchFragment" />
  27. bottom_nav.xml <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/menu_home" android:icon="@drawable/ic_home" android:title="@string/menu_home" /> <item android:id="@+id/menu_favorite"

    android:icon="@drawable/ic_favorite" android:title="@string/menu_favorite" /> <item android:id="@+id/menu_search" android:icon="@drawable/ic_search" android:title="@string/menu_search" /> </menu>
  28. Navigation Graph - bottom_nav.xml <fragment android:id="@+id/menu_home" android:name="com.star_zero.samplenavigation.HomeFragment" android:label="HomeFragment" /> <!--

    ... --> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/menu_home" android:icon="@drawable/ic_home" android:title="@string/menu_home" /> <!-- ... --> </menu> idを一致させる
  29. Code class MainActivity : AppCompatActivity() { private lateinit var binding:

    ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = DataBindingUtil .setContentView(this, R.layout.activity_main) val navController = findNavController(R.id.nav_host_fragment) binding.bottomNav.setupWithNavController(navController) } }
  30. Activity val options = ActivityOptionsCompat.makeSceneTransitionAnimation( requireActivity(), view, "image" ) val

    extras = ActivityNavigator.Extras.Builder() .setActivityOptions(options) .build() findNavController().navigate( R.id.action_hoge_to_foo, null, null, extras )
  31. Navigator @Navigator.Name("keep_state_fragment") class KeepStateNavigator( private val context: Context, private val

    manager: FragmentManager, private val containerId: Int ) : FragmentNavigator(context, manager, containerId) { override fun navigate( destination: Destination, args: Bundle?, navOptions: NavOptions?, navigatorExtras: Navigator.Extras? ): NavDestination? { // ... } }
  32. Navigation Graph <?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" android:id="@+id/nav_graph" app:startDestination="@id/firstFragment">

    <keep_state_fragment android:id="@+id/firstFragment" android:name="com.star_zero.samplenavigation.FirstFragment" android:label="FirstFragment" /> <keep_state_fragment android:id="@+id/secondFragment" android:name="com.star_zero.samplenavigation.SecondFragment" android:label="SecondFragment" /> </keep_state_fragment> <keep_state_fragment android:id="@+id/thirdFragment" android:name="com.star_zero.samplenavigation.ThirdFragment" android:label="ThirdFragment" /> </navigation>
  33. Activity val navController = findNavController(R.id.nav_host_fragment) val navHostFragment = supportFragmentManager .findFragmentById(R.id.nav_host_fragment)!!

    val navigator = KeepStateNavigator( this, navHostFragment.childFragmentManager, R.id.nav_host_fragment ) navController.navigatorProvider += navigator navController.setGraph(R.navigation.nav_graph)