【Jetpack日記(1)】Navigation的基本使用

前言

開(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)威的還是要從官方文檔看起,建議先看一遍視頻:

導(dǎo)航介紹頁(yè)面

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ò))。
Navigation的可視化,第一次看到驚呆了


這樣也就可以更加容易的實(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了。


Navigation界面

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


Fragment創(chuàng)建

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

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


添加Fragment

添加完成

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模式查看代碼。


Navigation連接
<?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):


處理導(dǎo)航事件

寫的有點(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();
運(yùn)行結(jié)果

然后我們發(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)的代碼。


設(shè)置跳轉(zhuǎn)動(dòng)畫(huà)
//要跳轉(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)案例中也有這樣的使用方法。



新建工程中的Bottom Navigation Activity就是這種方法

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


工程項(xiàng)目如圖

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

添加3個(gè)Fragment

接著在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);
    }

}

最終運(yùn)行結(jié)果


參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容