頂端應用程式列 在應用程式視窗頂端顯示一致的區域 以及目前畫面上的資訊與動作。
應用程式列的擁有權會因應用程式的需求而不同。使用片段時,應用程式列可實作為 ActionBar
,擁有權屬於代管活動或片段版面配置內的工具列。
如果所有畫面都使用相同的應用程式列,且應用程式列始終位於螢幕頂端並與螢幕同寬,則應使用由主題提供的活動代管動作列。使用主題應用程式列有助於維持一致的風格,並提供可代管選項選單和向上按鈕的區域。
如果想進一步控管跨多個畫面的應用程式列大小、位置和動畫,請使用片段代管的工具列。例如,您可能需要收合應用程式列,或希望應用程式列僅占一半的螢幕寬度並垂直置中。
在加載選單和回應使用者互動時,不同情境可能需要採用不同做法。瞭解不同的做法並採用最適合應用程式的做法,不但能節省時間,還能確保應用程式正常運作。
本主題中的範例參照包含可編輯設定檔的 ExampleFragment
。片段會在應用程式列中加載以下由 XML 定義的選單:
<!-- sample_menu.xml -->
<menu
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_settings"
android:icon="@drawable/ic_settings"
android:title="@string/settings"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/action_done"
android:icon="@drawable/ic_done"
android:title="@string/done"
app:showAsAction="ifRoom|withText"/>
</menu>
選單包含兩個選項:一個用於前往設定檔畫面,另一個用於儲存所做的設定檔變更。
活動擁有的應用程式列
應用程式列最常由代管活動擁有。應用程式 列由活動擁有,片段可以與應用程式列互動 方法是覆寫建立片段期間呼叫的架構方法。
透過活動註冊
您必須告知系統,您的應用程式列片段正在參與填入選項選單。方法是在片段的 onCreate(Bundle)
方法中呼叫 setHasOptionsMenu(true)
,如以下範例所示:
Kotlin
class ExampleFragment : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setHasOptionsMenu(true) } }
Java
public class ExampleFragment extends Fragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(true); } }
setHasOptionsMenu(true)
會向系統告知片段想接收選單相關回呼。發生點擊事件等選單相關事件時,系統會先在活動上呼叫事件處理方法,再到片段上呼叫該方法。
不過,應用程式邏輯不應仰賴此順序。如果同一個活動代管多個片段,則每個片段都可以提供選單選項。在此情況下,回呼順序取決於片段的加入順序。
加載選單
如要將選單合併至應用程式列的選項選單,請覆寫片段中的 onCreateOptionsMenu()
。這個方法會接收目前的應用程式列選單和 MenuInflater
做為參數。使用選單 inflater 來建立片段選單的例項,然後將其合併至目前的選單,如以下範例所示:
Kotlin
class ExampleFragment : Fragment() { ... override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { inflater.inflate(R.menu.sample_menu, menu) } }
Java
public class ExampleFragment extends Fragment { ... @Override public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { inflater.inflate(R.menu.sample_menu, menu); } }
圖 2 顯示了更新後的選單。
處理點擊事件
參與選項選單的所有活動和片段都可以回應觸控動作。片段的 onOptionsItemSelected()
會以參數的格式接收選定的選單項目,並透過傳回布林值表示是否耗用觸控動作。活動或片段從 onOptionsItemSelected()
傳回 true
後,其他參與的片段不會再收到回呼。
實作 onOptionsItemSelected()
時,請使用選單項目 itemId
上的 switch
陳述式。如果您擁有選定的項目,請妥善處理觸控作業並傳回 true
,表示點擊事件已處理。如果您不擁有選定的項目,請呼叫 super
實作方式。根據預設,super
實作方式會傳回 false
,方便繼續選單處理作業。
Kotlin
class ExampleFragment : Fragment() { ... override fun onOptionsItemSelected(item: MenuItem): Boolean { return when (item.itemId) { R.id.action_settings -> { // Navigate to settings screen. true } R.id.action_done -> { // Save profile changes. true } else -> super.onOptionsItemSelected(item) } } }
Java
public class ExampleFragment extends Fragment { ... @Override public boolean onOptionsItemSelected(@NonNull MenuItem item) { switch (item.getItemId()) { case R.id.action_settings: { // Navigate to settings screen. return true; } case R.id.action_done: { // Save profile changes. return true; } default: return super.onOptionsItemSelected(item); } } }
動態修改選單
請將隱藏/顯示按鈕或變更圖示的邏輯放在 onPrepareOptionsMenu()
中。系統會在選單顯示前呼叫此方法。
延續上例,「儲存」按鈕應在使用者開始編輯後才顯示,並在使用者儲存後消失。請將這個邏輯新增至 onPrepareOptionsMenu()
,讓選單正確顯示:
Kotlin
class ExampleFragment : Fragment() { ... override fun onPrepareOptionsMenu(menu: Menu){ super.onPrepareOptionsMenu(menu) val item = menu.findItem(R.id.action_done) item.isVisible = isEditing } }
Java
public class ExampleFragment extends Fragment { ... @Override public void onPrepareOptionsMenu(@NonNull Menu menu) { super.onPrepareOptionsMenu(menu); MenuItem item = menu.findItem(R.id.action_done); item.setVisible(isEditing); } }
如果是需要更新選單的情況,例如在使用者按下「編輯」按鈕來編輯設定檔資訊時,請在代管活動上呼叫 invalidateOptionsMenu()
,藉此要求系統呼叫 onCreateOptionsMenu()
。失效後,即可在 onCreateOptionsMenu()
中進行更新。選單加載時,系統會隨即呼叫 onPrepareOptionsMenu()
並更新選單,反映片段的目前狀態。
Kotlin
class ExampleFragment : Fragment() { ... fun updateOptionsMenu() { isEditing = !isEditing requireActivity().invalidateOptionsMenu() } }
Java
public class ExampleFragment extends Fragment { ... public void updateOptionsMenu() { isEditing = !isEditing; requireActivity().invalidateOptionsMenu(); } }
片段擁有的應用程式列
如果應用程式中大多數畫面都不需要應用程式列,或者其中一個畫面需要不同的應用程式列,您可以在片段版面配置中新增 Toolbar
。雖然 Toolbar
可以新增至片段檢視區塊階層中的任何位置,但一般做法是保持在螢幕頂端。如要在片段中使用 Toolbar
,請提供 ID,並在片段中參照這個 ID,與其他檢視區塊中的處理方式一樣。您也可以考慮使用 CoordinatorLayout
行為,製作工具列動畫。
<androidx.appcompat.widget.Toolbar
android:id="@+id/myToolbar"
... />
使用片段擁有的應用程式列時,Google 會建議直接使用 Toolbar
API。請勿使用 setSupportActionBar()
和 Fragment
選單 API,這些僅適用於活動擁有的應用程式列。
加載選單
Toolbar
便利方法 inflateMenu(int)
會使用選單資源的 ID 做為參數。如要將 XML 選單資源加入工具列,請將 resId
傳遞至此方法,如以下範例所示:
Kotlin
class ExampleFragment : Fragment() { ... override fun onViewCreated(view: View, savedInstanceState: Bundle?) { ... viewBinding.myToolbar.inflateMenu(R.menu.sample_menu) } }
Java
public class ExampleFragment extends Fragment { ... @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { ... viewBinding.myToolbar.inflateMenu(R.menu.sample_menu); } }
如要加載另一個 XML 選單資源,請使用新選單的 resId
再次呼叫此方法。新的選單項目會新增至選單,但不會修改或移除現有選單項目。
如要取代現有選單集,請在使用新選單 ID 呼叫 inflateMenu(int)
前清除選單,如以下範例所示:
Kotlin
class ExampleFragment : Fragment() { ... fun clearToolbarMenu() { viewBinding.myToolbar.menu.clear() } }
Java
public class ExampleFragment extends Fragment { ... public void clearToolbarMenu() { viewBinding.myToolbar.getMenu().clear() } }
處理點擊事件
您可以使用 setOnMenuItemClickListener()
方法,將 OnMenuItemClickListener
直接傳遞到工具列。使用者從工具列底部或相關溢位選單的動作按鈕中選取選單項目時,系統就會叫用此事件監聽器。選定的 MenuItem
會傳遞到事件監聽器的 onMenuItemClick()
方法,並可用來耗用動作,如以下範例所示:
Kotlin
class ExampleFragment : Fragment() { ... override fun onViewCreated(view: View, savedInstanceState: Bundle?) { ... viewBinding.myToolbar.setOnMenuItemClickListener { when (it.itemId) { R.id.action_settings -> { // Navigate to settings screen. true } R.id.action_done -> { // Save profile changes. true } else -> false } } } }
Java
public class ExampleFragment extends Fragment { ... @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { ... viewBinding.myToolbar.setOnMenuItemClickListener(item -> { switch (item.getItemId()) { case R.id.action_settings: // Navigate to settings screen. return true; case R.id.action_done: // Save profile changes. return true; default: return false; } }); } }
動態修改選單
片段擁有應用程式列後,您可以在執行階段修改 Toolbar
,方法和修改任何其他檢視畫面一樣。
延續上例,「儲存」選單選項應在使用者開始編輯時才顯示,輕觸後就會再次消失。
Kotlin
class ExampleFragment : Fragment() { ... fun updateToolbar() { isEditing = !isEditing val saveItem = viewBinding.myToolbar.menu.findItem(R.id.action_done) saveItem.isVisible = isEditing } }
Java
public class ExampleFragment extends Fragment { ... public void updateToolbar() { isEditing = !isEditing; MenuItem saveItem = viewBinding.myToolbar.getMenu().findItem(R.id.action_done); saveItem.setVisible(isEditing); } }
新增導覽圖示
如果圖示存在,導覽按鈕會顯示在工具列的開頭。在工具列上設定導覽圖示會使其公開可見。你也可以
請設定導覽專用 onClickListener()
,每當有人呼叫
使用者按下導覽按鈕,如下所示
範例:
Kotlin
class ExampleFragment : Fragment() { ... override fun onViewCreated(view: View, savedInstanceState: Bundle?) { ... myToolbar.setNavigationIcon(R.drawable.ic_back) myToolbar.setNavigationOnClickListener { view -> // Navigate somewhere. } } }
Java
public class ExampleFragment extends Fragment { ... @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { ... viewBinding.myToolbar.setNavigationIcon(R.drawable.ic_back); viewBinding.myToolbar.setNavigationOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // Navigate somewhere. } }); } }