初識Android中的Navigation——Jetpack中的新組件Navigation

初識Navigation(Google爲 單Activity+多Fragment 開發方式提供的官方支持)

簡單介紹下新的android支持包Jetpack

Android Developer上面掛着Jetpack已經很久了。Jetpack是一組基於Android平臺的庫。Jetpack中包含四個層面的東西

  • Foundation
    • AppCompat
    • Android KTX
    • Multidex
    • Test
  • Architecture
    • Data Binding
    • Lifecycles
    • LiveData
    • Navigation
    • Paging
    • Room
    • ViewModel
    • WorkManager
  • Behavior
    • Download manager
    • Media & playback
    • Notifications
    • Permissions
    • Sharing
    • Slices
  • UI
    • Animation & transitions
    • Auto
    • Emoji
    • Fragment
    • Layout
    • Palette
    • TV
    • Wear Os by Google

Android Jetpack的具體介紹可以參看官方文檔:
Android Jetpack

總結來說,以後Android將不再提供v4/v7/v13/v14等包的更新,統一到Jetpack庫中,並以androidx.作爲新的包開頭。官方將通過Jetpack提供對Android各平臺的兼容,並且Jetpack獨立於Android各平臺API進行更新,所以以後一般情況下我們只需要用最新的androidx.包就可以了,全部使用一套接口來兼容各平臺。

Jetpack中的Navigation(位於Architecture中)

今天我們體驗下Jetpack中的Navigation庫,Navigation庫是官方爲單Activity開發提供的官方支持。官方爲Navigation開發了IDEA的插件可以使用圖像化手段處理頁面跳轉關係;除了採用Bundle進行數據傳輸以外還提供了gradle插件幫助開發者使用圖形化界面來傳遞參數;另外還提供了各個跳轉之間的切換動畫(Navigation中也提供了跳轉到Activity的支持,但是暫時並沒有提供從Activity跳轉到其他頁面的支持)。

開始構建一個使用Navigation的項目

安裝Android Studio 3.2版本

要想在Android Studio中使用Navigation架構組件就必須使用Android Studio3.2或以上版本。而目前Android Studio3.2版本還處於Beta狀態,所以爲了提前體驗新功能我們只能下載Beta版嚐嚐鮮 Android Studio 3.2下載鏈接1Android Studio 3.2下載鏈接2

下載安裝後,導入配置文件時如果導入了老版本的Android Studio的配置文件,那麼老版本中的項目列表將同樣會顯示在Android Studio3.2中。

在項目中使用Navigation

添加依賴

安裝好3.2版本的Android Studio之後,可以單獨創建一個項目,也可以打開之前的項目。總之打開一個項目,並在其build.gradle文件中配置Navigation支持

dependencies {
    implementation 'android.arch.navigation:navigation-fragment:1.0.0-alpha05'
    implementation 'android.arch.navigation:navigation-ui:1.0.0-alpha05'

    androidTestImplementation 'android.arch.navigation:navigation-testing:1.0.0-alpha05'
}

Navigation中的包命名方式已經改爲以androidx.爲包首,但是當前版本依然依賴有android support相關包。

創建Navigation資源文件

在資源目錄(res目錄)中創建navigation文件夾,並在其中創建xml文件,並在其中創建文件nav_graph.xml。文件內容如下:

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android">
</navigation>

因爲目前Android Studio3.2以及Navigation都還處於Beta階段,所以支持還不是很完善,創建該xml文件時並不像layout、anim這些有直接的選項(最新版本3.3Canary或許已經有了,可以下載試下)。

開啓Android Studio對Navigation的圖形界面支持

在Android Studio 3.2版本中對Navigation的圖像化支持默認沒有開啓,需要我們手動打開。將Settings->Experimental界面中最下面Enable Navigation Editor勾上即可。

操作Navigation的圖形化界面、熟悉Navigation使用

navigation edit

如上所示即爲Navigation的圖形化界面。其中分爲三個部分:

  1. Destinations列表,包含當前界面展示的所有的destination
  2. Navigation圖形化編輯界面
  3. 屬性編輯器,用於編輯圖形化界面選中的元素屬性

destinations 指被Navigation操作的目標組件,目前可以是Activity、Fragment或者我們自定義的其他東西(navgation中給我們提供了幾個核心類可以用於實現自己的目標組件)。

創建目標組件

上面提到目標組件可以是Activity、Fragment或者自定義組件。目標組件的創建就是創建這些對象,但是創建完成後需要將其加入到Navigation組件中去通過Navigation控制。加目標組件到Navigation中如下所示

添加導航

點擊圖中被小框框出來的按鈕即會打開一個列表框,這個列表框中會列出所有尚未添加到nav_graph文件中(即尚未接入到Navigation中)的目標組件。另外還可以通過列表上部的’Create blank destination’按鈕創建一個新的目標組件出來。

我們現在通過’Create blank destination’按鈕來創建一個目標組件BlankFragment,通過Create blank destination按鈕創建的目標組件將自動加入到Navigation視圖中,點擊視圖中的該組件在屬性框列表將有如下屬性:

  • Type 該目標組件的類型,可以是Fragment、Activity、自定義類型
  • Label 該目標組件在Navigation視圖中的name
  • ID ID最爲重要,在代碼中使用Navigation時需要通過該ID去定位目標組件
  • Class 該屬性指向目標組件的具體類

點擊Navigation視圖中的Text標籤,看Navigation視圖的XML定義。現在Navigation視圖文件中多了一個<fragment>標籤,該標籤即用於表示我們剛剛添加的BlankFragment,可以看到除了四個屬性都在該標籤中有所表示:

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    app:startDestination="@id/blankFragment">

    <!--type屬性-->
    <fragment
        <!-- id屬性-->
        android:id="@+id/blankFragment"
        <!-- class屬性-->
        android:name="com.olair.architecture.BlankFragment"
        <!-- label屬性-->
        android:label="fragment_blank"
        <!-- tool:layout 用於預覽 -->
        tools:layout="@layout/fragment_blank" />
</navigation>

在這個XML中navigation標籤中有一個app:startDestination 屬性,該屬性用於表示Navigation的最開始的目標組件,即起始目標組件。
要設置起始目標組件可以在Navigation視圖窗格中點擊想要設置爲起始目標組件的組件,在屬性列表的下側會有一個’Set Start Destination’按鈕,點擊即可設置,當然也可以以XML的形式去編輯。
設置爲起始目標組件之後,可以看到在目標組件上方會出現一個小屋子的圖標。

涉及到的Navigatin視圖中的按鈕如下:

視圖中的點擊選項

連接到目標組件

當我們有多個目標組件的時候,就需要產生連接,可以從一個目標組件跳轉到另外一個目標組件,這一個Navigation的核心。首先我們在創建一個Navigation目標組件,依然以Fragment爲例。創建後XML文件內容如下:

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    app:startDestination="@id/blankFragment">
    <fragment
        android:id="@+id/blankFragment"
        android:name="com.olair.architecture.BlankFragment"
        android:label="fragment_blank"
        tools:layout="@layout/fragment_blank" />
    <fragment
        android:id="@+id/blankFragment2"
        android:name="com.olair.architecture.BlankFragment2"
        android:label="fragment_blank_fragment2"
        tools:layout="@layout/fragment_blank_fragment2" />
</navigation>

其中一個BlankFragment一個BlankFragment2。現在我們希望可以從BlackFragment跳轉到BlankFragment2。

  1. 打開Navigation的視圖窗口,將鼠標懸停在源組件BlackFragment上,將會看到在源組件右邊緣出現一個小圓點。
  2. 拖動在源組件右邊緣出現的圓點,將其拖動到目標組件之上。現在可以看到一條連接在源組件和目標組件之間的連線,該連線用於表達兩個組件之間的導航關係。
  3. 點擊這條線,屬性面板中的內容會有所變化,如下:
    • Type Action 建立連接既是創建一個Action標籤,Action標籤用於表示一個導航時事件
    • ID 該Action的ID
    • Destination 目標組件(Activity或者Fragment的ID)

進入Navigation編輯窗口的文本界面,可以看到一個Action標籤被添加到了源組件中,而且在這個Action標籤屬性中有它的ID以及目標組件的ID。樣例代碼如下:

TODO

讓APP通過Navigation來控制頁面切換

現在我們已經可以使用Navigation將各個組件組合起來,但是應該注意到我們創建的Navigation文件(nav_graph.xml)並沒有整合到我們的代碼,目前將Navigation功能應用進來還是有一些麻煩的,但不排除後面會簡化Navigation的應用方式。

設置一個起始組件

首先我們需要有一個起始的源組件作爲Navigation默認打開的組件(TODO)。起始組件的設置很簡單:

  1. 打開Navigation編輯串口
  2. 點擊你想設置爲起始源組件的組件
  3. 點擊其屬性窗格中的 Set Start Destination 按鈕

這樣就將該組件設置爲Navigation的起始組件,可以看下nav_graph.xml文件中多了一條屬性(TODO)。

修改Activity來支持Navigation

Activity可以通過實現NavHost接口來通過Navigation實現頁面切換。NavHost可以作爲一個空視圖添加到Activity的佈局文件中。

在Navigation中NavHost的默認實現是NavHostFragment(androidx.navigation.fragment.NavHostFragment),因爲是Fragment所以也直接支持添加到佈局文件中(佈局解析器可以解析fragment標籤)。

將NavHostFragment加入到佈局之後,還有幾個針對Navigation框架的幾個屬性需要設置。

  1. app:navGraph 用於關聯Navigation文件(nav_graph.xml)
  2. app:defaultNavHost=”true” 該屬性設置爲true,Navigation將接管系統的返回鍵。但是目前還需要手動在Activity代碼中添加一行:
@Override
public boolean onSupportNavigateUp() {
    return Navigation.findNavController(this, R.id.nav_host_fragment).navigateUp();
}

也可以通過代碼的形式將NavHostFragment添加到Activity中,如下所示

NavHostFragment finalHost = NavHostFragment.create(R.navigation.example_graph);
getSupportFragmentManager().beginTransaction()
   .replace(R.id.nav_host, finalHost)
   .setPrimaryNavigationFragment(finalHost) // this is the equivalent to app:defaultNavHost="true"
   .commit();

通過以上步驟,在你的Activity中就有了一個NavController對象,可以進行頁面切換動作。

將頁面切換事件綁定在UI組件上

Navigation通過NavController對象來控制界面切換,獲得NavController對象的方式有一下幾種:

  • NavHostFragment.findNavController(Fragment)
  • Navigation.findNavController(Activity, @IdRes int viewId)
  • Navigation.findNavController(View)
  • Navigation.findNavController(this, R.id.nav_host_fragment)這一種

獲取到NavController對象之後,通過其navigate()方法去控制界面跳轉,`navigate()方法中的參數就是在Navigation佈局文件(nav_graph.xml)中的目標組件的ID(注意不是其layout資源ID,這樣有一個優勢,可以自由的定義其過渡動畫)。以下代碼展示一個頁面切換的例子。

viewTransactionsButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        Navigation.findNavController(view).navigate(R.id.viewTransactionsAction);
    }
});

Navigation框架將自動維護一個用於返回的堆棧,當應用程序打開時會將首頁加入該堆棧,後面沒打開一頁會就會將該頁放入堆棧,相反的,如果用戶點擊了向前按鈕或者回退按鈕就將自動調用NavController.navigateUp()NavController.popBackStack()方法回退到剛纔的頁面。

針對Button,Navigation框架還提供了一種簡單的方式來設置界面切換事件,如下:

button.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.next_fragment, null));

Navigation對Menu的支持是最好的。一般情況下,無論是選項菜單還是上下文菜單亦或是NavigationView菜單都可以通過使用相同的ID達到相互關聯

Navigation在不同Fragment之間有兩種數據傳遞方式,其中一種。

  1. 在Navigation圖形界面選中目標組件
  2. 點擊右側屬性面板的 Add(+)按鈕,在其中可以設置參數類型、默認值、參數名字等。
  3. 看Navigation圖形界面的Text,可以看到多了一些屬性信息。如下:
<fragment
   android:id="@+id/confirmationFragment"
   android:name="com.example.cashdog.cashdog.ConfirmationFragment"
   android:label="fragment_confirmation"
   tools:layout="@layout/fragment_confirmation">
   <argument android:name="amount" android:defaultValue=”0” />

調用navigate方法時將包含了參數信息的Bundle對象傳過去。如下

Bundle bundle = new Bundle();
bundle.putString("amount", amount);
Navigation.findNavController(view).navigate(R.id.confirmationAction, bundle);

在目標組件中採用如下方式拿到值:

TextView tv = view.findViewById(R.id.textViewAmount);
tv.setText(getArguments().getString("amount"));

另外還有一種參數傳遞方式,需要引入插件:
apply plugin: 'androidx.navigation.safeargs'
但是感覺使用體驗很是一般不過多介紹。需要的可以查看Pass data between destinations in a type-safe way

嵌套的Navigation佈局

Navigation佈局可以像View一樣嵌套,簡單點說就是,可以實現一個Navigation不居中包含另外一個Navigation佈局。

創建一個子Navigation佈局的流程如下:

  1. 按住Shift按鍵不鬆,選中所有想加入到子佈局中的目標組件。
  2. 右擊查看菜單欄,選擇Move to Nested Graph > New Graph

可以查看熟悉下子佈局的屬性,在子佈局上面雙擊即可進入子佈局。

可以使用 <include app:graph="@navigation/included_graph"/>標籤來實現嵌套子佈局。但是在Android Studio3.2中實際展示效果並不好。
另外Navigation也是支持deep link的,但是基於國內應用的的情況並不多就不具體說了。

Navigation可以通過addOnNavigatedListener()方法添加目標組件切換的事件監聽。

  1. 定義動畫資源
  2. 在圖形界面選中

如上所述很簡單的就可以實現過渡動畫的支持。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章