简介
Navigation通过图形化的方式管理配置页面的切换。
基本使用
- 添加依赖
implementation 'androidx.navigation:navigation-fragment:2.5.3'
implementation 'androidx.navigation:navigation-ui:2.5.3'
- 创建xml文件(添加导航图)——nav_graph.xml
nav_graph.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"
android:id="@+id/nav_graph">
</navigation>
- 向activity中添加NavHost
通过activity的xml布局文件添加FragmentContainerView和NavHostFragment。
app:navGraph 将NavHostFragment与导航图关联
app:defaultNavHost=“true” 使得NavHostFragment 会响应系统的返回点击事件
<?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"
android:orientation="vertical">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph" />
</LinearLayout>
-
在导航图中添加目的地
这里添加了BlankFragment。
app:startDestination 起始目的地,第一次进入看到的界面
-
目的地建立联系
拖住圆圈到目的fragment,自动建立联系。
建立联系后,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/nav_graph"
app:startDestination="@id/blankFragment">
<activity
android:id="@+id/mainActivity"
android:name="cn.jn.mytest.MainActivity"
android:label="MainActivity" />
<fragment
android:id="@+id/blankFragment"
android:name="cn.jn.mytest.BlankFragment"
android:label="fragment_blank"
tools:layout="@layout/fragment_blank" >
<action
android:id="@+id/action_blankFragment_to_cragment2"
app:destination="@id/cragment" />
</fragment>
<fragment
android:id="@+id/cragment"
android:name="cn.jn.mytest.Cragment"
android:label="fragment_cragment"
tools:layout="@layout/fragment_cragment" />
</navigation>
- 导航到目的地
6.1 在activity中使用NavController进行导航
nav_host_fragment为FragmentContainerView
NavHostFragment navHostFragment =
(NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);
NavController navController = navHostFragment.getNavController();
6.2 使用插件Safe Args导航,在项目build.gradle文件中添加配置.
plugins {
id 'com.android.application' version '7.4.2' apply false
id 'com.android.library' version '7.4.2' apply false
id 'androidx.navigation.safeargs' version '2.5.3' apply false
}
在app下的build.gradle文件中添加配置
plugins {
id 'com.android.application'
id 'androidx.navigation.safeargs'
}
android {
........
}
配置好后,Safe Args会根据nav_graph.xml文件生成代码。生成的类的名称由源目的地类的名称和“Directions”一词组成。根据上面的设置,我要在BlankFragment跳转到cragment,生成类的名字就是BlankFragmentDirections,BlankFragmentDirections中的方法,名称组成:action开头+源目的地名称+to+目的地名称,我这边生成的方法名为actionBlankFragmentToCragment。通过BlankFragmentDirections获取NavDirections,再将其传到navigate中,就完成了跳转。
在BlankFragment中的跳转如下
Button blank_but_jump = view.findViewById(R.id.blank_but_jump);
blank_but_jump.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
NavDirections action =
BlankFragmentDirections.actionBlankFragmentToCragment();
Navigation.findNavController(v).navigate(action);
}
});
6.3 带参数的Safe Args导航
在导航图中给blankFragment添加参数argument。
<fragment
android:id="@+id/blankFragment"
android:name="cn.jn.mytest.BlankFragment"
android:label="fragment_blank"
tools:layout="@layout/fragment_blank">
<action
android:id="@+id/action_blankFragment_to_cragment"
app:destination="@id/cragment"
app:enterAnim="@anim/slide_in_right"
app:exitAnim="@anim/slide_out_left"
app:popExitAnim="@anim/slide_out_right">
<argument
android:name="testA"
android:defaultValue="0"
app:argType="integer" />
</action>
</fragment>
跳转+参数
BlankFragmentDirections.ActionBlankFragmentToCragment actionBlankFragmentToCragment = BlankFragmentDirections.actionBlankFragmentToCragment();
actionBlankFragmentToCragment.setTestA(1);
Navigation.findNavController(v).navigate(actionBlankFragmentToCragment);
接收
Bundle bundle = getArguments();
if (bundle != null) {
int testA = bundle.getInt("testA");
Log.d("aaaaaa", testA + "");
}
- 效果如下
添加动画
动画文件自己创建
deeklink
通过pendingIntent,跳转到应用程序的某个页面。
- 通过通知跳转fragmment
在导航图中添加了一个fragment,当做点击通知时的跳转页面。
<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/nav_graph"
app:startDestination="@id/blankFragment">
......
<fragment
android:id="@+id/notifyFragment"
android:name="cn.jn.mytest.NotiFragment"
android:label="fragment_notify"
tools:layout="@layout/fragment_notify" />
</navigation>
在BlankFragment,创建Notification。如果项目的targetSdk =33,则需要声明和动态申请android.permission.POST_NOTIFICATIONS的权限。
public class BlankFragment extends Fragment {
private ActivityResultLauncher<String> activityResultLauncher;
public BlankFragment() {
// Required empty public constructor
}
public static BlankFragment newInstance(String param1, String param2) {
BlankFragment fragment = new BlankFragment();
return fragment;
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
activityResultLauncher = registerForActivityResult(new ActivityResultContracts.RequestPermission(), new ActivityResultCallback<Boolean>() {
@RequiresApi(api = Build.VERSION_CODES.TIRAMISU)
@Override
public void onActivityResult(Boolean result) {
if (result) {
Log.d("权限", "已授权");
} else {
Log.d("权限", "未授权");
}
}
});
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_blank, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Button blank_but_jump = view.findViewById(R.id.blank_but_jump);
blank_but_jump.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//系统版本大于等于33
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
NotificationManager notificationManagerCompat = requireContext().getSystemService(NotificationManager.class);
//检测是否允许了权限
boolean b = notificationManagerCompat.areNotificationsEnabled();
if (!b) {
//请求权限
activityResultLauncher.launch(Manifest.permission.POST_NOTIFICATIONS);
return;
}
}
sendNotify();
}
});
}
/**
*通知
*/
public void sendNotify() {
NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(requireContext());
//创建通知通道
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationChannel notificationChannel = new NotificationChannel("MyChannel", "MyChannel", NotificationManager.IMPORTANCE_LOW);
notificationManagerCompat.createNotificationChannel(notificationChannel);
}
//要跳转的fragment
PendingIntent pendingIntent = new NavDeepLinkBuilder(requireActivity())
.setGraph(R.navigation.nav_graph)
.setDestination(R.id.notifyFragment)
.createPendingIntent();
Notification notificationCompat = new NotificationCompat.Builder(requireActivity().getApplicationContext(), "MyChannel")
.setContentTitle("123456")
.setContentInfo("跳转")
.setContentIntent(pendingIntent)
.setSmallIcon(R.mipmap.ic_launcher)
.setAutoCancel(true)
.build();
notificationManagerCompat.notify(1, notificationCompat);
}
}