自動調整版面配置

1. 事前準備

Android 裝置有多種形狀、大小和板型規格。因此,請務必將您的應用程式設計成在無論在不同類型的裝置 (小螢幕或大螢幕裝置) 上執行都毫無問題。開發人員撰寫可正式上架的應用程式可能為 Android WearAndroid AutoAndroid TV 提供支援,但這些主題並不在本課程的涵蓋範圍內。當您的應用程式支援多種螢幕時,您就可以將應用程式提供給更多擁有各種裝置的使用者。

您的應用程式必須具有彈性的版面配置。而不是以特定長寬比和螢幕尺寸的硬性尺寸來決定您的版面配置,您的版面配置應該要能配合不同的螢幕尺寸和方向自動調整。當您的應用程式是在折疊式裝置執行時也能應用相同的原則,裝置的螢幕大小和長寬比會在應用程式執行過程中隨之變更。在本程式碼研究室的結尾,您將會學到可折疊裝置的簡介。

aecb59fc49fb4abf.png

必要條件

  • 如何將程式碼下載到 Android Studio 並執行。
  • 熟悉 Android 架構元件 ViewModelLiveData
  • Navigation 元件的基本知識。

課程內容

  • 如何在應用程式中加入 SlidingPaneLayout

建構項目

  • 更新運動應用程式,配合大螢幕進行調整。

您將會需要的

  • 已安裝 Android Studio 的電腦。
  • 運動 應用程式的範例程式碼。

下載這個程式碼研究室的範例程式碼

本程式碼研究室提供範例程式碼,可延伸至本程式碼研究室所教授的功能。範例程式碼可能包含之前程式碼研究室中熟悉的程式碼,也可能包含較為陌生的程式碼,您將於後續程式碼研究室中學習這些程式碼。

如要從 GitHub 取得本程式碼研究室的程式碼,並在 Android Studio 中開啟,請按照下列步驟操作:

  1. 啟動 Android Studio。
  2. 在「Welcome to Android Studio」(歡迎使用 Android Studio) 視窗中,按一下「Check out project from version control」(從版本控制切換專案)
  3. 選擇「Git」

b89a22e2d8cf3b4e.png

  1. 在「Clone Repository」(複製存放區) 對話方塊中,將提供的程式碼網址貼到「URL」(網址) 方塊中。
  2. 按一下「Test」(測試) 按鈕,等待並確定畫面上顯示「Connection successful」(連線成功) 的綠色彈出式對話框。
  3. 您也可以將「Directory」(目錄) 變更為與建議預設值不同的內容。

e4fb01c402e47bb3.png

  1. 按一下「Clone」(複製) 。Android Studio 會開始擷取程式碼。
  2. 在「Checkout from Version Control」(從版本控制切換) 彈出式視窗中,按一下「Yes」(是)

1902d34f29119530.png

  1. 等待 Android Studio 開啟。
  2. 在程式碼研究室的範例程式碼或解決方案程式碼,選取正確的模組。

2371589274bce21c.png

  1. 按一下「Run」(執行) 按鈕 11c34fc5e516fb1c.png 即可建構並執行程式碼。

2. 範例應用程式總覽

運動應用程式由兩個畫面組成。第一個畫面會顯示運動清單。使用者可以選取特定運動項目,且會顯示第二個畫面。第二個畫面是顯示所選運動新聞的詳細資料畫面。詳細資料畫面會顯示預留位置文字,以簡化導入。

範例程式碼逐步操作說明

你下載的範例程式碼包含已為您預先設計的清單畫面和詳細資料畫面版面配置。在本課程中,您只會將重心放在配合大螢幕自動調整的應用程式。您將用 SlidingPaneLayou 來利用大螢幕。以下是一些檔案的簡短逐步操作說明,以協助您快速上手。

fragment_sports_list.xml

  • 在「設計」檢視畫面中開啟 res/layout/fragment_sports_list.xml
  • 這包含應用程式中第一個畫面的版面配置,也就是運動清單。
  • 這個版面配置包含一個顯示運動新聞清單的 Recyclerview。

19347945e512f94f.png

d9af155f87ddbcdf.png

sports_list_item.xml

  • 在「設計」檢視畫面中開啟 res/layout/sports_list_item.xml
  • 這包含每個項目在 Recyclerview 中版面配置。
  • 這個版面配置包括運動縮圖、新聞標題和簡短運動新聞的預留位置文字。

afe02fbb229608c2.png

fragment_sports_news.xml

  • 在「設計」檢視畫面中開啟 res/layout/fragment_sports_news.xml
  • 這包含應用程式中第二個畫面的版面配置。當使用者從 Recyclerview 選擇運動時,就會顯示這個畫面。
  • 這個版面配置包括運動圖片橫幅和運動新聞的預留位置文字。

f21a8edd59a53233.png

main_activity.xml 和 content_main.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。在觀察程式中會更新運動標題、圖片和新聞。

建立應用程式並加以執行

  1. 在模擬器或裝置上建構並執行應用程式。在運動清單中選取任意項目,應用程式應該會進入第二個包含預留位置文字的畫面。

3. 清單-詳細資料模式

目前的啟動器應用程式無法充分運用平板電腦等較大裝置的螢幕空間。為解決這個問題,您可以使用將在本程式碼研究室學習到的「清單-詳細資料」模式來顯示應用程式的 UI。

在平板電腦上執行應用程式

在這項工作中,您會建立一個具平板電腦設定檔的模擬器。模擬器建立完畢後,您會執行運動應用程式範例程式碼,並觀察 UI。

  1. 在 Android Studio 中,依序前往 「Tools」 (工具) > 「AVD Manager」
  2. 系統會隨即顯示「Android Virtual Device Manager」(Android 虛擬裝置管理工具) 視窗。按一下顯示於底部的「+ Create New Virtual Device」(+ 建立新的虛擬裝置)。
  3. 系統隨即會顯示「Virtual Device Configuration」(虛擬裝置設定) 視窗。請在此處設定模擬器硬體和 OS。按一下左側窗格中的「平板電腦」 。選取中間窗格內的「Pixel C」 或任何其他類似的硬體設定檔。

5c4600c27a47077e.png

  1. 按一下「下一步」
  2. 在撰寫這個程式碼研究室時,選取最新的系統映像檔 R (API 級別 30)。
  3. 按一下「下一步」
  4. 您現在可以選擇是否要重新命名虛擬裝置,這不是必須選項。
  5. 按一下「完成」
  6. 將領您返回「Android Virtual Device Manager」(Android 虛擬裝置管理工具) 視窗。點擊在新建立虛擬裝置旁的啟動圖示 65b3080672a3f31.png
  7. 應觸發具平板電腦設定檔的模擬器。請耐心等候,這可能需要一點時間。
  8. 關閉「Android Virtual Device Manager」(Android 虛擬裝置管理工具) 視窗。
  9. 在新建的模擬器上執行運動應用程式。

200e209de7a2f0ad.png

請注意,在大型裝置上,應用程式不會使用整個螢幕。在大螢幕上,清單-詳細資料會較清單更為有效。項目-詳細資料模式又稱為主要-詳細資料模式,會在版面配置的其中一側顯示項目清單,而且在您輕觸項目時,會在項目旁顯示詳細資料。這類檢視畫面通常只會在大螢幕 (例如平板電腦) 上顯示,因為大螢幕有更多空間,可以顯示更多的內容。

以下是清單-詳細資料模式的範例圖像:

9ebca0de8956275a.png

上述清單-詳細資料模式會在左側顯示項目清單,右側則會顯示所選項目的詳細資料。

同理,如果您在運動應用程式中使用上述模式,則新聞片段將成為詳細資料畫面。

51c9542717d2f875.png

在本程式碼研究室中,您將瞭解如何使用 SlidingPaneLayout 導入清單-詳細資料 UI。

4. SlidingPaneLayout 模式

清單-詳細資料 UI 可能需要根據螢幕大小而採取不同的行為。在大螢幕上,會有充足的空間可並排顯示清單和詳細資料窗格。在清單項目上點擊,即可在詳細資料窗格中顯示詳細資料。不過在小螢幕上,這樣的安排就會相當擁擠。與其同時顯示這兩個窗格,不如逐一顯示。一開始,清單窗格會填滿整個畫面。輕觸某個項目,會以該項目的詳細資料窗格取代清單窗格,同時填滿整個畫面。

您將學習如何使用 SlidingPaneLayout 管理邏輯,以便根據目前的螢幕大小選取適當的使用者體驗。

b0a205de3494e95d.gif

請注意詳細資料窗格在小螢幕上滑過清單窗格的方式。

下方圖片說明 SlidingPaneLayout 在小螢幕上的顯示方式。在選取清單中的項目時,請觀察詳細資料窗格與清單窗格重疊的方式。因此這兩個窗格始終都存在!

1363b67d106ea395.png

c64fa6a0641320dd.png

因此,SlidingPaneLayout 支援在大型裝置上並排顯示兩個窗格,當在手機之類的小型裝置上使用時,會自動調整為只顯示一個窗格。

5. 新增程式庫依附元件

  1. 開啟 build.gradle (Module: Sports.app)
  2. dependencies 區段中,包含下列可在應用程式中使用 SlidingPaneLayout 的依附元件。
dependencies {
...
    implementation "androidx.slidingpanelayout:slidingpanelayout:1.2.0-beta01"
}

6. 設定運動清單片段的 XML

在這項工作中,您將 fragment_sports_list 的根版面配置轉換為 SlidingPaneLayout。如同您所知,SlidingPaneLayout 提供水平的雙窗格版面配置,可在 UI 的頂層使用。這個版面配置將第一個窗格用作內容清單或瀏覽器,並對應到主要詳細資料檢視畫面,以在另一個窗格中顯示內容。

在運動應用程式中,第一個窗格會是顯示運動清單的 RecyclerView,第二個窗格則顯示運動新聞。

新增 SlidingPaneLayout

  1. 開啟 fragment_sports_list.xml。請注意根版面配置為 FrameLayout
  2. 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>
  1. SlidingPaneLayout 中加入 android:id 屬性,並指定一個 @+id/sliding_pane_layout 的值。
<androidx.slidingpanelayout.widget.SlidingPaneLayout
   ...
   android:id="@+id/sliding_pane_layout"
   ...>

在 SlidingPaneLayout 中新增第二個窗格

在這個工作中,您會在 SlidingPaneLayout 中新增第二個子項。這會顯示為右側的內容窗格。

  1. fragment_sports_list.xml 中的 RecyclerView 下新增第二個子項 androidx.fragment.app.FragmentContainerView
  2. FragmentContainerView 中加入必要屬性 layout_heightlayout_width。賦予這兩個屬性一個 match_parent 的值。請注意,您稍後會更新這些值。
<androidx.fragment.app.FragmentContainerView
   android:layout_height="match_parent"
   android:layout_width="match_parent"/>
  1. FragmentContainerView 中加入 android:id 屬性,並指定一個 @+id/detail_container 的值。
android:id="@+id/detail_container"
  1. 使用 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 顯示的平板電腦,會以橫向展開顯示項目

f9a18939802543dd.png

您想在 運動 應用程式中顯示單一窗格 (手機上的運動清單),這適用於寬度少於 600dp 的裝置。如要在平板電腦上顯示這兩個窗格,加總的寬度必須大於 840dp。您可以將 550dp 寬度用在第一個子項,即回收器檢視畫面,300dp 用於第二個子項,即 FragmentContainerView

  1. fragment_sports_list.xml 中,將 RecyclerView 的版面配置寬度變更為 550dp,再將 FragmentContainerView 的版面配置寬度變更為 300dp
<androidx.recyclerview.widget.RecyclerView
   ...
   android:layout_width="550dp"
   .../>

<androidx.fragment.app.FragmentContainerView
   ...
   android:layout_width="300dp"
   .../>
  1. 在具平板電腦設定檔的模擬器與具手機設定檔的模擬器上執行應用程式。

ad148a96d7487e66.png

請注意,平板電腦會顯示兩個窗格。您將在後續步驟中修正平板電腦上第二個窗格的寬度。

  1. 具手機設定檔的模擬器上執行應用程式。

a6be6d199d2975ac.png

新增 layout_weight

在這項工作中,您會修正平板電腦上的 UI,讓第二個窗格佔用全部剩餘的空間。

SlidingPaneLayout 支援定義在檢視畫面未重疊的情況下,使用子項檢視畫面版面配置參數 layout_weight 測量之後,剩餘空間的分割方式。這個參數僅適用於寬度。

  1. fragment_sports_list.xml 中,將 layout_weight 新增至 FragmentContainerView 並指定 1 的值。這樣一來,在測量過清單窗格之後,第二個窗格就會展開填滿剩餘的空間。
android:layout_weight="1"
  1. 執行應用程式。

ce3a93fe501ee5dc.png

恭喜!您已成功新增 SlidingPaneLayout。但這項設定尚未完成。在從清單選擇項目之後,您必須導入返回導覽功能並更新第二個窗格。您將於後續工作中導入這些內容。

7. 切換詳細資料窗格

在具平板電腦設定檔的模擬器上執行應用程式。從運動清單中選取清單項目。請注意,應用程式會導航至詳細資料窗格。

8fedee8d4837909.png

在這項工作中,您會修正這個問題。目前雙窗格內容會以選取的運動進行更新,接著應用程式會導航至 NewsDetailsFragment

  1. SportsListFragment 檔案的 onViewCreated() 函式中,找到以下程式行以前往詳細資料畫面。
// Navigate to the details screen
val action = SportsListFragmentDirections.actionSportsListFragmentToNewsFragment()
this.findNavController().navigate(action)
  1. 將上方程式行以下列程式碼取代:
binding.slidingPaneLayout.openPane()

呼叫 openPane() 上的 SlidingPaneLayout 以將第一個窗格切換至第二個窗格。如果兩個窗格都已顯示 (例如在平板電腦上),則不會出現任何可見效果。

  1. 在平板電腦和手機模擬器上執行應用程式。請注意,雙窗格內容會不斷正確更新。

b0d3c8c263be15f8.png

在您的下一個工作中,您可在應用程式新增的下一個功能為返回導覽功能。

8. 新增自訂的返回導覽功能

如果裝置較小,清單和詳細資料窗格將會重疊,因此需要確保系統返回按鈕會將使用者從詳細資料窗格移回清單窗格。方法是 提供自訂返回導覽功能,並將 OnBackPressedCallback 連結到 SlidingPaneLayout 目前的狀態。

返回導覽

返回導覽 是指使用者如何依據之前造訪的螢幕歷史記錄往回瀏覽。所有 Android 裝置都會針對這類導覽提供返回按鈕。視使用者的 Android 裝置而定,此按鈕有可能是實體按鈕也可能是軟體按鈕。

自訂返回導覽

當使用者導覽應用程式時,Android 系統會保留目的地的返回堆疊。這通常可讓 Android 在使用者按下返回按鈕時正確導覽至之前的目的地。不過有時候應用程式可能需要導入自己的返回行為,以提供最佳的使用者體驗。

舉例來說,在使用像 Chrome 瀏覽器的 WebView 時,您可能會想要覆寫預設的返回按鈕行為,讓使用者可以返回其以往的網頁瀏覽記錄,而不是之前的應用程式畫面。

同樣地,您必須在 SlidingPaneLayout 中提供自訂的返回導覽功能,將應用程式從詳細資料窗格導航回清單窗格。

導入自訂的返回導覽功能

如要在運動應用程式中導入自訂返回導覽功能,您必須:

  • 定義自訂回呼以處理返回鍵按鈕,這會覆寫 OnBackPressedCallback
  • 註冊並新增回呼執行個體。

首先,請定義自訂回呼。

  1. SportsListFragment 檔案中的 SportsListFragment 類別定義下方新增類別。將其命名為 SportsListOnBackPressedCallback
  2. 傳入 SlidingPaneLayoutprivate 執行個體做為建構函式參數。
class SportsListOnBackPressedCallback(
   private val slidingPaneLayout: SlidingPaneLayout
)
  1. OnBackPressedCallback 擴充類別。OnBackPressedCallback 類別會處理 onBackPressed 回呼。您必須盡快修正建構函式的參數錯誤。
class SportsListOnBackPressedCallback(
   private val slidingPaneLayout: SlidingPaneLayout
): OnBackPressedCallback()

OnBackPressedCallback 的建構函式會以布林值表示初始啟用狀態。只有在已啟用回呼的情況下(例如 isEnabled() 傳回 true) 發送器才會呼叫回呼的 handleOnBackPressed() 來處理返回按鈕事件。

  1. slidingPaneLayout.isSlideable*&& slidingPaneLayout.isOpen* 做為建構函式參數傳入 OnBackPressedCallback。只有在第二個窗格可滑動的情況下,布林值「isSlideable」才會為真,這種情況可能會發生在小螢幕且顯示單一窗格的情況下。。如果第二個窗格 (內容窗格) 完全開啟,則「isOpen的值將會是 true
class SportsListOnBackPressedCallback(
   private val slidingPaneLayout: SlidingPaneLayout
): OnBackPressedCallback(slidingPaneLayout.isSlideable && slidingPaneLayout.isOpen)

這個程式碼將確保回呼僅可以在小螢幕裝置上以及內容窗格開啟的情況下啟用。

  1. 為修正未導入方法的錯誤,請按一下紅色燈泡 cb1d366f3ceb9ad5.png,然後選取「Implement members」(導入成員)。
  2. 在「Implement members」(導入成員) 彈出式視窗中按一下「確定」以覆寫 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")
   }
}
  1. handleOnBackPressed() 函式中刪除 TODO 陳述式並新增下列程式碼,關閉內容窗格並返回清單窗格。
slidingPaneLayout.closePane()

監控 SlidingPaneLayout 的事件

除了處理返回事件外,您也必須監聽及監控與滑動窗格相關的事件。隨著內容窗格的滑動,應相應地啟用或停用回呼。請使用 PanelSlideListener 進行這項操作。

SlidingPaneLayout.PanelSlideListener 介面包含三種抽象方法:onPanelSlide()onPanelOpened()onPanelClosed()。當詳細資料窗格的滑動、開啟和關閉時,系統會呼叫這些方法。

  1. SlidingPaneLayout.PanelSlideListener 展開 SportsListOnBackPressedCallback 類別。
  2. 如要解決錯誤,請導入這三種方法。按一下紅色燈泡,然後選取 Android Studio 中的「Implement members」(導入成員)

bddae0e597f6e1d3.png

  1. 您的 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")
   }
}
  1. 移除 TODO 陳述式。
  2. 在開啟詳細資料窗格 (可見) 時,啟用 OnBackPressedCallback 回呼。方法是呼叫 setEnabled() 函式並傳入 true。在 onPanelOpened() 中編寫以下程式碼:
setEnabled(true)
  1. 使用屬性存取語法可以簡化上述的程式碼。
override fun onPanelOpened(panel: View) {
   isEnabled = true
}
  1. 同樣地,當詳細資料窗格關閉時,請將「isEnabled 設為 false
override fun onPanelClosed(panel: View) {
   isEnabled = false
}
  1. 完成回呼的最後一個步驟,是將 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。此方法可確保只有在 LifecycleOwnerLifecycle.State.STARTED 時,才會新增 OnBackPressedCallback。當相關的 LifecycleOwner 被刪除時,該活動或片段也會移除已註冊的回呼以防止記憶體流失,讓回呼適合用於比活動的生命週期更短的片段或其他生命週期的擁有者。

addCallback() 方法也會將回呼類別當做第二個參數使用。您將按照下列步驟註冊回呼:

  1. SportsListFragment 檔案的 onViewCreated() 函式中,緊接在繫結變數宣告下方,為 SlidingPaneLayout 建立執行個體,並為其指派 binding.slidingPaneLayout 的值。
val slidingPaneLayout = binding.slidingPaneLayout
  1. SportsListFragment 檔案的 onViewCreated() 函式中,緊接在 slidingPaneLayout 宣告下方,新增下列程式碼:
// Connect the SlidingPaneLayout to the system back button.
requireActivity().onBackPressedDispatcher.addCallback(
   viewLifecycleOwner,
   SportsListOnBackPressedCallback(slidingPaneLayout)
)

上述程式碼使用了 addCallback(),並傳入 viewLifecycleOwnerSportsListOnBackPressedCallback 的執行個體。這個回呼只會在片段的生命週期中啟用。

  1. 您現在可以在具手機設定檔的模擬器上執行應用程式,看看自訂返回按鈕的實際運作情形。

33967fa8fde5b902.gif

9. 鎖定模式

根據預設,當清單和詳細資料窗格在像電話這類小型螢幕上重疊時,使用者可以左右滑動,不使用 手勢操作 即可在兩個窗格之間切換。您可以設定 SlidingPaneLayout 的鎖定模式,藉此鎖定或解鎖詳細資料窗格。

  1. 在具手機設定檔的模擬器中,嘗試將詳細資料窗格在畫面中滑開。
  2. 你也可以在詳細資料窗格中滑動,請自行嘗試。
  3. 這不是 運動 應用程式中的理想功能。建議您鎖定 SlidingPaneLayout,以免使用者使用手勢將畫面滑來滑去。如要導入這個功能,請在 slidingPaneLayout 定義下方的 onViewCreated() 方法中,將「lockMode設為「LOCK_MODE_LOCKED
slidingPaneLayout.lockMode = SlidingPaneLayout.LOCK_MODE_LOCKED

如要進一步瞭解其他鎖定模式,請參閱 說明文件

  1. 再次執行應用程式,注意詳細資料窗格現已鎖定。

恭喜!您已成功將 SlidingPaneLayout 新增至應用程式!

10. 解決方案程式碼

本程式碼研究室的解決方案程式碼在下方顯示的專案和模組中。

如要取得這個程式碼研究室的程式碼,並在 Android Studio 中開啟,請按照下列步驟操作:

取得程式碼

  1. 按一下所提供的網址。系統會在瀏覽器中開啟專案的 GitHub 頁面。
  2. 在專案的 GitHub 頁面中,按一下「Code」(程式碼) 按鈕,開啟對話方塊。

5b0a76c50478a73f.png

  1. 在對話方塊中點選「Download ZIP」(下載 ZIP) 按鈕,將專案儲存至電腦。等待下載作業完成。
  2. 在電腦上尋找檔案 (可能位於「下載」資料夾中)。
  3. 按兩下 ZIP 檔案,將檔案解壓縮。這項操作會建立含有專案檔案的新資料夾。

在 Android Studio 中開啟專案

  1. 啟動 Android Studio。
  2. 在「Welcome to Android Studio」(歡迎使用 Android Studio) 視窗中,按一下「Open an existing Android Studio project」(開啟現有的 Android Studio 專案)。

36cc44fcf0f89a1d.png

注意:如果 Android Studio 已開啟,請依序選取「File」(檔案) >「New」(新增) >「Import Project」(匯入專案) 選單選項。

21f3eec988dcfbe9.png

  1. 在「Import Project」(匯入專案) 對話方塊中,前往未壓縮專案資料夾所在的位置 (可能位於「下載」資料夾中)。
  2. 按兩下該專案資料夾。
  3. 等待 Android Studio 開啟專案。
  4. 按一下「Run」(執行) 按鈕 11c34fc5e516fb1c.png 即可建構並執行應用程式,請確認應用程式的建構符合預期。
  5. 在「Project」(專案) 工具視窗中瀏覽專案檔案,查看應用程式的設定方式。

11. 瞭解詳情