初識Navigation(Google爲 單Activity+多Fragment 開發方式提供的官方支持)
- 初識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下載鏈接1。Android 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的圖形化界面。其中分爲三個部分:
- Destinations列表,包含當前界面展示的所有的destination
- Navigation圖形化編輯界面
- 屬性編輯器,用於編輯圖形化界面選中的元素屬性
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。
- 打開Navigation的視圖窗口,將鼠標懸停在源組件BlackFragment上,將會看到在源組件右邊緣出現一個小圓點。
- 拖動在源組件右邊緣出現的圓點,將其拖動到目標組件之上。現在可以看到一條連接在源組件和目標組件之間的連線,該連線用於表達兩個組件之間的導航關係。
- 點擊這條線,屬性面板中的內容會有所變化,如下:
- 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)。起始組件的設置很簡單:
- 打開Navigation編輯串口
- 點擊你想設置爲起始源組件的組件
- 點擊其屬性窗格中的 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框架的幾個屬性需要設置。
- app:navGraph 用於關聯Navigation文件(nav_graph.xml)
- 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的支持
Navigation對Menu的支持是最好的。一般情況下,無論是選項菜單還是上下文菜單亦或是NavigationView菜單都可以通過使用相同的ID達到相互關聯
Navigation的數據傳遞
Navigation在不同Fragment之間有兩種數據傳遞方式,其中一種。
- 在Navigation圖形界面選中目標組件
- 點擊右側屬性面板的 Add(+)按鈕,在其中可以設置參數類型、默認值、參數名字等。
- 看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佈局的流程如下:
- 按住Shift按鍵不鬆,選中所有想加入到子佈局中的目標組件。
- 右擊查看菜單欄,選擇Move to Nested Graph > New Graph
可以查看熟悉下子佈局的屬性,在子佈局上面雙擊即可進入子佈局。
可以使用
<include app:graph="@navigation/included_graph"/>
標籤來實現嵌套子佈局。但是在Android Studio3.2中實際展示效果並不好。
另外Navigation也是支持deep link的,但是基於國內應用的的情況並不多就不具體說了。
Navigation的一些事件監聽
Navigation可以通過addOnNavigatedListener()
方法添加目標組件切換的事件監聽。
Navigation對過渡動畫的支持
- 定義動畫資源
- 在圖形界面選中
如上所述很簡單的就可以實現過渡動畫的支持。