文章目录
Jetpack Navigation
概述
-
Navigation是一个可简化Android导航的库和插件
-
Navigation通过管理Fragment的切换,可以通过可视化的方式,看见App的交互流程
-
可以配置Fragment的过渡和切换动画
-
SafeArgs插件,数据传递时提供了类型安全
添加依赖
模块层的build.gradle
dependencies {
implementation "androidx.navigation:navigation-fragment-ktx:2.0.0"
implementation "androidx.navigation:navigation-ui-ktx:2.0.0"
}
如果需要使用SafeArgs插件,还需要以下配置
项目的build.gradle
buildscript {
dependencies {
//SafeArgs插件
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.0.0"
}
}
模块层的build.gradle
apply plugin: 'androidx.navigation.safeargs'
Navigation说明
Navigation组成 | 说明 |
---|---|
Navigation Graph | 导航图,可视化显示Fragment之间关系 |
NavHostFragment | Fragment容器 |
NavController | 导航的控制者 |
导航图
navigation属性 | 说明 |
---|---|
app:startDestination | 导航图的开始 |
Fragment容器
属性 | 说明 |
---|---|
android:name | 必须是androidx.navigation.fragment.NavHostFragment |
app:navGraph | 指定导航图 |
app:defaultNavHost=“true” | 与系统返回按钮关联 |
导航控制者
api | 说明 |
---|---|
findNavController | 获取导航者 |
navigate | 跳转指定目标 |
基本使用
模拟登陆注册
定义导航图
在res目录下心间navigation目录,在该目录下新建welcome_navigation.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"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/login_navigation"
app:startDestination="@id/welcome">
<fragment
android:id="@+id/welcome"
android:name="com.example.navigationdemo.login.WelcomeFragment"
android:label="欢迎"
tools:layout="@layout/fragment_welcome">
<action
android:id="@+id/action_to_login"
app:destination="@id/login" />
<action
android:id="@+id/action_to_register"
app:destination="@id/register"
app:enterAnim="@anim/common_slide_in_right"
app:exitAnim="@anim/common_slide_out_left"
app:popEnterAnim="@anim/common_slide_in_left"
app:popExitAnim="@anim/common_slide_out_right" />
</fragment>
<fragment
android:id="@+id/login"
android:name="com.example.navigationdemo.login.LoginFragment"
android:label="登陆"
tools:layout="@layout/fragment_login" />
<fragment
android:id="@+id/register"
android:name="com.example.navigationdemo.login.RegisterFragment"
android:label="注册"
tools:layout="@layout/fragment_register">
<!--SafeArgs-->
<argument
android:name="data"
android:defaultValue="default"
app:argType="string" />
</fragment>
</navigation>
创建NavHostFragment
新建WelcomeActivity,在其xml布局里写入:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".login.WelcomeActivity">
<fragment
android:id="@+id/my_welcome_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/welcome_navigation" />
</FrameLayout>
定义导航逻辑
class WelcomeFragment : Fragment() {
private lateinit var btnToLogin: Button
private lateinit var btnToRegister: Button
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_welcome, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
btnToLogin = view.findViewById<Button>(R.id.btn_to_login)
btnToRegister = view.findViewById<Button>(R.id.btn_to_register)
//利用id导航
btnToLogin.setOnClickListener {
val navOptions = navOptions {
anim {
enter = R.anim.common_slide_in_right
exit = R.anim.common_slide_out_left
popEnter = R.anim.common_slide_in_left
popExit = R.anim.common_slide_out_right
}
}
val bundle = Bundle()
bundle.putString("data", "1234567")
findNavController().navigate(R.id.login, bundle, navOptions)
}
//使用SafeArags导航
btnToRegister.setOnClickListener {
val action = WelcomeFragmentDirections
.actionToRegister()
.setData("ABCDEFG")
findNavController().navigate(action)
}
}
}
定义导航目标
LoginFragment
class LoginFragment : Fragment() {
private lateinit var content: TextView
private var param: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param = it.getString("data")
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_login, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
content = view.findViewById<TextView>(R.id.content)
content.setText("接收数据:$param")
}
}
RegisterFragment
class RegisterFragment : Fragment() {
private lateinit var content: TextView
private var param: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param = it.getString("data")
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_register, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val content = view.findViewById<TextView>(R.id.content)
content.text = "接收数据:$param"
}
}
模拟底部切换Fragment
定义导航图
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/tab_navigation"
app:startDestination="@id/first_fragment">
<fragment
android:id="@+id/first_fragment"
android:name="com.example.navigationdemo.tab.FirstFragment"
android:label="第一页"
tools:layout="@layout/fragment_first" />
<fragment
android:id="@+id/second_fragment"
android:name="com.example.navigationdemo.tab.SecondFragment"
android:label="第二页"
tools:layout="@layout/fragment_second" />
<fragment
android:id="@+id/third_fragment"
android:name="com.example.navigationdemo.tab.ThirdFragment"
android:label="第三页"
tools:layout="@layout/fragment_third" />
</navigation>
创建NavHostFragment和定义导航逻辑
新建TabActivity在xml布局写入:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".tab.TabActivity">
<fragment
android:id="@+id/my_tab_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0px"
android:layout_weight="1"
app:defaultNavHost="true"
app:navGraph="@navigation/tab_navigation" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@color/white"
android:orientation="horizontal">
<TextView
android:id="@+id/switch_first"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#f00"
android:gravity="center"
android:text="第一页" />
<TextView
android:id="@+id/switch_second"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#0f0"
android:gravity="center"
android:text="第二页" />
<TextView
android:id="@+id/switch_third"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#00f"
android:gravity="center"
android:text="第三页" />
</LinearLayout>
</LinearLayout>
class TabActivity : AppCompatActivity() {
private lateinit var switchFirst: TextView
private lateinit var switchSecond: TextView
private lateinit var switchThird: TextView
val navOptions = navOptions {
anim {
enter = R.anim.common_fade_in
exit = R.anim.common_fade_out
popEnter = R.anim.common_fade_in
popExit = R.anim.common_fade_out
}
}
val bundle = Bundle()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_tab)
switchFirst = findViewById<TextView>(R.id.switch_first)
switchSecond = findViewById<TextView>(R.id.switch_second)
switchThird = findViewById<TextView>(R.id.switch_third)
// val navHostFragment =
// supportFragmentManager.findFragmentById(R.id.my_tab_fragment) as NavHostFragment
// val navController = navHostFragment.navController
val navController = findNavController(R.id.my_tab_fragment)
switchFirst.setOnClickListener {
navController.navigate(R.id.first_fragment, bundle, navOptions)
}
switchSecond.setOnClickListener {
navController.navigate(R.id.second_fragment, bundle, navOptions)
}
switchThird.setOnClickListener {
navController.navigate(R.id.third_fragment, bundle, navOptions)
}
}
}