1. 事前準備
Android 裝置有多種形狀、大小和板型規格。因此,建議將應用程式設計成在可順利在各種類型的裝置 (小螢幕或大螢幕裝置) 上執行。開發人員撰寫可正式發布的應用程式可能為 Android Wear、Android Auto 和 Android TV 提供支援,但這些主題並不在本課程的涵蓋範圍內。只要應用程式盡量支援多種螢幕,就能提供給更多擁有不同裝置的使用者。
您的應用程式必須具有彈性的版面配置。版面配置應配合不同的螢幕大小和方向而彈性調整,而不是以特定顯示比例和螢幕大小的硬性尺寸來指定版面配置。在折疊式裝置上執行應用程式時,這個原則同樣適用,因為這類裝置的螢幕大小和長寬比可能會在應用程式執行過程中變動。在本程式碼研究室的結尾,您將會學到可折疊裝置的簡介。
必要條件
- 如何將程式碼下載到 Android Studio 並執行。
- 熟悉 Android 架構元件
ViewModel
和LiveData
。 - Navigation 元件的基本知識。
課程內容
- 如何在應用程式中加入
SlidingPaneLayout
。
建構項目
- 更新運動應用程式,配合大螢幕進行調整。
您將會需要的
- 已安裝 Android Studio 的電腦。
- 運動 應用程式的範例程式碼。
下載本程式碼研究室的範例程式碼
本程式碼研究室提供範例程式碼,可延伸至本程式碼研究室所教授的功能。範例程式碼可能包含程式碼研究室先前介紹過的程式碼,也可能會有之後才會介紹的程式碼,因此不盡然是您熟悉的內容。
如要從 GitHub 取得本程式碼研究室的程式碼,並在 Android Studio 中開啟,請按照下列步驟操作:
- 啟動 Android Studio。
- 在「Welcome to Android Studio」視窗中,按一下「Get from VCS」。
- 在「Get from Version Control」對話方塊中,確認您已為「Version Control」選取「Git」。
- 將提供的程式碼網址貼到「URL」方塊中。
- 您也可以將「Directory」變更為與建議預設值不同的內容。
- 按一下「Clone」。Android Studio 會開始擷取程式碼。
- 等待 Android Studio 開啟。
- 在程式碼研究室的範例程式碼、應用程式或解決方案程式碼中,選取正確的模組。
- 按一下「Run」按鈕 ,即可建構並執行程式碼。
2. 觀看程式設計示範影片 (可略過)
如果您想觀看課程老師示範完成此程式碼研究室,請觀看以下影片。
建議您在全螢幕模式下觀看影片 (點選影片右下角的 圖示),才能清楚看見 Android Studio 和程式碼。
您可以跳過這個步驟,也可以不觀看這段影片,立即開始進行程式碼研究室的操作步驟。
3. 範例應用程式總覽
運動應用程式由兩個畫面組成。第一個畫面會顯示運動清單。使用者可以選取特定運動項目,系統便會顯示第二個畫面。第二個畫面會顯示所選運動新聞的詳細資料。詳細資料畫面會顯示預留位置文字,以簡化實作。
範例程式碼逐步操作說明
您下載的範例程式碼包含預先設計的清單畫面和詳細資料畫面版面配置。在本課程中,您只需瞭解如何讓應用程式配合大螢幕自動調整即可。您將用 SlidingPaneLayou
來利用大螢幕。以下是一些檔案的簡短逐步操作說明,以協助您快速上手。
fragment_sports_list.xml
- 在「設計」檢視畫面中開啟
res/layout/fragment_sports_list.xml
。 - 這包含應用程式中第一個畫面的版面配置,也就是運動清單。
- 這個版面配置包含顯示體育新聞清單的 Recyclerview。
sports_list_item.xml
- 在「設計」檢視畫面中開啟
res/layout/sports_list_item.xml
。 - 這包含每個項目在 Recyclerview 中版面配置。
- 這個版面配置包含體育項目的縮圖、新聞標題和體育新聞摘要的預留位置文字。
fragment_sports_news.xml
- 在「設計」檢視畫面中開啟
res/layout/fragment_sports_news.xml
。 - 這包含應用程式中第二個畫面的版面配置。當使用者從 Recyclerview 選擇運動時,就會顯示這個畫面。
- 這個版面配置包含體育項目的圖片橫幅和體育新聞的預留位置文字。
main_activity.xml 和 content_main.xml
這兩個函式數用單一片段定義了主要活動的版面配置。
navigation/nav_graph.xml
導覽圖包含兩個目的地,一個用於運動清單,另一個用於運動新聞。
res/values 資料夾
您已熟悉此資料夾中的資源檔案。
colors.xml
包含應用程式中使用的主題顏色。strings.xml
包含應用程式所需的所有字串。themes.xml
包含您為應用程式產生的 UI 自訂項目。
MainActivity.kt
這個檔案包含預設範本產生的程式碼,可將活動的內容檢視畫面設為 main_activity.xml
。為了處理應用程式列的預設向上導覽,我們覆寫了 onSupportNavigateUp()
方法。
model/Sport.kt
這是一種資料類別,用來存放運動名單 Recyclerview 顯示的各列資料。
data/SportsData.kt
這個檔案內含名為 getSportsData()
的函式,此函式會傳回預先填入硬式編碼運動資料的 ArrayList
。
SportsViewModel.kt
這是應用程式的共享 ViewModel
。您可以透過 SportsListFragment
來分享 ViewModel
,第一個畫面包含運動清單和 NewsDetailsFragment
,第二個畫面含有詳細的運動新聞。
_currentSport
屬性為MutableLiveData,
類型,此類型會儲存使用者選取的現有運動。currentSport
屬性是_currentSport
的備用屬性,並以公開唯讀版本的形式公開,方便其他類別使用。_sportsData
屬性包含運動資料清單。與上一個屬性類似,sportsData
是這項屬性的公開唯讀版本,- 初始化器
init{}
區塊會初始化_currentSport
和_sportsData
。_sportsData
會透過來自data/SportsData.kt
的完整運動清單進行初始化。_currentSport
會使用清單中的第一個項目進行初始化。 - 函式
updateCurrentSport()
包含Sports
執行個體,並以傳送的值更新_currentSport
。
SportsAdapter.kt
這是 RecyclerView
的轉接介面。在建構函式中,會傳入點擊事件監聽器。這個檔案中的大部分程式碼都是先前的程式碼研究室介紹過的樣板程式碼。
SportsListFragment.kt
這是第一個畫面片段,是顯示運動清單之處。
onCreateView()
函式會使用繫結物件加載fragment_sports_list
版面配置 XML。onViewCreated()
函式會設定RecyclerView
轉接介面。這個函式會將使用者選取的運動項目更新為共用ViewModel
(也就是SportsViewModel
) 中的目前運動項目,並導覽至內含運動新聞的詳細資料畫面,使用submitList(List)
將要顯示的運動清單提交至轉接介面。
NewsDetailsFragment.kt
這是您應用程式的第二個畫面,其中會顯示運動新聞的預留位置文字。
onCreateView()
函式會使用繫結物件加載fragment_sports_news
版面配置 XML。onViewCreated()
函式會在SportsViewModel
的屬性上附加觀察器currentSport
,在資料有變時自動更新 UI。運動標題、圖片和新聞會在觀察器中更新。
建立應用程式並加以執行
- 在模擬器或裝置上建構並執行應用程式。選取體育清單中的任何項目,應用程式應該就會進入第二個畫面,畫面上包含新聞的預留位置文字。
4. 清單/詳細資料模式
目前的範例應用程式無法充分運用大螢幕裝置 (如平板電腦) 的螢幕空間。為解決這個問題,您稍後會透過本程式碼研究室介紹的「清單詳細資料」模式來顯示應用程式 UI。
在平板電腦上執行應用程式
在這項工作中,您會建立一個具平板電腦設定檔的模擬器。模擬器建立完畢後,您將執行 Sports 應用程式範例程式碼並觀察 UI。
- 在 Android Studio 中,依序前往「Tools」>「AVD Manager」。
- 系統會隨即顯示「Android Virtual Device Manager」視窗。按一下底部顯示的「+ Create New Virtual Device...」。
- 系統隨即會顯示「Virtual Device Configuration」視窗。請在此處設定模擬器硬體和 OS。按一下左側窗格中的「Tablet」。選取中間窗格內的「Pixel C」或任何其他類似的硬體設定檔。
- 按一下「Next」。
- 在撰寫這個程式碼研究室時,選取最新的系統映像檔 R (API 級別 30)。
- 按一下「Next」。
- 您現在可以選擇是否要重新命名虛擬裝置,這不是必須選項。
- 按一下「Finish」。
- 系統會將您帶回「Android Virtual Device Manager」視窗。在新建的虛擬裝置旁邊按一下啟動圖示 。
- 這應會啟動具平板電腦設定檔的模擬器。請耐心等候,這可能需要一點時間。
- 關閉「Android Virtual Device Manager」視窗。
- 在新建的模擬器上執行運動應用程式。
請注意,在大型裝置上,應用程式不會使用整個螢幕。在大螢幕上,清單詳細資料模式會較清單模式更為有效。清單詳細資料模式又稱為「主控制項詳細資料」模式,這種模式會在版面配置的其中一側顯示項目清單,而當您輕觸項目時,便會在項目一旁顯示詳細資料。一般情況下,這類檢視畫面只會在大螢幕 (例如平板電腦) 上顯示,因為大螢幕的空間足以顯示更多的內容。
以下是清單-詳細資料模式的範例圖片:
如上所示,清單詳細資料模式會在左側顯示項目清單,在右側則會顯示所選項目的詳細資料。
同理,如果您在運動應用程式中使用上述模式,則新聞片段將成為詳細資料畫面。
在本程式碼研究室中,您將瞭解如何使用 SlidingPaneLayout
實作清單/詳細資料 UI。
5. SlidingPaneLayout 模式
清單-詳細資料 UI 可能需要根據螢幕大小而採取不同的行為。大螢幕有足夠的空間,可並排顯示清單和詳細資料窗格。在清單項目上點擊,即可在詳細資料窗格中顯示詳細資料。不過在小螢幕上,這樣的安排就會相當擁擠。與其同時顯示這兩個窗格,不如逐一顯示。一開始,清單窗格會填滿整個畫面。輕觸某個項目,會以該項目的詳細資料窗格取代清單窗格,同時填滿整個畫面。
您將瞭解如何使用 SlidingPaneLayout 來管理邏輯,進一步根據目前的螢幕大小選取適當的使用者體驗。
請注意詳細資料窗格在小螢幕上滑過清單窗格的方式。
下方圖片說明 SlidingPaneLayout
在小螢幕上的顯示方式。請在清單項目處於選取狀態時,觀察詳細資料窗格與清單窗格如何重疊,才能讓這兩個窗格始終存在!
因此,SlidingPaneLayout
支援在大型裝置上並排顯示兩個窗格,而在手機之類的小型裝置上,則會自動調整為只顯示一個窗格。
6. 新增程式庫依附元件
- 開啟
build.gradle (Module: Sports.app)
。 - 在
dependencies
區段中,加入下列依附元件,即可在應用程式中使用SlidingPaneLayout
。
dependencies {
...
implementation "androidx.slidingpanelayout:slidingpanelayout:1.2.0-beta01"
}
7. 設定體育清單片段的 XML
在這項工作中,您將 fragment_sports_list
的根版面配置轉換為 SlidingPaneLayout
。前面介紹過,SlidingPaneLayout
提供水平的雙窗格版面配置,可在 UI 頂層使用。這個版面配置將第一個窗格用作內容清單或瀏覽器,並對應到主要詳細資料檢視畫面,以在另一個窗格中顯示內容。
在運動應用程式中,第一個窗格會是顯示運動清單的 RecyclerView
,第二個窗格則顯示運動新聞。
新增 SlidingPaneLayout
- 開啟
fragment_sports_list.xml
。請注意根版面配置為FrameLayout
。 - 將
FrameLayout
變更為androidx.slidingpanelayout.widget.SlidingPaneLayout.
<androidx.slidingpanelayout.widget.SlidingPaneLayout
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=".SportsListFragment">
<androidx.recyclerview.widget.RecyclerView...>
</androidx.slidingpanelayout.widget.SlidingPaneLayout>
- 在
SlidingPaneLayout
中加入android:id
屬性,並指定一個@+id/sliding_pane_layout
的值。
<androidx.slidingpanelayout.widget.SlidingPaneLayout
...
android:id="@+id/sliding_pane_layout"
...>
在 SlidingPaneLayout 中新增第二個窗格
在這個工作中,您會在 SlidingPaneLayout
中新增第二個子項。這會顯示為右側的內容窗格。
- 在
fragment_sports_list.xml
中的RecyclerView
下新增第二個子項androidx.fragment.app.FragmentContainerView
。 - 在
FragmentContainerView
中加入必要屬性layout_height
和layout_width
,並指定match_parent
這個屬性值。請注意,您稍後會更新這些值。
<androidx.fragment.app.FragmentContainerView
android:layout_height="match_parent"
android:layout_width="match_parent"/>
- 在
FragmentContainerView
中加入android:id
屬性,並指定一個@+id/detail_container
的值。
android:id="@+id/detail_container"
- 使用
android:name
屬性在FragmentContainerView
中新增NewsDetailsFragment
。
android:name="com.example.android.sports.NewsDetailsFragment"
更新 layout_width 屬性
SlidingPaneLayout
會依據兩個窗格的寬度來判斷是否要並排顯示窗格。舉例來說,如果經過測量後,清單窗格的最小尺寸為 300dp
,而詳細資料窗格需要 400dp
,那麼只要可用寬度至少為 700dp
,SlidingPaneLayout
就會自動並排顯示這兩個窗格。
如果子項檢視畫面的組合寬度超過 SlidingPaneLayout
中的可用寬度,子項檢視畫面會發生重疊。在本範例中,子項檢視畫面會展開來填滿 SlidingPaneLayout
中的可用寬度。
為了判斷子項檢視畫面的寬度,建議您瞭解裝置螢幕寬度相關的基本資訊。下表列出了幾個主觀的中斷點,可讓您針對各種可調整大小的應用程式版面配置來進行設計、開發及測試。這些中斷點經過特別挑選,目的是讓您兼顧版面配置的簡單與靈活,進一步根據獨特的情境需求來最佳化應用程式。
寬度 | 中斷點 | 裝置佔比 |
精簡寬度 | < 600dp | 99.96% 直向模式的手機 |
中等寬度 | 600dp+ | 93.73% 以 portraitLarge 顯示的平板電腦,會以直向展開內部的顯示項目 |
展開寬度 | 840dp+ | 97.22% 以 landscapeLarge 顯示的平板電腦,會橫向展開內部的顯示項目 |
在運動應用程式中,建議您在手機 (寬度小於 600dp
的裝置) 上顯示單一窗格 (也就是體育項目清單)。如要在平板電腦上顯示這兩個窗格,加總的寬度必須大於 840dp
。您可以將第一個子項 (RecyclerView) 的寬度設為 550dp
,第二個子項 (FragmentContainerView
) 則設為 300dp
。
- 在
fragment_sports_list.xml
中,將RecyclerView
的版面配置寬度變更為550dp
,再將FragmentContainerView
的版面配置寬度變更為300dp
。
<androidx.recyclerview.widget.RecyclerView
...
android:layout_width="550dp"
.../>
<androidx.fragment.app.FragmentContainerView
...
android:layout_width="300dp"
.../>
- 分別在採用平板電腦設定檔和手機設定檔的模擬器上執行應用程式。
請注意,平板電腦會顯示兩個窗格。您將在後續步驟中將平板電腦上的第二個窗格設為固定寬度。
- 具手機設定檔的模擬器上執行應用程式。
新增 layout_weight
在這項工作中,您將針對平板電腦調整 UI,讓第二個窗格占滿剩餘的全部空間。
如果檢視畫面未重疊,則在透過版面配置參數 layout_weight
測量子項檢視畫面之後,SlidingPaneLayout
可定義剩餘空間的分割方式。這個參數僅適用於寬度。
- 在
fragment_sports_list.xml
中,將layout_weight
加入FragmentContainerView
並指定其值為1
。這樣一來,在測量清單窗格之後,第二個窗格就會展開並填滿剩餘空間。
android:layout_weight="1"
- 執行應用程式。
恭喜!您已成功新增 SlidingPaneLayout
。但這項設定尚未完成。從清單選擇項目之後,您必須導入返回導覽功能並更新第二個窗格。您將於後續工作中實作這些項目。
8. 替換詳細資料窗格
在具平板電腦設定檔的模擬器上執行應用程式。從運動清單中選取清單項目。請注意,應用程式會導航至詳細資料窗格。
在這項工作中,您會修正這個問題。目前,系統會先以選取的體育項目更新雙窗格的內容,接著應用程式會轉至 NewsDetailsFragment
。
- 在
SportsListFragment
檔案的onViewCreated()
函式中,找到以下程式行以前往詳細資料畫面。
// Navigate to the details screen
val action = SportsListFragmentDirections.actionSportsListFragmentToNewsFragment()
this.findNavController().navigate(action)
- 使用下列程式碼取代以上這幾行:
binding.slidingPaneLayout.openPane()
對 SlidingPaneLayout
呼叫 openPane()
,將第一個窗格切換至第二個窗格。如果兩個窗格皆處於顯示狀態 (例如在平板電腦上),這項操作不會造成任何可見的影響。
- 在平板電腦和手機模擬器上執行應用程式。請注意,雙窗格內容會不斷正確更新。
在下一個工作中,您將為應用程式新增自訂返回導覽功能。
9. 新增自訂返回導覽功能
小型裝置上的清單和詳細資料窗格會重疊,因此您必須確保系統返回按鈕可讓使用者從詳細資料窗格返回清單窗格。方法是 提供自訂返回導覽功能,並將 OnBackPressedCallback
連結到 SlidingPaneLayout
目前的狀態。
返回導覽
「返回瀏覽」是指使用者依據瀏覽歷史記錄返回先前瀏覽過的畫面。所有 Android 裝置都會針對這類導覽提供返回按鈕。視使用者的 Android 裝置而定,該按鈕可能是實體按鈕或軟體按鈕。
自訂返回導覽
當使用者導覽應用程式時,Android 系統會保留目的地的返回堆疊。一般情況下,使用者按下返回按鈕時,Android 可以導覽至之前的目的地。不過在少數情況下,您可能必須為應用程式實作專屬的返回行為,盡可能提供最佳使用者體驗。
舉例來說,在使用 WebView (例如 Chrome 瀏覽器) 時,您可能要覆寫預設的返回按鈕行為,讓使用者返回先前的網頁瀏覽記錄,而不是回到先前的應用程式畫面。
同樣地,您必須在 SlidingPaneLayout
中提供自訂的返回導覽功能,將應用程式從詳細資料窗格導航回清單窗格。
導入自訂的返回導覽功能
如要在 Sports 應用程式中實作自訂返回導覽,需要執行以下作業:
- 定義自訂回呼來處理返回鍵按鍵動作,這會覆寫
OnBackPressedCallback
。 - 註冊並新增回呼例項。
首先,請定義自訂回呼。
- 在
SportsListFragment
檔案中的SportsListFragment
類別定義下方新增類別。將其命名為SportsListOnBackPressedCallback
。 - 傳入
SlidingPaneLayout
的private
例項做為建構函式參數。
class SportsListOnBackPressedCallback(
private val slidingPaneLayout: SlidingPaneLayout
)
- 透過
OnBackPressedCallback
擴充類別。OnBackPressedCallback
類別會處理onBackPressed
回呼。您會在不久之後修正這項建構函式參數錯誤。
class SportsListOnBackPressedCallback(
private val slidingPaneLayout: SlidingPaneLayout
): OnBackPressedCallback()
OnBackPressedCallback
的建構函式會以布林值表示初始啟用狀態。只有在已啟用回呼的情況下 (即 isEnabled()
傳回 true),分派器才會呼叫回呼的 handleOnBackPressed()
來處理返回按鈕事件。
- 將
slidingPaneLayout.
isSlideable
*&& slidingPaneLayout.isOpen
* 做為建構函式參數傳入OnBackPressedCallback
。只有在第二個窗格可滑動的情況下,布林值isSlideable
才會為 true;這種情況可能會發生在顯示單一窗格的小螢幕裝置上。如果第二個窗格 (內容窗格) 完全開啟,則isOpen
的值將為true
。
class SportsListOnBackPressedCallback(
private val slidingPaneLayout: SlidingPaneLayout
): OnBackPressedCallback(slidingPaneLayout.isSlideable && slidingPaneLayout.isOpen)
這段程式碼可確保只有在小螢幕裝置上且內容窗格開啟的情況下,才會啟用這個回呼。
- 如要修正未實作方法造成的錯誤,請按一下紅色燈泡圖示 ,然後選取「Implement members」。
- 在「Implement members」彈出式視窗中按一下「OK」,覆寫
handleOnBackPressed
方法。
您的類別應如下所示:
class SportsListOnBackPressedCallback(
private val slidingPaneLayout: SlidingPaneLayout
): OnBackPressedCallback(slidingPaneLayout.isSlideable && slidingPaneLayout.isOpen) {
/**
* Callback for handling the [OnBackPressedDispatcher.onBackPressed] event.
*/
override fun handleOnBackPressed() {
TODO("Not yet implemented")
}
}
- 在
handleOnBackPressed()
函式中刪除 TODO 陳述式,然後新增下列程式碼來關閉內容窗格並返回清單窗格。
slidingPaneLayout.closePane()
監控 SlidingPaneLayout 的事件
除了處理返回事件外,您也必須監聽及監控與滑動窗格相關的事件。內容窗格滑動時,應視滑動情況啟用或停用回呼。您將使用 PanelSlideListener
進行這項操作。
SlidingPaneLayout.PanelSlideListener
介面包含三個抽象方法:onPanelSlide()
、onPanelOpened()
和 onPanelClosed()
。詳細資料窗格滑動、開啟及關閉時,系統會呼叫這些方法。
- 從
SlidingPaneLayout.PanelSlideListener
展開SportsListOnBackPressedCallback
類別。 - 如要解決錯誤,請導入這三種方法。按一下紅色燈泡,然後在 Android Studio 中選取「Implement members」。
- 您的
SportsListOnBackPressedCallback
類別應如下所示:
class SportsListOnBackPressedCallback(
private val slidingPaneLayout: SlidingPaneLayout
): OnBackPressedCallback(slidingPaneLayout.isSlideable && slidingPaneLayout.isOpen),
SlidingPaneLayout.PanelSlideListener{
override fun handleOnBackPressed() {
slidingPaneLayout.closePane()
}
override fun onPanelSlide(panel: View, slideOffset: Float) {
TODO("Not yet implemented")
}
override fun onPanelOpened(panel: View) {
TODO("Not yet implemented")
}
override fun onPanelClosed(panel: View) {
TODO("Not yet implemented")
}
}
- 移除 TODO 陳述式。
- 在詳細資料窗格開啟 (可見) 時,啟用
OnBackPressedCallback
回呼。實際做法為呼叫setEnabled()
函式並傳入true
。在onPanelOpened()
中編寫以下程式碼:
setEnabled(true)
- 使用屬性存取語法可以簡化上述的程式碼。
override fun onPanelOpened(panel: View) {
isEnabled = true
}
- 同樣地,當詳細資料窗格關閉時,請將「
isEnabled
」 設為false
。
override fun onPanelClosed(panel: View) {
isEnabled = false
}
- 如要完成回呼,最後一個步驟是將
SportsListOnBackPressedCallback
事件監聽器類別新增至事件監聽器清單中,該清單將會收到詳細資料窗格滑動事件的通知。將init
區塊新增至SportsListOnBackPressedCallback
類別。在init
區塊內,呼叫slidingPaneLayout.addPanelSlideListener()
以傳入this
。
init {
slidingPaneLayout.addPanelSlideListener(this)
}
完成的 SportsListOnBackPressedCallback
類別看起來應如下所示:
class SportsListOnBackPressedCallback(
private val slidingPaneLayout: SlidingPaneLayout
): OnBackPressedCallback(slidingPaneLayout.isSlideable && slidingPaneLayout.isOpen),
SlidingPaneLayout.PanelSlideListener{
init {
slidingPaneLayout.addPanelSlideListener(this)
}
override fun handleOnBackPressed() {
slidingPaneLayout.closePane()
}
override fun onPanelSlide(panel: View, slideOffset: Float) {
}
override fun onPanelOpened(panel: View) {
isEnabled = true
}
override fun onPanelClosed(panel: View) {
isEnabled = false
}
}
註冊回呼
如要查看回呼的實際效果,請使用分派器 OnBackPressedDispatcher
註冊回呼。
FragmentActivity
的基礎類別可讓您透過 OnBackPressedDispatcher
控制返回按鈕的行為。OnBackPressedDispatcher
可控管系統如何將返回按鈕事件分派到一或多個 OnBackPressedCallback
物件。
使用 addCallback()
方法新增回呼。這個方法需要使用 LifecycleOwner
。此方法可確保只有在 LifecycleOwner
為 Lifecycle.State.STARTED
時,才會新增 OnBackPressedCallback
。當相關 LifecycleOwner
遭到刪除時,活動或片段也會移除已註冊的回呼,藉此防止記憶體流失,並讓回呼適合用於片段或其他生命週期擁有者 (生命週期較短時)。
addCallback()
方法也會採用將回呼類別做為第二個參數的例項。請按照下列步驟註冊回呼:
- 在
SportsListFragment
檔案的onViewCreated()
函式中,於繫結變數宣告的下方為SlidingPaneLayout
建立例項,並為其指派binding.slidingPaneLayout
的值。
val slidingPaneLayout = binding.slidingPaneLayout
- 在
SportsListFragment
檔案的onViewCreated()
函式中,緊接在slidingPaneLayout
宣告下方,新增下列程式碼:
// Connect the SlidingPaneLayout to the system back button.
requireActivity().onBackPressedDispatcher.addCallback(
viewLifecycleOwner,
SportsListOnBackPressedCallback(slidingPaneLayout)
)
上述程式碼使用了 addCallback()
,並傳入 viewLifecycleOwner
和 SportsListOnBackPressedCallback
的例項。這個回呼的有效期間僅限於片段的生命週期。
- 您現在可以在具手機設定檔的模擬器上執行應用程式,看看自訂返回按鈕的實際運作情形。
10. 鎖定模式
根據預設,在手機等小螢幕裝置上,當清單和詳細資料窗格重疊時,使用者可以左右滑動,不必使用手勢操作即可切換這兩個窗格。您可以設定 SlidingPaneLayout
的鎖定模式,鎖定或解鎖詳細資料窗格。
- 在具手機設定檔的模擬器中,嘗試將詳細資料窗格在畫面中滑開。
- 你也可以在詳細資料窗格中滑動,請自行嘗試。
- 在 Sports 應用程式中,您不必使用這項功能。建議您鎖定
SlidingPaneLayout
,防止使用者透過手勢向內及向外滑動。如要實作這項功能,請在onViewCreated()
方法的slidingPaneLayout
定義下方,將lockMode
設為LOCK_MODE_LOCKED
:
slidingPaneLayout.lockMode = SlidingPaneLayout.LOCK_MODE_LOCKED
如要進一步瞭解其他鎖定模式,請參閱說明文件。
- 再次執行應用程式,注意詳細資料窗格現已鎖定。
恭喜!您已成功將 SlidingPaneLayout
新增至應用程式!
11. 解決方案程式碼
本程式碼研究室的解決方案程式碼位於下方顯示的專案和模組中。
- 前往專案所在的 GitHub 存放區頁面。
- 驗證分支版本名稱與程式碼研究室中指定的分支版本名稱相符。例如,在下列螢幕截圖中,分支版本名稱為「main」。
- 在專案的 GitHub 頁面中,按一下「Code」按鈕,畫面上會出現彈出式視窗。
- 在彈出式視窗中,按一下「Download ZIP」按鈕,將專案儲存至電腦。等待下載作業完成。
- 在電腦中找到該檔案 (可能位於「下載」資料夾中)。
- 按兩下解壓縮 ZIP 檔案。這項操作會建立含有專案檔案的新資料夾。
在 Android Studio 中開啟專案
- 啟動 Android Studio。
- 在「Welcome to Android Studio」視窗中,按一下「Open」。
注意:如果 Android Studio 已開啟,請改為依序選取「File」>「Open」選單選項。
- 在檔案瀏覽器中,前往已解壓縮的專案資料夾所在的位置 (可能位於「Downloads」資料夾中)。
- 按兩下該專案資料夾。
- 等待 Android Studio 開啟專案。
- 按一下「Run」按鈕 ,即可建構並執行應用程式。請確認應用程式的建構作業符合預期。