前言
在移動開發中,對開發者來說不同的人具有不同的能力,就像讀一本書一樣,一千個讀者,有一千個哈姆雷特,但不管怎樣,只要你是個軟體開發者你就必須學習windows或Linux等作業系統的運行原理,就不扯這么多了直接上干貨,
【由于文中篇幅較長,提前預告:文末有大量手寫框架原始碼及架構思維資料,需要的可直接跳越至文末領取】
實戰
在實戰之前,我們先來了解一下 Navigation 中最關鍵的三要素,他們是:
- Navigation Graph (New XML resource)
如我們的第一張圖所示,這是一個新的資源檔案,用戶在可視化界面可以看出
他能夠到達的 Destination (用戶能夠到達的螢屏界面),以及流程關系, - NavHostFragment (Layou XML view)
當前 Fragment 的容器 - NavController (Kotlin/Javaobject)
導航的控制者
可能我這么解釋還是有點抽象,做一個不是那么恰當的比喻,我們可以將 Navigation Graph 看作一個地圖,
NavHostFragment 看作一個車,以及把 NavController 看作車中的方向盤, Navigation Graph 中可以看出各個地點(Destination)和通往各個地點的路徑, NavHostFragment 可以到達地圖中的各個目的地,但是決定到什么目的地還是方向盤 NavController ,雖然它取決于開車人(用戶),
第一步 添加依賴
模塊層的 build.gradle 檔案需要添加:
ext.navigationVersion = "2.0.0"
dependencies {
//...
implementation "androidx.navigation:navigation-fragment- ktx:$rootProject.navigationVersion"
implementation "androidx.navigation:navigation-ui-ktx:$rootProject.navigationVersion"
}
如果你要使用 SafeArgs 插件,還要在專案目錄下的 build.gradle 檔案添加:
buildscript {
ext.navigationVersion = "2.0.0"
dependencies {
classpath "androidx.navigation:navigation-safe-args-gradle- plugin:$navigationVersion"
}
}
以及模塊下面的 build.gradle 檔案添加:
apply plugin: 'kotlin-android-extensions'
apply plugin: 'androidx.navigation.safeargs'
第二步 創建navigation導航
- 創建基礎目錄:資源檔案 res 目錄下創建 navigation 目錄 -> 右擊 navigation 目錄New一個 Navigation resource file
- 創建一個
Destination
,如果說
navigation
是我們的導航工具,
Destination
是我們的目的地,在此之前,我已經寫好了一個
WelcomeFragment
、
LoginFragment
和
RegisterFragment
,添加
Destination
的操作完成后如下所示:

添加Destination
除了可視化界面之外,我們仍然有必要看一下里面的內容組成, login_navigation.xml :
<navigation
...
android:id="@+id/login_navigation"
app:startDestination="@id/welcome">
<fragment
android:id="@+id/login"
android:name="com.joe.jetpackdemo.ui.fragment.login.LoginFragment"
android:label="LoginFragment"
tools:layout="@layout/fragment_login"
/>
<fragment
android:id="@+id/welcome"
android:name="com.joe.jetpackdemo.ui.fragment.login.WelcomeFragment"
android:label="LoginFragment"
tools:layout="@layout/fragment_welcome">
<action
.../>
<action
.../>
</fragment>
<fragment
android:id="@+id/register"
android:name="com.joe.jetpackdemo.ui.fragment.login.RegisterFragment"
android:label="LoginFragment"
tools:layout="@layout/fragment_register"
>
<argument
.../>
</fragment>
</navigation>
我在這里省略了一些不必要的代碼,讓我們看一下 navigation標簽 的屬性:
app:startDestination 默認的起始位置
第三步 建立 NavHostFragment
我們創建一個新的 LoginActivity ,在 activity_login.xml 檔案中:
<androidx.constraintlayout.widget.ConstraintLayout
...>
<fragment
android:id="@+id/my_nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="@navigation/login_navigation"
app:defaultNavHost="true"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
有幾個屬性需要解釋一下:
- android:name
值必須是androidx.navigation.fragment.NavHostFragment,宣告這是一個 NavHostFragment - app:navGraph
存放的是第二步建好導航的資源檔案,也就是確定了Navigation Graph - app:defaultNavHost="true"
與系統的回傳按鈕相關聯
第四步 界面跳轉、引數傳遞和影片
在 WelcomeFragment 中,點擊登錄和注冊按鈕可以分別跳轉到 LoginFragment 和 RegisterFragment 中,

WelcomeFragment.
這里我使用了兩種方式實作:
方式一 利用ID導航
目標: WelcomeFragment 攜帶 key 為 name 的資料跳轉到 LoginFragment , LoginFragment 接收后顯示,
Have a account ? Login 按鈕的點擊事件如下:
btnLogin.setOnClickListener {
// 設定影片引數
val navOption = navOptions {
anim {
enter = R.anim.slide_in_right
exit = R.anim.slide_out_left
popEnter = R.anim.slide_in_left
popExit = R.anim.slide_out_right
}
}
// 引數設定
val bundle = Bundle()
bundle.putString("name","TeaOf")
findNavController().navigate(R.id.login, bundle,navOption)
}
后續 LoginFragment 的接收代碼比較簡單,直接獲取Fragment中的 Bundle 即可,這里不再出示代碼,最后的效
果:

LoginFragment
方式二 利用 Safe Args **
目標: WelcomeFragment 通過 Safe Args 將資料傳到 RegisterFragment , RegisterFragment 接收后顯示,
再看一下已經展示過的 login_navigation.xml :
<navigation
...>
<fragment
...
/>
<fragment
android:id="@+id/welcome"
>
<action
android:id="@+id/action_welcome_to_login"
app:destination="@id/login"/>
<action
android:id="@+id/action_welcome_to_register"
app:enterAnim="@anim/slide_in_right"
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right"
app:destination="@id/register"/>
</fragment>
<fragment
android:id="@+id/register"
...
>
<argument
android:name="EMAIL"
android:defaultValue="2005@qq.com"
app:argType="string"/>
</fragment>
</navigation>
細心的可能已經觀察到 navigation 目錄下的 login_navigation.xml 資源檔案中的 action 標簽和 argument
標簽,這里需要解釋一下:
- app:destination
跳轉完成到達的 fragment 的Id - app:popUpTo
將 fragment 從 堆疊 中彈出,直到某個Id的 fragment
argument標簽
- android:name
標簽名字 - app:argType
標簽的型別 - android:defaultValue
默認值
點擊Android studio中的Make Project按鈕,可以發現系統為我們生成了兩個類:

系統生成的類
WelcomeFragment
中的
JOIN US
按鈕點擊事件:
btnRegister.setOnClickListener {
val action = WelcomeFragmentDirections
.actionWelcomeToRegister()
.setEMAIL("TeaOf1995@Gamil.com")
findNavController().navigate(action)
}
RegisterFragment 中的接收:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// ...
val safeArgs:RegisterFragmentArgs by navArgs()
val email = safeArgs.email
mEmailEt.setText(email)
}
以及效果:

RegisterFragment
需要提及的是,如果不用
Safe Args
,
action
可以由
Navigation.createNavigateOnClickListener(R.id.next_action, null)
方式生成,感興趣的可以自行撰寫,
更多
Navigation 可以系結 menus 、 drawers 和 bottom navigation ,這里我們以 bottom navigation 為例,我先在
navigation 目錄下新創建了 main_navigation.xml ,接著新建了 MainActivity ,下面則是
activity_main.xml :
<LinearLayout
...>
<fragment
android:id="@+id/my_nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
app:navGraph="@navigation/main_navigation"
app:defaultNavHost="true"
android:layout_height="0dp"
android:layout_weight="1"/>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/navigation_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white"
app:itemIconTint="@color/colorAccent"
app:itemTextColor="@color/colorPrimary"
app:menu="@menu/menu_main"/>
</LinearLayout>
MainActivity 中的處理也十分簡單:
class MainActivity : AppCompatActivity() {
lateinit var bottomNavigationView: BottomNavigationView
override fun onCreate(savedInstanceState: Bundle?) {
//...
val host: NavHostFragment =
supportFragmentManager.findFragmentById(R.id.my_nav_host_fragment) as NavHostFragment
val navController = host.navController
initWidget()
initBottomNavigationView(bottomNavigationView,navController)
}
private fun initBottomNavigationView(bottomNavigationView: BottomNavigationView, navController: NavController) {
bottomNavigationView.setupWithNavController(navController)
}
private fun initWidget() {
bottomNavigationView = findViewById(R.id.navigation_view)
}
}
效果:

結束
更多手寫專案原始碼請往下看(文末可直接領取)
- Data Binding
- ViewModel & LiveData
- Room
- Paging
- WorkManger
- Paging 3

MVC/MVP/MVVM
- MVC框架-ASP.NET表單
- MVC框架-第一應用程式
- MVC框架-檔案夾
- MVC框架-模型
- MVC框架-控制器
- MVC框架-視圖
- MVC框架-布局
- MVP架構設計:Google官方MVP思想解讀
- 開源MVP框架
- MVC、MVP、MVVM,到底該怎么選?

大廠架構演進之路
- 抖音 iOS 工程架構演進
- 美團外賣 Android 平臺化架構演進實踐
- 安居客 Android 專案架構演進
- 攜程 Android App 插件化和動態加載實踐
- 微信Android客戶端架構演進之路
- 千萬級用戶的 Android 客戶端是如何養成的 | 架構師實踐日
- 手機淘寶構架演化實踐
- 英語流利說 Android 架構演進

我建立了一個編程資料共享學習Q裙:裙號是793544421,也可直接添加我的唯心:【Keaiduoooo_】,我整理了一系列編程學習視頻、Android技術原理、手寫原始碼、架構思維、書籍、筆記等等,需要文中資料的同學,進群即可獲得,【技術學習交流,廣告勿入】,技術是有邊界的,但是學習是無界的,群里會有一些大神幫忙解答,有時你悶頭想一天,不如別人的三言兩語就醍醐灌頂,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/291188.html
標籤:其他
