Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Navigation Architecture Component 入門 / shibuya....
Search
star_zero
December 13, 2018
Programming
780
4
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Navigation Architecture Component 入門 / shibuya.apk #30
star_zero
December 13, 2018
More Decks by star_zero
See All by star_zero
今からはじめるAndroidアプリ開発 2024 / DevFest 2024
star_zero
0
1.6k
Jetpack Compose の Side-effect を使いこなす / DroidKaigi 2023
star_zero
5
7.1k
Android 14 新機能 / Android 14 Meetup Nagoya
star_zero
1
680
Android 14 と Predictive back gesture / Shibuya.apk #42
star_zero
0
490
Coroutines Test 入門 / Android Test Night #8
star_zero
2
1.3k
What's new in Jetpack / I/O Extended Japan 2022
star_zero
1
710
Kotlin 2021 Recap / DevFest 2021
star_zero
3
1.4k
Kotlin Symbol Processing (KSP) を使ったコード生成 / DroidKaigi 2021
star_zero
2
5.3k
What's new Android 12
star_zero
0
620
Other Decks in Programming
See All in Programming
A2UI という光を覗いてみる
satohjohn
1
140
Hunting Vulnerabilities in Symfony with LLMs
vinceamstoutz
0
550
1B+ /day規模のログを管理する技術
broadleaf
0
100
技術的負債解消で開発者の未来を開く- AIの力でコード刷新
kmd2kmd
0
110
ローカルLLMを使ってB2Bサービスを作っていての学び
yaotti
0
200
Language Server 使ってる? 〜VSCode と Zed の場合〜 / Are you using a Language Server? ~For VS Code and Zed~
handlename
0
800
LLMによるContent Moderationの本番運用の裏側と品質担保への挑戦
suikabar
3
720
エージェンティックRAGにAWSで入門しよう!
har1101
8
1.7k
Mujeres en SEO Summit 2026 - Greatest Disaster Hits en Web Performance
guaca
0
190
その問い、本当に正しいですか?AI時代のエンジニアに必要な哲学と認知科学 / ai-philosophy-cognitive-science
minodriven
11
5.9k
並列実装の現場、2ヶ月間実務でAIを使い倒したAIもPCも私も限界が近い
ming_ayami
0
130
作って学ぶ、 JSX (TSX) ランタイムの基本
syumai
7
1.7k
Featured
See All Featured
The Limits of Empathy - UXLibs8
cassininazir
1
360
Heart Work Chapter 1 - Part 1
lfama
PRO
7
36k
How to Align SEO within the Product Triangle To Get Buy-In & Support - #RIMC
aleyda
2
1.5k
Impact Scores and Hybrid Strategies: The future of link building
tamaranovitovic
0
310
SEO Brein meetup: CTRL+C is not how to scale international SEO
lindahogenes
1
2.7k
Embracing the Ebb and Flow
colly
88
5.1k
Data-driven link building: lessons from a $708K investment (BrightonSEO talk)
szymonslowik
1
1.1k
The B2B funnel & how to create a winning content strategy
katarinadahlin
PRO
1
390
Getting science done with accelerated Python computing platforms
jacobtomlinson
2
240
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
10
1.2k
Conquering PDFs: document understanding beyond plain text
inesmontani
PRO
4
2.8k
Marketing to machines
jonoalderson
1
5.5k
Transcript
Navigation Architecture Component 入門 shibuya.apk #30
About Me • Kenji Abe • Cookpad Inc. • Android
Developer • Twitter: @STAR_ZERO
Navigation Architecture Component
⚠注意⚠ まだ alpha08
Navigation Architecture Component • XMLで画面遷移を定義できる • Android StudioでGUIが使える • 引数も定義できる
(SafeArgs) • DeepLinkできる • Shared Element Transitionsできる • カスタマイズできる
Navigation Architecture Component • 基本は Fragment -> Fragment • Fragment
-> Activityはできる • Activity -> Activityは簡単にはできない (できないことはない)
基本的な使い方
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" }
Navigation Graph (Navigation Editor) res/navigation/nav_graph.xml
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>
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の定義
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
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> 画面遷移の定義
Layout <fragment android:id="@+id/nav_host_fragment" android:name="androidx.navigation.fragment.NavHostFragment" android:layout_width="0dp" android:layout_height="0dp" app:defaultNavHost="true" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" app:navGraph="@navigation/nav_graph" />
Layout <fragment android:id="@+id/nav_host_fragment" android:name="androidx.navigation.fragment.NavHostFragment" android:layout_width="0dp" android:layout_height="0dp" app:defaultNavHost="true" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" app:navGraph="@navigation/nav_graph" /> Navigtion用のFragment BackButtonの制御 画面遷移を定義したXML
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
引数
Navigation Graph (Navigation Editor)
<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" /> <argument android:name="user_id"
app:argType="integer" /> <argument android:name="user_name" android:defaultValue="ABC" app:argType="string" /> </fragment> Navigation Graph (XML)
引数の型いろいろ <!-- 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" />
<!-- 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
Code (ワタス側) val userId = getUserId() val userName = getUserName()
val action = FirstFragmentDirections .actionFirstFragmentToSecondFragment(userId) action.setUserName(userName) findNavController().navigate(action)
Code (ワタス側) val userId = getUserId() val userName = getUserName()
val action = FirstFragmentDirections .actionFirstFragmentToSecondFragment(userId) action.setUserName(userName) findNavController().navigate(action) ワタス側のFragmentクラス名 + Directions
Code (ワタス側) val userId = getUserId() val userName = getUserName()
val action = FirstFragmentDirections .actionFirstFragmentToSecondFragment(userId) action.setUserName(userName) findNavController().navigate(action) <action>のidから生成されたメソッド これに引数をワタス(default値がないもののみ)
Code (ワタス側) val userId = getUserId() val userName = getUserName()
val action = FirstFragmentDirections .actionFirstFragmentToSecondFragment(userId) action.setUserName(userName) findNavController().navigate(action) default値が設定されてるものは setterにワタス
Code (ワタス側) val userId = getUserId() val userName = getUserName()
val action = FirstFragmentDirections .actionFirstFragmentToSecondFragment(userId) action.setUserName(userName) findNavController().navigate(action) 最後にnavigateメソッドにワタス
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で引数を取得
Deep Link
Navigation Graph (Navigation Editor)
Navigation Graph (XML) <fragment android:id="@+id/deepLinkFragment" android:name="com.star_zero.samplenavigation.DeepLinkFragment" android:label="DeepLinkFragment"> <deepLink app:uri="star-zero.com/{id}" />
</fragment> スキーマ省略時はhttpとhttpsに対応 {id}はプレースホルダー パラメーターとして取得可能
AndroidManifest.xml <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> <nav-graph android:value="@navigation/nav_graph" /> </activity>
Code (パラメーターをモラウ) val args = arguments?.getString("id") Timber.d("args: ${args}")
NavigationUI
ActionBar
None
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() } }
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を連携
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() } } 左上の矢印ボタンを押したとき
Toolbar
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) } }
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は設定しなくて良い
Menu Item
None
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>
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を一致させる
Code override fun onOptionsItemSelected(item: MenuItem): Boolean { val navController =
findNavController() return item.onNavDestinationSelected(navController) || super.onOptionsItemSelected(item) }
Bottom Navigation
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" />
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>
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を一致させる
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) } }
Shared Element Transitions https://github.com/STAR-ZERO/navigation-shared-element
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 )
Fragment val extra = FragmentNavigatorExtras(view to "image") findNavController().navigate( R.id.action_gridFragment_to_imageFragment, null,
null, extra )
カスタマイズ https://github.com/STAR-ZERO/navigation-keep-fragment-sample
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? { // ... } }
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>
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)
まとめ
まとめ • 単純な画面遷移は難しくない • SafeArgs便利 • ちょっと凝ったことする時はカスタマイズ必要 • ちょっとずつ導入可能 •
Single Activity
ありがとうございました