-
导航图:在一个集中位置包含所有导航相关信息的 XML 资源。包括所有的fragment及相关fragment切换的路径。(类似于地图功能)
-
NavHost
:显示导航图中目标的空白容器。导航组件包含一个默认NavHost
实现 (NavHostFragment
),可显示 Fragment 目标。(功能类似于汽车) -
NavController
:在NavHost
中管理应用导航的对象。当用户在整个应用中移动时,NavController
会安排NavHost
中目标内容的交换。(功能类似于方向盘,想显示地图上的位置就切换过去,没有路径则过不去)
implementation "androidx.navigation:navigation-fragment:2.3.2"
implementation "androidx.navigation:navigation-ui:2.3.2"
1,建立导航图
在res下新建导航图文件夹navigation,右键新建->Navigation Resource File
2,新建3个Fragment,WelcomeFragment LoginFragment RegisterFragment
自动生成代码
package com.sun.navigation;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
/**
* A simple {@link Fragment} subclass.
* Use the {@link LoginFragment#newInstance} factory method to
* create an instance of this fragment.
*/
public class LoginFragment extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
public LoginFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment LoginFragment.
*/
// TODO: Rename and change types and number of parameters
public static LoginFragment newInstance(String param1, String param2) {
LoginFragment fragment = new LoginFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_login, container, false);
}
}
很nice,自动生成布局,传参相关代码也写好了。
3,当前设计方向为欢迎能进入登录及注册,登录能进去注册,通过在login_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/welcomeFragment">
<fragment
android:id="@+id/welcomeFragment"
android:name="com.sun.navigation.WelcomeFragment"
android:label="fragment_welcome"
tools:layout="@layout/fragment_welcome" >
<action
android:id="@+id/action_welcomeFragment_to_loginFragment"
app:destination="@id/loginFragment" />
<action
android:id="@+id/action_welcomeFragment_to_registerFragment"
app:destination="@id/registerFragment" />
</fragment>
<fragment
android:id="@+id/loginFragment"
android:name="com.sun.navigation.LoginFragment"
android:label="fragment_login"
tools:layout="@layout/fragment_login" >
<action
android:id="@+id/action_loginFragment_to_registerFragment"
app:destination="@id/registerFragment" />
</fragment>
<fragment
android:id="@+id/registerFragment"
android:name="com.sun.navigation.RegisterFragment"
android:label="fragment_register"
tools:layout="@layout/fragment_register" />
</navigation>
4,添加Fragment容器NavHostFragment
activity_main.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"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="@+id/my_nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"//这是系统定义的专门用来显示navigation地图中fragment的fragment
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true" //true 返回键会回到上一个fragment false返回键由activity响应,一般是退出activity
app:navGraph="@navigation/login_navigation" />
</LinearLayout>
这样子显示部分就好了,activity启动后把androidx.navigation.fragment.NavHostFragment作为显示容器,加载navigation中的login_navigation导航图,在导航图上startDestination标识了welcomefragment是首先展示页,同时在welcomeFragment中,定义了2个action(跳转动作,路标?),可以跳转到LoginFragment和RegisterFragment,另外,LoginFragment也有动作能跳转到RegisterFragment上,下面在代码中添加NavControIIer(导航控制器?)完成页面切换。
普通导航
Navigation.findNavController(v).navigate(R.id.action_welcomeFragment_to_loginFragment);
带参数导航
Bundle bundle=new Bundle();
bundle.putString("phone",et_phone.getText().toString());
Navigation.findNavController(v).navigate(R.id.action_loginFragment_to_registerFragment,bundle);
如何导航到一个地图上本页面无法到达的页面会咋样?
报错参数异常
java.lang.IllegalArgumentException: Navigation action/destination com.sun.navigation:id/action_welcomeFragment_to_registerFragment cannot be found from the current destination Destination
5,为了解决跳转的生硬,需要添加动画,在原始代码上,可以通过fragment事务的setCustomAnimations()进行处理,而navigation,直接在导航图上进行添加,这样就能把偏view的动画添加代码移动xml上
双击action,给fragment的切换添加动画
<fragment
android:id="@+id/welcomeFragment"
android:name="com.sun.navigation.WelcomeFragment"
android:label="fragment_welcome"
tools:layout="@layout/fragment_welcome">
<action
android:id="@+id/action_welcomeFragment_to_loginFragment"
app:destination="@id/loginFragment"
app:enterAnim="@anim/window_right_in"
app:exitAnim="@anim/window_left_out"
app:popEnterAnim="@anim/window_left_in"
app:popExitAnim="@anim/window_right_out" />
<action
android:id="@+id/action_welcomeFragment_to_registerFragment"
app:destination="@id/registerFragment"
app:enterAnim="@anim/window_right_in"
app:exitAnim="@anim/window_left_out"
app:popEnterAnim="@anim/window_left_in"
app:popExitAnim="@anim/window_right_out" />
</fragment>
在导航图上自动出现了enterAnim和exitAnim的属性,这样就完成了动画的添加。
至此,navigation的基本操作已经完成,还有使用场景较少的深层链接,SafeArgs(个人不推荐)后续有时间再分析。
Android-Jetpack代码位置:github