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 Component 実践編
Search
yoppie
December 03, 2019
Technology
300
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
1k
Androidエンジニアが Flutterでアプリを リリースするまでの苦悩
yoppie
0
550
FragmentContainerViewとは
yoppie
0
800
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
290
sabotage
yoppie
1
980
Play with Kotlin
yoppie
1
650
Other Decks in Technology
See All in Technology
脆弱性対応、どこで線を引くか
rymiyamoto
1
420
2026TECHFRESH畢業分享會 - 原生還是跨平台? App 開發踩坑實錄
line_developers_tw
PRO
0
1.3k
脱SaaS!FDEを支えるプロビジョニングと分離設計
knih
0
240
200個のGitHubリポジトリを横断調査したかった
icck
0
140
徹底討論!ECS vs EKS!
daitak
0
150
【Snowflake Summit 2026 Recap!!】Snowflake Summit Deep Dive: Security & Governance
civitaspo
1
260
AI駆動開発を通して感じた、 AI時代のデザイナーの役割変化
whisaiyo
4
2.3k
Oracle AI Database@Google Cloud:サービス概要のご紹介
oracle4engineer
PRO
6
1.5k
Flow 不死:AI 時代 DevOps 的不變本質
cheng_wei_chen
2
280
Agent Skills設計で柔軟性と硬さのバランスが難しい話
nassy20
0
140
AWS Security Hub CSPMの成功・失敗体験
cmusudakeisuke
0
240
FPGAの開発コンペでZephyrを使ってみた
iotengineer22
0
120
Featured
See All Featured
エンジニアに許された特別な時間の終わり
watany
107
250k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.5k
JAMstack: Web Apps at Ludicrous Speed - All Things Open 2022
reverentgeek
1
480
How People are Using Generative and Agentic AI to Supercharge Their Products, Projects, Services and Value Streams Today
helenjbeal
1
220
How STYLIGHT went responsive
nonsquared
100
6.2k
Leo the Paperboy
mayatellez
7
1.8k
Google's AI Overviews - The New Search
badams
0
1k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
47
8.2k
Ethics towards AI in product and experience design
skipperchong
2
310
WCS-LA-2024
lcolladotor
0
650
Imperfection Machines: The Place of Print at Facebook
scottboms
270
14k
Building a Scalable Design System with Sketch
lauravandoore
463
34k
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ؒͷը໘ભҠΛ γϯϓϧʹ࣮Ͱ͖Δ ࣮ફͰಋೖ͢ΔͱͳΔͱ ӡ༻อकੑΛߟྀ͢ΔΑ͏ʹͳΓ ҙ͕ඞཁ