前言
Google 在2018年推出了 Android Jetpack,在Jetpack里有一種管理fragment的新架構模式,那就是navigation. 字面意思是導航,但是除了做APP引導頁面以外.也可以使用在App主頁分tab的情況.. 甚至可以一個功能模塊就一個activity大部分頁面UI都使用fragment來實現,而navigation就成了管理fragment至關重要的架構.
但是,它不單單只能管理fragment也可以管理activity.這點你格外注意.
使用條件
你的Android studio 必需升級到3.2版本以上,此博客正在寫的時候Android studio已經到達3.5,所以升級到最新版本即可.
依賴
//navigation implementation 'android.arch.navigation:navigation-fragment:1.0.0' implementation 'android.arch.navigation:navigation-ui:1.0.0'
使用流程
創建navigation目錄
1.選中項目資源文件夾 res 右擊 >> New >> New Resource Directory
2.選中navigation 點擊創建 (注意這個目錄只有在Android studio3.2版本以上才能出現)
創建navigation目錄下的xml文件
1.選中項目資源文件夾 res 右擊 >> New >> New Resource File
2.選擇navigation ,輸入xml文件名稱,點擊ok創建
配置創建的xml文件
上面我們創建了一個叫demo_nav.xml的navigation文件,現在我們需要來設配它來管理fragment
1.打開這個文件選擇,模式使用視圖手動配置.
2.切換到Design模式后,我們可以看到下面這個界面(恩,一片空白). 我們可以在左上角點擊添加圖標,進入添加內容的操作.
3.點擊后,可以看到下面這個彈窗,這里解釋一下:
第一個 Create new destinattion,字面意思創建一個新目標(其實就是創建fragment,當然你也可以手動另外創建fragment不一定需要在這里創建)
第二個 placeholder,這個就是重點了. 這是一個管理fragment跳轉的節點,我們點擊后可以創建它.為了了解它的使用方式,點擊3次創建三個節點
4.節點創建后可以看到三個節點(看下面圖片,這些節點都是我已經導入fragment了.不要急后面會講解如何導入).這里有一個重點! 你可以點擊這些頁面(會有一個藍點),點擊藍點按住向右分配它需要跳轉的另外一個頁面.(它會自動生成一些我們跳轉的代碼)
6.然后點擊左下角的Text模式,在Text模式下,可以看到如下代碼,在上面的圖片中你可以很清楚的看到創建了3個節點,並且是一個跳轉一個的.從第一個fragment跳轉到第二個fragment,再從第二個fragment跳轉到第三個fragment
下面我們來重點講解下下面的這些代碼的關鍵點了:
在<navigation里的屬性:
1.android:id="@+id/demo_nav" 這個屬性是你這個xml文件navigation的id,很重要,我們需要在activity的xml布局里引用,記得寫上不要忘記
2.app:startDestination="@id/one" 這個屬性是你首次加載的第一個頁面,很重要,一般就是第一個fragment
在<fragment 里的屬性:
其實就是一個節點你也可以理解成一個fragment
1.android:id="@+id/one" 每一個fragment節點都需要有自己的id,很重要. 我們需要在后面的節點上使用這些id指定跳轉目標
2.android:name="demo.yt.com.demo.fragment.BlankFragment" 這個屬性是你這個節點所對應的fragment(需要你導入指定的fragment文件路徑),這個很重要
3.android:label="BlankFragment" 一個標簽名稱,用於記錄這個節點的標簽信息(大概可能是在代碼里的Intent里獲取來知曉此次是那個fragment節點在跳轉,沒深究了)
4.tools:layout="@layout/fragment_blank" 這個屬性不是重要的,設置它后你可以在切換到Design模式后看到,視圖頁面的fragment的預覽圖(就在上面的圖片里,可以直接看到fragment效果)
在<action 里的屬性:
action 負責編寫跳轉動作
1. android:id="@+id/action_one_to_two" 這個很重要,它是這個跳轉動作的id, 這個id我們將在后面的代碼中調用,用於執行fragment的跳轉
2. app:destination="@id/two" 跳轉的目標fragment,這個很重要
<?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/demo_nav" app:startDestination="@id/one"> <fragment android:id="@+id/one" android:name="demo.yt.com.demo.fragment.BlankFragment" android:label="BlankFragment" tools:layout="@layout/fragment_blank"> <action android:id="@+id/action_one_to_two" app:destination="@id/two" /> </fragment> <fragment android:id="@+id/two" android:name="demo.yt.com.demo.fragment.Blank2Fragment" android:label="BlankFragment" tools:layout="@layout/fragment_blank2"> <action android:id="@+id/action_two_to_three" app:destination="@id/three" /> </fragment> <fragment android:id="@+id/three" android:name="demo.yt.com.demo.fragment.Blank3Fragment" android:label="BlankFragment" tools:layout="@layout/fragment_blank3"/> </navigation>
讓navigation與Activity關聯起來
現在我們已經創建了navigation,但是使用它還需要一個根Activity,它畢竟還是需要依托Activity的.
1.創建了一個叫DemoActivity的Activity.這個沒啥,下面來看這個Activity的布局xml怎么配(如下xml代碼)
我們就關注fragment的一些屬性
1.android:name="androidx.navigation.fragment.NavHostFragment" 這個非常重要,這是你告知fragment需要使用navigation模式的關鍵屬性,另外它是固定死的.你必需寫.
2. app:defaultNavHost="true" 這是你實現物理按鍵(比如返回鍵),是按一下退出一個fragment 還是直接退出這個Activity的關鍵屬性
3.app:navGraph="@navigation/demo_nav" 很重要,這就是我們前面創建的navigation的xml文件
<?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=".fragment.DemoActivity"> <fragment android:id="@+id/demo_fragment" android:layout_width="0dp" android:layout_height="0dp" android:name="androidx.navigation.fragment.NavHostFragment" app:defaultNavHost="true" app:navGraph="@navigation/demo_nav" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent"/> </androidx.constraintlayout.widget.ConstraintLayout>
實現fragment跳轉與返回
進入到DemoActivity后,首先會自動加載到第一個fragment. 然后我們看看如何跳轉到其他fragment中
1.從第一個碎片跳轉到第二個碎片,關鍵代碼 Navigation.findNavController(getView()).navigate(R.id.action_one_to_two);
public class BlankFragment extends Fragment { private Button mBtnInputFragment2; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { final View view = inflater.inflate(R.layout.fragment_blank, container, false);; mBtnInputFragment2 = view.findViewById(R.id.btn_input_fragment2); mBtnInputFragment2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Navigation.findNavController(getView()).navigate(R.id.action_one_to_two);//這個id就是navigation里的action的id } }); return view; } @Override public void onDestroy() { super.onDestroy(); } @Override public void onDetach() { super.onDetach(); } }
2.從第二個碎片返回到第一個碎片,關鍵代碼 Navigation.findNavController(getView()).popBackStack();
public class Blank2Fragment extends Fragment { private Button mBtnInputFragment3, mBtnBack; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_blank2, container, false); mBtnInputFragment3 = view.findViewById(R.id.btn_input_fragment3); mBtnBack = view.findViewById(R.id.back); mBtnInputFragment3.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Navigation.findNavController(getView()).navigate(R.id.action_two_to_three); //進入第三個碎片 } }); mBtnBack.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Navigation.findNavController(getView()).popBackStack(); //返回上一個碎片 } }); return view; } }