【JetPack】Navigation知识点总结
Navigation的主要元素:
1、Navigation 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"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/my_nav_graph"
app:startDestination="@id/homeFragment">
<fragment
android:id="@+id/homeFragment"
android:name="com.example.navigation.HomeFragment"
android:label="fragment_home"
tools:layout="@layout/fragment_home" >
<action
android:id="@+id/action_homeFragment_to_detailFragment"
app:destination="@id/detailFragment" />
</fragment>
<fragment
android:id="@+id/detailFragment"
android:name="com.example.navigation.DetailFragment"
android:label="fragment_detail"
tools:layout="@layout/fragment_detail" >
<action
android:id="@+id/action_detailFragment_to_homeFragment"
app:destination="@id/homeFragment" />
</fragment>
</navigation>
2、NavHostFragment:
一个特殊的Fragment,可以将它看作是其他Fragment的容器,Navigation Graph中的Fragment正是通过NavHostFragment进行展示的。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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=".MainActivity">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragmentContainerView"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="409dp"
android:layout_height="729dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/my_nav_graph" />
</androidx.constraintlayout.widget.ConstraintLayout>
3、NavController:
用于在代码中完成Navigation Graph中具体的页面切换工作。
MainActivity.java
public class MainActivity extends AppCompatActivity {
NavController navController;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 这样写会报错
// NavController navController = Navigation.findNavController(this, R.id.fragmentContainerView);
// 需要先通过id获取到对应的NavHostFragment容器
NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.fragmentContainerView);
if (navHostFragment != null) {
// 如果不为空,再获取到的容器对应的NavController
navController = navHostFragment.getNavController();
} else {
throw new RuntimeException("NavHostFragment not found");
}
// 该代码的主要目的是将 ActionBar(或 Toolbar)与 NavController 关联起来,以便在使用 Android 导航组件时,ActionBar 可以自动更新其显示内容
NavigationUI.setupActionBarWithNavController(this, navController);
}
@Override
public boolean onSupportNavigateUp() {
// header上返回按键好用
return navController.navigateUp();
}
}
HomeFragment.java
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Button button = getView().findViewById(R.id.button);
button.setOnClickListener(view -> {
// 由于最外层设置了NavController,所以这里可以通过容器中的view找到NavController
NavController navController = Navigation.findNavController(view);
// 通过NavController进行导航,确定目的地
navController.navigate(R.id.action_homeFragment_to_detailFragment);
});
}
DetailFragment.java
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Button button = getView().findViewById(R.id.button2);
button.setOnClickListener((v)->{
// 由于最外层设置了NavController,所以这里可以通过容器中的view找到NavController
NavController navController = Navigation.findNavController(v);
// 通过NavController进行导航,确定目的地
navController.navigate(R.id.action_detailFragment_to_homeFragment);
});
}
三者之间的关系
当你想切换Fragment时,使用NavController对象,告诉它你想要去Nlavigation Graph中的哪个Fragment,NavController会将你想去的Fragment展示NavHostFragment中
实现顺序
1.创建Fragment
2.创建navgation_graph,指定fragment切换逻辑
3.在Activity的页面中添加navHostFragmrnt容器进行界面显示
4.在Activity中通过navHostFragmrnt获取到navController,并设置bar和fragment的对应关系,以及bar上返回按键生效
5.在需要触发fragment切换的位置通过获取navController进行导航,设置对应的action,确认触发后目的地
添加页面切换动画
页面之间参数传递
方法一:直接传递bundle对象(接收数据时需要知道对应key值以及value类型,并且需要判空)
Bundle bundle = new Bundle();
bundle.putString("user_name", "Jay");
NavController navController = Navigation.findNavController(view);
navController.navigate(R.id.action_homeFragment_to_detailFragment, bundle);
接收bundle对象
Bundle arguments = getArguments();
String userName = null;
if (arguments != null) {
userName = arguments.getString("user_name");
Log.d("userName", "" + userName);
}
方法二:引入arg插件
dependencies {
// 添加 safe-arg 插件依赖
classpath("androidx.navigation:navigation-safe-args-gradle-plugin:2.4.0")
}
plugins {
id 'androidx.navigation.safeargs'
}
Bundle bundle = new HomeFragmentArgs.Builder()
.setUserName("Jay")
.setAge(20)
.build().toBundle();
HomeFragmentArgs args = HomeFragmentArgs.fromBundle(getArguments());
String username = args.getUserName();
int age = args.getAge();
Log.d("Test", "userName = " + userName + "age = " + age);
NavigationUI的使用场景
Fragment切换时,设计到AppBar上的内容显示,为了方便统一管理引入NavigationUI
public class MainActivity extends AppCompatActivity {
private NavController navController;
private AppBarConfiguration appBarConfiguration;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.fragmentContainerView);
if (navHostFragment != null) {
navController = navHostFragment.getNavController();
}
appBarConfiguration = new AppBarConfiguration.Builder(navController.getGraph()).build();
// 将Appbar与Navigation建立联系
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.menu_settings, menu);
return true;
}
// 响应Meun的点击事件
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
return NavigationUI.onNavDestinationSelected(item, navController) || super.onOptionsItemSelected(item);
}
// 响应AppBar的返回按键
@Override
public boolean onSupportNavigateUp() {
return NavigationUI.navigateUp(navController, appBarConfiguration) || super.onSupportNavigateUp();
}
}
跳转后的假面不显示meun
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
setHasOptionsMenu(true);
return inflater.inflate(R.layout.fragment_setting, container, false);
}
@Override
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
menu.clear();
super.onCreateOptionsMenu(menu, inflater);
}
监听页面切换完成的回调
// 监听界面切换完成
navController.addOnDestinationChangedListener(new NavController.OnDestinationChangedListener() {
@Override
public void onDestinationChanged(@NonNull NavController navController, @NonNull NavDestination navDestination, @Nullable Bundle bundle) {
Log.d("test","onDestinationChanged");
}
});
深层链接DeepLink之PendingIntent
private void sendNotifycation() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel myChannel = new NotificationChannel(getActivity().getPackageName(), "MyChannel", NotificationManager.IMPORTANCE_DEFAULT);
myChannel.setDescription("My NotificationChannel");
NotificationManager notificationManager = getActivity().getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(myChannel);
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(getActivity(), getActivity().getPackageName())
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentTitle("Deep Link")
.setContentText("点我")
.setPriority(NotificationManager.IMPORTANCE_DEFAULT)
.setContentIntent(getPendingIntent());
// 发送通知
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(getActivity());
if (ActivityCompat.checkSelfPermission(getActivity(), android.Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
notificationManager.notify(notifyId++, builder.build());
}
private PendingIntent getPendingIntent() {
Bundle bundle = new Bundle();
bundle.putString("name","Jay");
return Navigation.findNavController(getActivity(),R.id.button)
.createDeepLink()
.setGraph(R.navigation.my_nav_graph)
.setDestination(R.id.detailFragment)
.setArguments(bundle)
.createPendingIntent();
}
深层链接DeepLink之Url