Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Navigation Component 実践編
Search
yoppie
December 03, 2019
Technology
310
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Navigation Component 実践編
yoppie
December 03, 2019
More Decks by yoppie
See All by yoppie
AmperとFleetを使ったAndroidアプリ
yoppie
0
1.1k
Androidエンジニアが Flutterでアプリを リリースするまでの苦悩
yoppie
0
560
FragmentContainerViewとは
yoppie
0
820
Recent tips collection
yoppie
0
1.1k
Distribute Android app updates with bitrise
yoppie
0
1.4k
EC2 using Lumen and DynamoDB and SNS
yoppie
1
300
sabotage
yoppie
1
1k
Play with Kotlin
yoppie
1
660
Other Decks in Technology
See All in Technology
Tofu-Controller lightning talk @ Containerday 2026
gionn
0
120
実体験から学ぶ分析エージェントの開発と運⽤
recruitengineers
PRO
8
2.4k
Classmethod Company Deck
satoshi7
1
730
Local CI × GitHub Actions
gogutan
3
230
DGX Spark でどこまでハッキングができるのか?
kash1064
3
1.4k
二歩目のフロントエンド・ウェブアクセシビリティ
camiha
2
660
Getting Started with Google Antigravity
glaforge
0
320
AIがコードを書く時代に、エンジニアは何で自分の価値を証明するのか / In an era where AI writes code how do engineers prove their value
carta_engineering
3
1.1k
OptunaHub: ブラックボックス最適化のためのプラットフォーム
pfn
PRO
0
140
アウトプット初心者、半年間のふりかえり
4o1sobblue
0
440
Gemini Intelligence 入門 ― AppFunctions と Gemini Nano
takuroabe
0
290
TinyGoでオブザーバビリティ?OpenTelemetryはTinyGoで使えるのか / Is OpenTelemetry available in TinyGo environment?
ymotongpoo
2
140
Featured
See All Featured
Dominate Local Search Results - an insider guide to GBP, reviews, and Local SEO
greggifford
PRO
0
370
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
12
1.3k
Jess Joyce - The Pitfalls of Following Frameworks
techseoconnect
PRO
1
450
Six Lessons from altMBA
skipperchong
29
4.5k
SERP Conf. Vienna - Web Accessibility: Optimizing for Inclusivity and SEO
sarafernandez
2
1.6k
The #1 spot is gone: here's how to win anyway
tamaranovitovic
4
1.2k
Claude Code のすすめ
schroneko
67
230k
The SEO Collaboration Effect
kristinabergwall1
1
590
Why Your Marketing Sucks and What You Can Do About It - Sophie Logan
marketingsoph
0
430
エンジニアに許された特別な時間の終わり
watany
109
250k
職位にかかわらず全員がリーダーシップを発揮するチーム作り / Building a team where everyone can demonstrate leadership regardless of position
madoxten
69
67k
The Hidden Cost of Media on the Web [PixelPalooza 2025]
tammyeverts
2
530
Transcript
/BWJHBUJPO$PNQPOFOU ࣮ફฤ
'BDFCPPLIJLPXBJJEF5XJUUFS!ZPQQJF@Y (JUIVCZPTIJZB92JJUBZPQQJF@Y ϒϩάIUUQTZPQQJFYIBUFOBCMPHDPN ZPQQJF
ͪΐͬͱখ
None
%SPJE,BJHJ
'SBHNFOU$POUBJOFS7JFX ͱ
/BWJHBUJPO$PNQPOFOU ࣮ફฤ
w "OESPJE+FUQBDLʹؚ·Ε͍ͯΔίϯϙʔωϯτ w "DUJWJUZ'SBHNFOUؒͷը໘ભҠΛγϯϓϧʹ࣮Ͱ͖Δ w ར w 'SBHNFOU5SBOTBDUJPOͷॲཧΛϥΠϒϥϦ͕ߦ͏ w %FFQ-JOLͷ࣮ͷ؆қԽ
w 4BGF"SHTΛ༻͍ͨܕ҆શͷ͠ w ը໘ભҠͷύλʔϯΛ9.-ʹఆٛ͠ՄࢹԽ /BWJHBUJPO(SBQI /BWJHBUJPO$PNQPOFOU
None
4IBSFE7JFX.PEFM Λ༻͍ͨڞ༗
՝ 'SBHNFOU͔Β'SBHNFOU͠Λ͢Δ߹ ௨ৗ4BGF"SHTΛ༻͍ͨܕ҆શͷ͢͠Δ ͔͠͠ϗετ͍ͯ͠Δ"DUJWJUZͱ֤'SBHNFOUͰԿ͔Λ ڞ༗͢Δ͜ͱ͕Ͱ͖ͳ͍ 5PPMCBSͷ5JUMFͷมߋɺ4OBDLCBSͷදࣔΛ ֤'SBHNFOUͰߦͳΘͣ"DUJWJUZʹ·ͱΊ͍ͨ
Activity Fragment 1 Fragment 4 Fragment 3 Fragment 2 SharedViewModel
ղܾࡦ
4IBSFE7JFX.PEFMͷྫ class SharedViewModel : ViewModel(){ val fragmentType = MutableLiveData<FragmentType>().apply {
this.value = FragmentType.FIRST } } enum class FragmentType(val type: String) { FIRST("first"), SECOND("second"), THIRD("third"), FOURTH("fourth") }
"DUJWJUZͰ0CTFSWF val sharedViewModel = ViewModelProviders.of(this).get(SharedViewModel::class.java) sharedViewModel.fragmentType.observe(this, Observer { value ->
value?.let { Snackbar.make( findViewById(android.R.id.content), it.type, Snackbar.LENGTH_SHORT ).show() } }) 4IBSFE7JFX.PEFMͷGSBHNFOU5ZQF͕มߋ͞Εͨ࣌ʹ 4OBDLCBS͕දࣔ͞ΕΔ
'SBHNFOUͰQPTU7BMVF sharedViewModel = ViewModelProviders.of(requireActivity()).get(SharedViewModel::class.java) snackbarButton.clicks().subscribe { sharedViewModel.fragmentType.postValue(FragmentType.FIRST) } "DUJWJUZͰ0CTFSWF͍ͯ͠ΔͷͰɺ 'SBHNFOUͷ4IBSFE7JFX.PEFMͷΠϯελϯεΛ
7JFX.PEFM1SPWJEFSTPG ͷҾʹSFRVJSF"DUJWJUZ Λ ࢦఆ͠ͷ"DUJWJUZʹͻ͚ͮͯ࡞
݁Ռ 4IBSFE7JFX.PEFMΛ࡞Δ͜ͱͰɺ ϗετ͍ͯ͠Δ"DUJWJUZͱ ֤'SBHNFOUͰΛڞ༗ "DUJWJUZʹॲཧΛू
ը໘ભҠޙͱ ը໘ભҠ࣌ͷذॲཧ
՝ "DUJWJUZ͕࣋ͭ5PPMCBS'MPBUJOH"DUJPO#VUUPOͳͲͷ 7JFXͷڍಈΛ'SBHNFOUʹґଘͯ͠มߋͨ͠Γɺ 'SBHNFOUؒͷը໘ભҠ࣌ʹม͍͑ͨ ͔͠͠ɺ'SBHNFOUʹ"DUJWJUZ͕࣋ͭ7JFXͷڍಈͷॲཧΛ ॻ͖ͨ͘ͳ͍ why? val toolbar =
view.findViewById<Toolbar>(R.id.toolbar) requireActivity().setSupportActionBar(toolbar)
'SBHNFOUʹґଘͨ͠ڍಈͷมߋ ͳͷͰ'SBHNFOUͰॻ͖ͨ͘ͳΔ ͔͠͠5PPMCBS"DUJWJUZ͕อ༗ͯ͠ ͍ΔͷͰɺอकੑͷ؍͔Β "DUJWJUZͰॻ͖͘ )PNF'SBHNFOUͷ߹ͷΈ 5PPMCBSͷΔϘλϯԡԼ࣌ ͷڍಈΛมߋ͍ͨ͠
ղܾࡦ /BW$POUSPMMFSͷ DVSSFOU%FTUJOBUJPO BEE0O%FTUJOBUJPO$IBOHFE-JTUFOFS Λར༻
binding.toolbar .navigationClicks() .filter { navController.currentDestination != null } .subscribe {
when (navController.currentDestination!!.id) { R.id.homeFragment -> finish() R.id.secondFragment -> navController.navigate( SecondFragmentDirections.homeToFirst() ) } } navController = findNavController(R.id.container_fragment) 'SBHNFOU͝ͱʹ 5PPMCBSͷॲཧΛذ
navController.addOnDestinationChangedListener { _, destination, _ -> when (destination.id) { R.id.firstFragment
-> binding.toolbarButton.visibility = View.GONE R.id.secondFragment -> binding.toolbarButton.visibility = View.VISIBLE } } 'SBHNFOUؒͷը໘ભҠ࣌ ը໘ભҠ࣌ʹ5PPMCBSʹ͋Δ#VUUPOͷWJTJWJMJUZΛมߋ
'SBHNFOUʹґଘ͘͠'SBHNFOU ؒͷը໘ભҠʹΑΔ"DUJWJUZ͕࣋ͭ 7JFX ࠓճͷྫͩͱ5PPMCBS ͷ ڍಈมߋΛ'SBHNFOUʹॻ͔ͣʹ "DUJWJUZʹهࡌͰ͖ͨ ݁Ռ
#PUUPN/BWJHBUJPO7JFXͱͷ ซ༻࣌ͷঢ়ଶอ࣋
՝ #PUUPN/BWJHBUJPO7JFXͱ/BWJHBUJPO$PNQPOFOUΛซ༻ ͢Δ߹ɺσϑΥϧτͰλϒΓସ͑࣌ʹ'SBHNFOU͕࠶ ੜ͞Ε·͢ɻ Αͬͯɺ࠶ੜ͞Εͳ͍Α͏ʹ͢ΔͨΊʹ 'SBHNFOUͷঢ়ଶอ࣋Λ࣮͢Δඞཁ͕ ͋Γ·͢ɻ #PUUPN/BWJHBUJPO7JFX
ղܾࡦ 'SBHNFOU/BWJHBUPSΫϥεΛܧঝͨ͠ $VTUPN/BWJHBUPSΫϥεΛ࡞͠ɺ ঢ়ଶอ࣋͞ΕΔΑ͏ʹOBWJHBUF Λ্ॻ͖
@Navigator.Name("custom_fragment") class CustomNavigator( private val context: Context, private val manager:
FragmentManager, private val containerId: Int ) : FragmentNavigator(context, manager, containerId) { @Suppress("DEPRECATION") override fun navigate( destination: Destination, args: Bundle?, navOptions: NavOptions?, navigatorExtras: Navigator.Extras? ): NavDestination? { // ... } }
if (manager.isStateSaved) { return null } var className = destination.className
if (className[0] == '.') { className = context.packageName + className } val tag = destination.id.toString() val transaction = manager.beginTransaction() val currentFragment = manager.primaryNavigationFragment if (currentFragment != null) { transaction.hide(currentFragment) } var fragment = manager.findFragmentByTag(tag) if (fragment == null) { fragment = instantiateFragment(context, manager, className, args) transaction.add(containerId, fragment, tag) } fragment.arguments = args transaction.show(fragment) transaction.setPrimaryNavigationFragment(fragment) transaction.commit() return destination Ξχϝʔγϣϯͱ #BDL4UBDLपΓͷ ॲཧল͍͍ͯ·͢
class CustomNavHostFragment : NavHostFragment() { override fun createFragmentNavigator( ): Navigator<out
FragmentNavigator.Destination> { return CustomNavigator(requireContext(), childFragmentManager, id) } } /BW)PTU'SBHNFOUͷDSFBUF'SBHNFOU/BWJHBUPS ͷ Γ͕'SBHNFOU/BWJHBUPSͳͷͰܧঝͨ͠ $VTUPN/BW)PTU'SBHNFOUΛ࡞্͠ॻ͖
<navigation xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/bottom_navigation" app:startDestination="@+id/tab1"> <custom_fragment android:id="@+id/tab1" android:name="hoge.HogeFragment" android:label="tab1" android:tag="tab1"
/> OBWJHBUJPOϨΠΞτ $VTUPN/BWJHBUPSΫϥεʹ͚ͭͨ !/BWJHBUPS/BNFΞϊςʔγϣϯͷҾʹࢦఆ͍ͯ͠Δ DVTUPN@GSBHNFOUΛར༻
<fragment android:id="@+id/bottom_navigation_view_fragment" android:name="hoge.navigation.CustomNavHostFragment" android:layout_width="match_parent" android:layout_height="wrap_content" app:defaultNavHost="true" app:layout_constraintBottom_toTopOf="@id/bottom_navigation_view" app:layout_constraintTop_toBottomOf="@+id/toolbar" app:navGraph="@navigation/navigation" />
<com.google.android.material.bottomnavigation.BottomNavigationView android:id="@+id/bottom_navigation_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?android:attr/windowBackground" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:menu="@menu/bottom_navigation_menu" /> BOESPJEYOBWJHBUJPOGSBHNFOU/BW)PTU'SBHNFOU Ͱͳࣗ͘࡞ͨ͠$VTUPN/BW)PTU'SBHNFOUΛࢦఆ
݁Ռ 'SBHNFOUͷঢ়ଶอ࣋ʹޭ
࠷ޙʹ /BWJHBUJPO$PNQPOFOUΛ͏ͱ "DUJWJUZ'SBHNFOUؒͷը໘ભҠΛ γϯϓϧʹ࣮Ͱ͖Δ ࣮ફͰಋೖ͢ΔͱͳΔͱ ӡ༻อकੑΛߟྀ͢ΔΑ͏ʹͳΓ ҙ͕ඞཁ