JetPack之Navigation与Fragment
Navigation三大核心概念
导航图
在一个集中位置包含所有导航相关信息的XML资源,这包括应用内所有单个区域内容(可以配置携带参数以及用户可以通过应用获取的可能路径)
NavHost
显示导航图中目标的空白容器,导航组件包含一个默认NavHost实现(NavHostFragment),可显示Fragment目标。
NavController
在NavHost中管理应用导航的对象。当用户在整个应用中移动时,NavController会安排NavHost中目标内容的交换。
好处:
开始使用
Navigation官网链接
1.build.gradle 声明依赖项
def nav_version = "2.3.3"
// Java language implementation
implementation "androidx.navigation:navigation-fragment:$nav_version"
implementation "androidx.navigation:navigation-ui:$nav_version"
2.创建导航图链接
<?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"
<!--navigation的xml的id-->
android:id="@+id/nav_graph"
<!--默认从afragment显示-->
app:startDestination="@id/afragment"
tools:ignore="UnusedNavigation">
<!--action申明-->
<action
android:id="@+id/to_cfragment"
app:destination="@+id/cfragment"
<!--进入动画-->
app:enterAnim="@anim/nav_default_enter_anim"
<!--退出动画-->
app:exitAnim="@anim/nav_default_exit_anim">
</action>
<action
android:id="@+id/to_afragment"
app:destination="@+id/afragment"
app:enterAnim="@anim/nav_default_enter_anim"
app:exitAnim="@anim/nav_default_exit_anim">
</action>
<action
android:id="@+id/to_bfragment"
app:destination="@+id/bfragment"
app:enterAnim="@anim/nav_default_enter_anim"
app:exitAnim="@anim/nav_default_exit_anim">
</action>
<action
android:id="@+id/to_dfragment"
app:destination="@+id/dfragment"
app:enterAnim="@anim/nav_default_enter_anim"
app:exitAnim="@anim/nav_default_exit_anim">
</action>
<!--fragment申明-->
<fragment android:id="@+id/afragment"
android:name="com.suyong.jetpacknavigation.fragment.AFragment"
android:label="afragment"
tools:layout="@layout/fragment_a"
/>
<fragment android:id="@+id/bfragment"
android:name="com.suyong.jetpacknavigation.fragment.BFragment"
android:label="bfragment"
tools:layout="@layout/fragment_b"
/>
<fragment android:id="@+id/cfragment"
android:name="com.suyong.jetpacknavigation.fragment.CFragment"
android:label="cfragment"
tools:layout="@layout/fragment_c"
/>
<fragment android:id="@+id/dfragment"
android:name="com.suyong.jetpacknavigation.fragment.DFragment"
android:label="dfragment"
tools:layout="@layout/fragment_d"
/>
</navigation>
然后我们需要创建显示fragment的容器了,如下所示
<fragment
android:id="@+id/nav_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
<!--这个就是系统里面帮我们实现好存放frament的地方-->
android:name="androidx.navigation.fragment.NavHostFragment"
<!--导航的配置xml-->
app:navGraph="@navigation/nav_graph"
<!--设置返回栈有这个fragment管理,不设置的话呢返回事件就被activity接管了,会导致应用直接退出-->
app:defaultNavHost="true"/>
在Activcity中获取NavController
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//获取NavigationController
//动态注绑定
NavController navController = Navigation.findNavController(this, R.id.nav_fragment);
}
}
然后运行代码你就能看到程序完美的运行了。
接下来就是实现fragment之间的跳转了,我们用了Navigation之后,数据传递就方便多了
//只要这样就这可以了,是不是很简单,注意to_cfragment是我们nav xml配置文件里的一个action
Bundle bundle = new Bundle();
bundle.putString("name","from AFragment");
Navigation.findNavController(getView()).navigate(R.id.to_cfragment,bundle);
上面的是动态传参,我们也可以通过配置文件实现静态传参。
<?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/afragment"
tools:ignore="UnusedNavigation">
<!--action申明-->
<action
android:id="@+id/to_cfragment"
app:destination="@+id/cfragment"
app:enterAnim="@anim/nav_default_enter_anim"
app:exitAnim="@anim/nav_default_exit_anim">
</action>
....
<!--fragment申明-->
<fragment android:id="@+id/afragment"
android:name="com.suyong.jetpacknavigation.fragment.AFragment"
android:label="afragment"
tools:layout="@layout/fragment_a"
>
<!--注意这里我们静态申明在afragment中,所以我们只有在AFragment中才可以getArguments().getString("name")获取到这个 from xml argments 的值-->
<argument android:name="name" android:defaultValue="from xml argments"/>
</fragment>
....
</navigation>
注意: 动态配置会覆盖掉静态配置
我们接收呢,我们只要如下即可
getArguments().getString("name");
现在我们的fragment就可以了接下来丰富一下界面,我们在底部添加几个tab,然后通过点击tab来切换fragment
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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">
<fragment
android:id="@+id/nav_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="@navigation/nav_graph"
app:defaultNavHost="true"/>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
<!--配置tab项-->
app:menu="@menu/menu"/>
</RelativeLayout>
menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
<!--这里的id一定要跟上面的nav_graph.xml里的fragment的id一一对应-->
android:id="@+id/afragment"
android:icon="@mipmap/index"
android:title="首页"></item>
<item
android:id="@+id/bfragment"
android:icon="@mipmap/cate"
android:title="分类"
/>
<item
android:id="@+id/cfragment"
android:icon="@mipmap/cart"
android:title="购物车" />
<item
android:id="@+id/dfragment"
android:icon="@mipmap/me"
android:title="我的" />
<item
android:id="@+id/efragment"
android:icon="@mipmap/me"
android:title="圈子" />
</menu>
最后我们还需要在上面的基础下,添加下面两行下代码,绑定事件
BottomNavigationView bottomNavigationView = findViewById(R.id.bottom_view);
//绑定navigation与navController
NavigationUI.setupWithNavController(bottomNavigationView ,navController);
然后我们就可以通过点击tab来切换fragment了。
<deepLink app:uri="www.yourWebsite.com/{params}"/>
然后再activiy配置文件里配置
<!--为activity配置nav_graph-->
<!--静态绑定-->
<nav-graph android:value="@navigation/nav_graph"/>
然后我们可以在Android studio的控制台输入(模拟器)
adb shell am start -a android.intent.action.VIEW -d "http://www.yourWebsite.com/fromweb"
这样我们就实现了DeepLink,而且显示的是BFragment
DeepLink官方链接
而且我们还可以携带参数,通过getArguments().getString("params")
,获取到的值是fromweb
/**
* 通过PendingIntent设置,当通知被点击后需要跳转到哪个destination,以及传递的参数
* */
private PendingIntent getPendingIntent()
{
if(getActivity() != null)
{
Bundle bundle = new Bundle();
bundle.putString("params", "from Notification");
return Navigation
.findNavController(getActivity(), R.id.button)
.createDeepLink()
.setGraph(R.navigation.nav_graph)
//目的地Frgment
.setDestination(R.id.bfragment)
.setArguments(bundle)
.createPendingIntent();
}
return null;
}
/**
* 向通知栏发送一个通知
* */
private void sendNotification(){
if(getActivity() == null){
return;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "ChannelName", importance);
channel.setDescription("description");
NotificationManager notificationManager = getActivity().getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(getActivity(), CHANNEL_ID)
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentTitle("Navigation")
.setContentText("Hello World!")
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setContentIntent(getPendingIntent())
.setAutoCancel(true);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(getActivity());
notificationManager.notify(notificationId, builder.build());
}