Slide 1

Slide 1 text

Navigation Architecture Component 入門 shibuya.apk #30

Slide 2

Slide 2 text

About Me • Kenji Abe • Cookpad Inc. • Android Developer • Twitter: @STAR_ZERO

Slide 3

Slide 3 text

Navigation Architecture Component

Slide 4

Slide 4 text

⚠注意⚠ まだ alpha08

Slide 5

Slide 5 text

Navigation Architecture Component • XMLで画面遷移を定義できる • Android StudioでGUIが使える • 引数も定義できる (SafeArgs) • DeepLinkできる • Shared Element Transitionsできる • カスタマイズできる

Slide 6

Slide 6 text

Navigation Architecture Component • 基本は Fragment -> Fragment • Fragment -> Activityはできる • Activity -> Activityは簡単にはできない
 (できないことはない)

Slide 7

Slide 7 text

基本的な使い方

Slide 8

Slide 8 text

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" }

Slide 9

Slide 9 text

Navigation Graph (Navigation Editor) res/navigation/nav_graph.xml

Slide 10

Slide 10 text

Navigation Graph (XML)

Slide 11

Slide 11 text

Navigation Graph (XML) Fragmentの定義

Slide 12

Slide 12 text

Navigation Graph (XML) 最初に表示されるFragment

Slide 13

Slide 13 text

Navigation Graph (XML) 画面遷移の定義

Slide 14

Slide 14 text

Layout

Slide 15

Slide 15 text

Layout Navigtion用のFragment BackButtonの制御 画面遷移を定義したXML

Slide 16

Slide 16 text

Code fun navigate() { val navController = findNavController() navController .navigate(R.id.action_firstFragment_to_secondFragment) } NavController取得 Nav Graphに設定した のid

Slide 17

Slide 17 text

引数

Slide 18

Slide 18 text

Navigation Graph (Navigation Editor)

Slide 19

Slide 19 text

Navigation Graph (XML)

Slide 20

Slide 20 text

引数の型いろいろ

Slide 21

Slide 21 text

引数の型いろいろ https://android.googlesource.com/platform/frameworks/support/+/ 6f59e3d74d0da5a4bf79c8480f56964e3af47f1c/navigation/safe-args-generator/src/main/kotlin/ androidx/navigation/safe/args/generator/Types.kt

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

Code (ワタス側) val userId = getUserId() val userName = getUserName() val action = FirstFragmentDirections .actionFirstFragmentToSecondFragment(userId) action.setUserName(userName) findNavController().navigate(action) 最後にnavigateメソッドにワタス

Slide 27

Slide 27 text

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で引数を取得

Slide 28

Slide 28 text

Deep Link

Slide 29

Slide 29 text

Navigation Graph (Navigation Editor)

Slide 30

Slide 30 text

Navigation Graph (XML) スキーマ省略時はhttpとhttpsに対応 {id}はプレースホルダー パラメーターとして取得可能

Slide 31

Slide 31 text

AndroidManifest.xml

Slide 32

Slide 32 text

Code (パラメーターをモラウ) val args = arguments?.getString("id") Timber.d("args: ${args}")

Slide 33

Slide 33 text

NavigationUI

Slide 34

Slide 34 text

ActionBar

Slide 35

Slide 35 text

No content

Slide 36

Slide 36 text

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() } }

Slide 37

Slide 37 text

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を連携

Slide 38

Slide 38 text

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() } } 左上の矢印ボタンを押したとき

Slide 39

Slide 39 text

Toolbar

Slide 40

Slide 40 text

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) } }

Slide 41

Slide 41 text

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は設定しなくて良い

Slide 42

Slide 42 text

Menu Item

Slide 43

Slide 43 text

No content

Slide 44

Slide 44 text

Navigation Graph - Menu Item

Slide 45

Slide 45 text

Navigation Graph - Menu Item idを一致させる

Slide 46

Slide 46 text

Code override fun onOptionsItemSelected(item: MenuItem): Boolean { val navController = findNavController() return item.onNavDestinationSelected(navController) || super.onOptionsItemSelected(item) }

Slide 47

Slide 47 text

Bottom Navigation

Slide 48

Slide 48 text

Navigation Graph

Slide 49

Slide 49 text

bottom_nav.xml

Slide 50

Slide 50 text

Navigation Graph - bottom_nav.xml idを一致させる

Slide 51

Slide 51 text

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) } }

Slide 52

Slide 52 text

Shared Element Transitions https://github.com/STAR-ZERO/navigation-shared-element

Slide 53

Slide 53 text

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 )

Slide 54

Slide 54 text

Fragment val extra = FragmentNavigatorExtras(view to "image") findNavController().navigate( R.id.action_gridFragment_to_imageFragment, null, null, extra )

Slide 55

Slide 55 text

カスタマイズ https://github.com/STAR-ZERO/navigation-keep-fragment-sample

Slide 56

Slide 56 text

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? { // ... } }

Slide 57

Slide 57 text

Navigation Graph

Slide 58

Slide 58 text

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)

Slide 59

Slide 59 text

まとめ

Slide 60

Slide 60 text

まとめ • 単純な画面遷移は難しくない • SafeArgs便利 • ちょっと凝ったことする時はカスタマイズ必要 • ちょっとずつ導入可能 • Single Activity

Slide 61

Slide 61 text

ありがとうございました