前言
開(kāi)個(gè)新坑,上回秋招的時(shí)候已經(jīng)會(huì)開(kāi)始問(wèn)一些關(guān)于Jetpack的一些問(wèn)題了,然而碰都沒(méi)碰過(guò),前段時(shí)間開(kāi)始學(xué)習(xí),發(fā)現(xiàn)網(wǎng)上的質(zhì)量參差不齊,基本就是照著官網(wǎng)的,還是自己來(lái)記錄吧,本篇文章將會(huì)記錄自己學(xué)習(xí)Jetpack架構(gòu)組件中Navigation組件的基本使用。
Navigation介紹
首先我們看看Navigation到底是啥,一般查閱資料,我們最權(quán)威的還是要從官方文檔看起,建議先看一遍視頻:

Navigation其實(shí)就是對(duì)Fragment的管理,在以前使用Fragment的時(shí)候,尤其是在單Activity+多Fragment的時(shí)候,是需要處理多個(gè)Fragment的生命周期,很容易出現(xiàn)問(wèn)題,而Navigation這個(gè)組件它提供了多Fragment之間的轉(zhuǎn)場(chǎng),棧管理,幫助你更輕松的使用Fragment,而且最重要的是它是可視化的(沒(méi)錯(cuò))。


這樣也就可以更加容易的實(shí)現(xiàn)單Activity+多Fragment的這種實(shí)現(xiàn)模式了,也就是全局只要的一個(gè)Activity就行(這里其實(shí)還是有爭(zhēng)議的)。
Navigation的基本使用
還是老樣子,我們根據(jù)官方開(kāi)發(fā)文檔來(lái)看,但是開(kāi)發(fā)文檔寫的挺難懂的,所以這里再按我自己的理解來(lái)使用。
首先要使用Navigation需要build.gradle 文件添加以下依賴項(xiàng)(具體版本根據(jù)開(kāi)發(fā)文檔來(lái)查看):
implementation 'androidx.navigation:navigation-fragment:2.2.0'
implementation 'androidx.navigation:navigation-ui:2.2.0'
然后我們就需要?jiǎng)?chuàng)建一個(gè)Navigation了,我們?cè)趓es文件夾下右鍵新建一個(gè)Android Resource File,名字輸入nav_grap,在Resource type類型里面選擇Navigation,然后我們就可以看到res文件夾下面有一個(gè)新建的navigation文件夾和已經(jīng)創(chuàng)建好的Navigation了。

中間一大框框的就是導(dǎo)航圖了,也就是可視化界面,左邊主要展示這個(gè)Navigation的宿主(具體是啥后面再說(shuō))和Navigation導(dǎo)航的Fragment。接著我們?cè)趧?chuàng)建兩個(gè)Fragment,名字隨意。

接著我們回到Navigation界面,我們可以看到左上角有一排的按鈕,我們點(diǎn)擊第一個(gè)添加按鈕就可以進(jìn)行Fragment的添加。

這時(shí)候我們會(huì)看到你創(chuàng)建的Fragmt和Activity,我們雙擊進(jìn)行全部添加,至于placeholder這個(gè)其實(shí)就是占位符的意思,我們暫且別管。


Navigation也可以切換到text模式,也就是代碼查看,我們切換到代碼查看一下:
<?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/oneFragment"
tools:ignore="UnusedNavigation">
<fragment
android:id="@+id/oneFragment"
android:name="com.ju.navigationdemo.OneFragment"
android:label="fragment_one"
tools:layout="@layout/fragment_one" />
<fragment
android:id="@+id/twoFragment"
android:name="com.ju.navigationdemo.TwoFragment"
android:label="fragment_two"
tools:layout="@layout/fragment_two" />
<activity
android:id="@+id/mainActivity2"
android:name="com.ju.navigationdemo.MainActivity"
android:label="activity_main"
tools:layout="@layout/activity_main" />
</navigation>
看到這里用過(guò)Fragment的靜態(tài)使用方法的人也就明白了,也就是靜態(tài)添加了Fragment和Activity,接著我們回到視圖模式,選型一個(gè)Fragment,我們發(fā)現(xiàn)它的右邊有一個(gè)小圓球,這個(gè)就是連接的意思,我們可以通過(guò)這個(gè)小圓球來(lái)進(jìn)行對(duì)想要的Fragment的進(jìn)行跳轉(zhuǎn)等操作,只要拉動(dòng)這個(gè)小圓球選定你要導(dǎo)航的Fragment就好了,我們導(dǎo)航到第二個(gè)Fragment,在切換到text模式查看代碼。

<?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/oneFragment"
tools:ignore="UnusedNavigation">
<fragment
android:id="@+id/oneFragment"
android:name="com.ju.navigationdemo.OneFragment"
android:label="fragment_one"
tools:layout="@layout/fragment_one" >
<action
android:id="@+id/action_oneFragment_to_twoFragment"
app:destination="@id/twoFragment" />
</fragment>
<fragment
android:id="@+id/twoFragment"
android:name="com.ju.navigationdemo.TwoFragment"
android:label="fragment_two"
tools:layout="@layout/fragment_two" />
<activity
android:id="@+id/mainActivity2"
android:name="com.ju.navigationdemo.MainActivity"
android:label="activity_main"
tools:layout="@layout/activity_main" />
</navigation>
你會(huì)發(fā)現(xiàn)多了一個(gè)action標(biāo)簽,這就是,里面兩個(gè)屬性一個(gè)是id(這個(gè)很重要),另一個(gè)app:destination這個(gè)屬性就是要導(dǎo)航的Fragmen的id。接著我們回到視圖模式,點(diǎn)擊Activity,發(fā)現(xiàn)Activity是沒(méi)有這個(gè)小圓球的,這也就是說(shuō)Navigation組件不支持Activity的導(dǎo)航,它主要是管理Fragment的,那么我們就右擊刪除這個(gè)Activity吧。
接著我們需要一個(gè)宿主來(lái)存放這個(gè)Navigation,我們就給他放在MainActivity的布局下(其實(shí)就是單Activity+多Fragment的模式):
<?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">
<fragment
android:id="@+id/container"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph" />
</androidx.constraintlayout.widget.ConstraintLayout>
這里的name是指定 Fragment 的類型為NavHostFragment,這個(gè)就是Navigation的實(shí)現(xiàn)類,類型是Fragment,而defaultNavHost是讓Navigation容器處理返回事件,在 Navigation 容器中如果有頁(yè)面的跳轉(zhuǎn),點(diǎn)擊返回按鈕會(huì)先處理 容器中 Fragment 頁(yè)面間的返回,處理完容器中的頁(yè)面,再處理 Activity 頁(yè)面的返回。如果值為 false 則直接處理 Activity 頁(yè)面的返回。最重要的是navGraph這個(gè)屬性,它就是指定Navigation文件。
接下來(lái)就是處理跳轉(zhuǎn)事件了,官方文檔說(shuō)是可以通過(guò)以下方法來(lái)進(jìn)行實(shí)現(xiàn):

寫的有點(diǎn)含糊,其實(shí)就是通過(guò)這個(gè)Navigation找到它的Controller來(lái)進(jìn)行跳轉(zhuǎn)操作。我們?cè)诘谝粋€(gè)Fragment的布局文件中一個(gè)Button,然后對(duì)這個(gè)Button進(jìn)行控件的跳轉(zhuǎn)。。。
public class OneFragment extends Fragment {
public OneFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_one, container, false);
initView(view);
return view;
}
private void initView(View view) {
view.findViewById(R.id.test).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//進(jìn)行跳轉(zhuǎn)
Navigation.findNavController(v).navigate(R.id.action_oneFragment_to_twoFragment);
}
});
}
}
如果是回退的話則是:
Navigation.findNavController(v).navigateUp();
如果是要傳遞數(shù)據(jù)給Fragment的話,可以通過(guò)Bundle進(jìn)行傳遞:
Bundle bundle = new Bundle();
bundle.putInt("test",1);
//進(jìn)行跳轉(zhuǎn)
Navigation.findNavController(v).navigate(R.id.action_oneFragment_to_twoFragment,bundle);
//進(jìn)行接收
Bundle bundle = getArguments();

然后我們發(fā)現(xiàn)一個(gè)問(wèn)題,沒(méi)有跳轉(zhuǎn)動(dòng)畫(huà),其實(shí)我們也可以在Navigation的可視化界面進(jìn)行設(shè)置,點(diǎn)擊連接的那跟線,然后在右邊的Animations中就可以進(jìn)行設(shè)置了,然后在text模式也會(huì)成成相應(yīng)的代碼。

//要跳轉(zhuǎn)的action標(biāo)簽會(huì)自動(dòng)生成,也可以自定義anim
<action
android:id="@+id/action_oneFragment_to_twoFragment"
app:destination="@id/twoFragment"
app:enterAnim="@anim/fragment_open_enter"
app:exitAnim="@anim/fragment_open_exit"
app:popEnterAnim="@anim/fragment_open_enter"
app:popExitAnim="@anim/fragment_open_exit" />
Navigation + BottomNavigationView構(gòu)建導(dǎo)航欄
如果只是最基本的使用那就沒(méi)意思了,其實(shí)這個(gè)Navigation是可以配合BottomNavigationView做出導(dǎo)航欄的效果的,BottomNavigationView是谷歌推出的一個(gè)底部導(dǎo)航欄的控件,一般是配合Fragment來(lái)一起使用的,而且在官網(wǎng)案例中也有這樣的使用方法。


我們就自己來(lái)實(shí)現(xiàn)一個(gè),首先我們?cè)趧倓偣こ痰幕A(chǔ)上在創(chuàng)建一個(gè)Fragment,這樣就是三個(gè)Fragment了。

然后我們?cè)贜avigation中把連接的線去掉,并且把第3個(gè)Fragment也添加進(jìn)去。

接著在MainActivity的布局中添加BottomNavigationView:
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<fragment
android:id="@+id/container"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_weight="9"
android:layout_height="0dp"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/nav_view"
android:layout_width="match_parent"
android:layout_weight="1"
android:layout_height="0dp"
android:layout_marginStart="0dp"
android:layout_marginEnd="0dp"
android:background="?android:attr/windowBackground"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:menu="@menu/bottom_nav_menu" />
</LinearLayout>
BottomNavigationView的menu如下:
//icon隨意,id要和Navigation里面3個(gè)Fragmet的id要對(duì)應(yīng)!?。。。。。。。。。?!
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/oneFragment"
android:icon="@drawable/ic_home_black_24dp"
android:title="一" />
<item
android:id="@+id/twoFragment"
android:icon="@drawable/ic_dashboard_black_24dp"
android:title="二" />
<item
android:id="@+id/threeFragment"
android:icon="@drawable/ic_notifications_black_24dp"
android:title="三" />
</menu>
然后在MainActivity輸入以下代碼:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//獲得BottomNavigationView
BottomNavigationView navView = findViewById(R.id.nav_view);
//獲得Navigation的Control
NavController navController = Navigation.findNavController(this,R.id.container);
//綁定
NavigationUI.setupWithNavController(navView,navController);
//獲取頂部appBar
AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
R.id.oneFragment, R.id.twoFragment, R.id.threeFragment)
.build();
//綁定
NavigationUI.setupActionBarWithNavController(this,navController,appBarConfiguration);
}
}
