JetPack之Navigation与Fragment使用

学习目标:

JetPack之Navigation与Fragment


学习内容:

  • Navigation三大核心概念

    • 导航图
      在一个集中位置包含所有导航相关信息的XML资源,这包括应用内所有单个区域内容(可以配置携带参数以及用户可以通过应用获取的可能路径)

    • NavHost
      显示导航图中目标的空白容器,导航组件包含一个默认NavHost实现(NavHostFragment),可显示Fragment目标。

    • NavController
      在NavHost中管理应用导航的对象。当用户在整个应用中移动时,NavController会安排NavHost中目标内容的交换。

  • 好处:

    • 帮我们处理了Fragment事务。
    • 为动画和转换提供标准化资源。
    • 实现和处理DeepLink。
    • safe Args 在目标之间导航和传递数据时提供类型安全的Gradle插件(activity和fragment数据传递)。
    • ViewModel支持。

开始使用
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实现方式
    我们需要在nav_graph的配置文件里,在你想要deeplink的fragment里写如下代码
    比如在BFragment里面的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

  • 显式DeepLink实现方式
    跳转BFragment
    /**
     * 通过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());
    }

你可能感兴趣的:(Android,android)