結束 Wear 上的全螢幕活動
透過集合功能整理內容
你可以依據偏好儲存及分類內容。
試試 Compose 的方式
建議您使用 Wear OS 版 Jetpack Compose,這是 Wear OS 的推薦 UI 工具包。
使用者可以從左至右滑動,退出 Wear OS 活動。如果應用程式支援水平捲動,使用者只要前往內容邊緣,然後由左向右滑動,即可離開。按下電源鍵也會將使用者帶回錶面。
滑動關閉手勢
使用者可以從左向右滑動來關閉目前的畫面。因此,建議您使用下列方法:
我們也建議您不要在應用程式中加入水平滑動手勢。
關閉活動
活動會自動支援滑動關閉手勢。從左到右滑動活動會導致活動關閉,應用程式會向下瀏覽
返回堆疊。
關閉片段
如要支援片段中的滑動關閉功能,您必須在
SwipeDismissFrameLayout
類別中包裝含有片段的檢視畫面。決定是否使用片段時,請考量這一點。使用 SwipeDismissFrameLayout
類別,如以下範例所示:
Kotlin
class SwipeDismissFragment : Fragment() {
private val callback = object : SwipeDismissFrameLayout.Callback() {
override fun onSwipeStarted(layout: SwipeDismissFrameLayout) {
// Optional
}
override fun onSwipeCanceled(layout: SwipeDismissFrameLayout) {
// Optional
}
override fun onDismissed(layout: SwipeDismissFrameLayout) {
// Code here for custom behavior, such as going up the
// back stack and destroying the fragment but staying in the app.
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View =
SwipeDismissFrameLayout(activity).apply {
// If the fragment should fill the screen (optional), then in the layout file,
// in the androidx.wear.widget.SwipeDismissFrameLayout element,
// set the android:layout_width and android:layout_height attributes
// to "match_parent".
inflater.inflate(
R.layout.swipe_dismiss_frame_layout,
this,
false
).also { inflatedView ->
addView(inflatedView)
}
addCallback(callback)
}
}
Java
public class SwipeDismissFragment extends Fragment {
private final Callback callback =
new Callback() {
@Override
public void onSwipeStart() {
// Optional
}
@Override
public void onSwipeCancelled() {
// Optional
}
@Override
public void onDismissed(SwipeDismissFrameLayout layout) {
// Code here for custom behavior, such as going up the
// back stack and destroying the fragment but staying in the app.
}
};
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
SwipeDismissFrameLayout swipeLayout = new SwipeDismissFrameLayout(getActivity());
// If the fragment should fill the screen (optional), then in the layout file,
// in the androidx.wear.widget.SwipeDismissFrameLayout element,
// set the android:layout_width and android:layout_height attributes
// to "match_parent".
View inflatedView = inflater.inflate(R.layout.swipe_dismiss_frame_layout, swipeLayout, false);
swipeLayout.addView(inflatedView);
swipeLayout.addCallback(callback);
return swipeLayout;
}
}
注意:在活動中使用片段時,請使用 FragmentManager.add
而非 FragmentManager.replace
,以支援滑動關閉手勢。這有助於確保先前的片段在滑動時,會在頂層片段下方算繪。
在某些情況下,例如在包含支援平移功能的地圖檢視畫面中,使用者介面無法防止水平滑動。在這種情況下,您有兩種選擇:
- 如果返回堆疊較短,使用者可以按下電源鍵,關閉應用程式並返回錶面主畫面。
- 如果您希望使用者向下瀏覽返回堆疊,可以將檢視畫面包裝在支援邊緣滑動的
SwipeDismissFrameLayout
物件中。當檢視區塊或其子項從
canScrollHorizontally()
呼叫傳回 true
時,系統就會啟用邊緣滑動功能。邊緣滑動可讓使用者從螢幕最左邊 10% 的區域滑動,而不是從檢視畫面中的任何位置滑動來關閉檢視畫面。
以下範例說明如何在 SwipeDismissFrameLayout
物件中包裝檢視畫面:
<androidx.wear.widget.SwipeDismissFrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/swipe_dismiss_root" >
<TextView
android:id="@+id/test_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="Swipe me to dismiss me." />
</androidx.wear.widget.SwipeDismissFrameLayout>
Kotlin
activity?.findViewById<SwipeDismissFrameLayout>(R.id.swipe_dismiss_root)?.apply {
addCallback(object : SwipeDismissFrameLayout.Callback() {
override fun onDismissed(layout: SwipeDismissFrameLayout) {
layout.visibility = View.GONE
}
})
}
Java
SwipeDismissFrameLayout testLayout =
(SwipeDismissFrameLayout) activity.findViewById(R.id.swipe_dismiss_root);
testLayout.addCallback(new SwipeDismissFrameLayout.Callback() {
@Override
public void onDismissed(SwipeDismissFrameLayout layout) {
layout.setVisibility(View.GONE);
}
}
);
不建議的做法:停用滑動關閉功能
我們通常不建議停用滑動關閉功能,因為使用者預期可以透過滑動關閉任何畫面。在特殊情況下,您可以在
樣式資源中擴充預設主題,並將 android:windowSwipeToDismiss
屬性設為 false
,如以下程式碼範例所示:
<resources>
<style name="AppTheme" parent="@android:style/Theme.DeviceDefault">
<item name="android:windowSwipeToDismiss">false</item>
</style>
</resources>
接著,您可以在使用者首次使用應用程式時,告知他們只要按下電源鍵即可退出應用程式。
按下實體電源鍵會傳送電源鍵事件。因此,您無法使用電源鍵當作返回按鈕或一般導覽功能。
按下電源鍵時,使用者會回到錶面主畫面。但有兩種例外情況:
- 如果使用者處於輸入法編輯器 (IME) 中,例如手寫辨識畫面,按下按鈕會關閉 IME,並將使用者帶回應用程式。
- 如果使用者位於錶面,按下硬體按鈕會開啟應用程式啟動器。
請注意,按下電源鍵時,Activity
類別的
isFinishing()
方法不會傳回 true
,因此您無法攔截按鍵事件。
這個頁面中的內容和程式碼範例均受《內容授權》中的授權所規範。Java 與 OpenJDK 是 Oracle 和/或其關係企業的商標或註冊商標。
上次更新時間:2025-07-26 (世界標準時間)。
[null,null,["上次更新時間:2025-07-26 (世界標準時間)。"],[],[],null,["# Exit full-screen activities on Wear\n\nTry the Compose way \nJetpack Compose on Wear OS is the recommended UI toolkit for Wear OS. \n[Try Compose on Wear OS →](/training/wearables/compose) \n\n\nA user can exit a Wear OS activity by swiping from left to right.\nIf the app has horizontal scrolling, the user exits by navigating to the edge\nof the content and then swiping from left to right.\nPressing the power button also returns the user to the watch face.\n\nThe swipe-to-dismiss gesture\n----------------------------\n\n\nUsers swipe from left to right to close the current screen. Therefore, we\nrecommend that you use the following:\n\n- Vertical layouts\n- Content containers\n\n\nWe also recommend that your app not contain\nhorizontal swiping gestures.\n\n### Dismiss an activity\n\n\nActivities automatically support swipe-to-dismiss. Swiping an activity\nfrom left to right results in dismissal of the activity, and the app\nnavigates down the [back stack](/guide/components/tasks-and-back-stack).\n\n### Dismiss a fragment\n\n\nTo support swipe-to-dismiss in fragments, you must wrap the\nfragment-containing view in the\n[`SwipeDismissFrameLayout`](/reference/androidx/wear/widget/SwipeDismissFrameLayout) class. Take this into consideration\nwhen deciding whether to use fragments. Use the\n`SwipeDismissFrameLayout` class as shown in the following example: \n\n### Kotlin\n\n```kotlin\nclass SwipeDismissFragment : Fragment() {\n private val callback = object : SwipeDismissFrameLayout.Callback() {\n override fun onSwipeStarted(layout: SwipeDismissFrameLayout) {\n // Optional\n }\n\n override fun onSwipeCanceled(layout: SwipeDismissFrameLayout) {\n // Optional\n }\n\n override fun onDismissed(layout: SwipeDismissFrameLayout) {\n // Code here for custom behavior, such as going up the\n // back stack and destroying the fragment but staying in the app.\n }\n }\n\n override fun onCreateView(\n inflater: LayoutInflater,\n container: ViewGroup?,\n savedInstanceState: Bundle?\n ): View =\n SwipeDismissFrameLayout(activity).apply {\n\n // If the fragment should fill the screen (optional), then in the layout file,\n // in the androidx.wear.widget.SwipeDismissFrameLayout element,\n // set the android:layout_width and android:layout_height attributes\n // to \"match_parent\".\n\n inflater.inflate(\n R.layout.swipe_dismiss_frame_layout,\n this,\n false\n ).also { inflatedView -\u003e\n addView(inflatedView)\n }\n addCallback(callback)\n }\n}\n```\n\n### Java\n\n```java\npublic class SwipeDismissFragment extends Fragment {\n private final Callback callback =\n new Callback() {\n @Override\n public void onSwipeStart() {\n // Optional\n }\n\n @Override\n public void onSwipeCancelled() {\n // Optional\n }\n\n @Override\n public void onDismissed(SwipeDismissFrameLayout layout) {\n // Code here for custom behavior, such as going up the\n // back stack and destroying the fragment but staying in the app.\n }\n };\n\n @Override\n public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n SwipeDismissFrameLayout swipeLayout = new SwipeDismissFrameLayout(getActivity());\n\n // If the fragment should fill the screen (optional), then in the layout file,\n // in the androidx.wear.widget.SwipeDismissFrameLayout element,\n // set the android:layout_width and android:layout_height attributes\n // to \"match_parent\".\n\n View inflatedView = inflater.inflate(R.layout.swipe_dismiss_frame_layout, swipeLayout, false);\n swipeLayout.addView(inflatedView);\n swipeLayout.addCallback(callback);\n\n return swipeLayout;\n }\n}\n```\n\n\n**Note:** When you use fragments within your activity, use\n[`FragmentManager.add`](/reference/androidx/fragment/app/FragmentTransaction#add(int,%20java.lang.Class\u003c?%20extends%20androidx.fragment.app.Fragment\u003e,%20android.os.Bundle))\nrather than\n[`FragmentManager.replace`](/reference/androidx/fragment/app/FragmentTransaction#replace(int,%20java.lang.Class\u003c?%20extends%20androidx.fragment.app.Fragment\u003e,%20android.os.Bundle))\nto support the swipe-to-dismiss gesture.\nThis helps ensure that your previous fragment renders under the top fragment while it is\nswiped away.\n\n### Horizontal scrollable views\n\n\nIn some cases, such as in a view containing a map that supports panning,\nthe user interface can't prevent horizontal swiping. In this\nscenario, there are two choices:\n\n- If the back stack is short, the user can dismiss the app and return to the watch face home screen by pressing the power button.\n- If you want the user to go down the back stack, you can wrap the view in a `SwipeDismissFrameLayout` object, which supports edge swipe. Edge swipe is enabled when the view or its children returns `true` from a [`canScrollHorizontally()`](/reference/android/view/View#canScrollHorizontally(int)) call. Edge swipe lets the user dismiss the view by swiping from the leftmost 10% of the screen, rather than anywhere in the view.\n\n\nThe following examples show how to wrap a view in a\n`SwipeDismissFrameLayout` object: \n\n```xml\n\u003candroidx.wear.widget.SwipeDismissFrameLayout\n xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:tools=\"http://schemas.android.com/tools\"\n android:layout_width=\"match_parent\"\n android:layout_height=\"match_parent\"\n android:id=\"@+id/swipe_dismiss_root\" \u003e\n\n \u003cTextView\n android:id=\"@+id/test_content\"\n android:layout_width=\"match_parent\"\n android:layout_height=\"match_parent\"\n android:gravity=\"center\"\n android:text=\"Swipe me to dismiss me.\" /\u003e\n\u003c/androidx.wear.widget.SwipeDismissFrameLayout\u003e\n``` \n\n### Kotlin\n\n```kotlin\nactivity?.findViewById\u003cSwipeDismissFrameLayout\u003e(R.id.swipe_dismiss_root)?.apply {\n addCallback(object : SwipeDismissFrameLayout.Callback() {\n\n override fun onDismissed(layout: SwipeDismissFrameLayout) {\n layout.visibility = View.GONE\n }\n })\n}\n```\n\n### Java\n\n```java\nSwipeDismissFrameLayout testLayout =\n (SwipeDismissFrameLayout) activity.findViewById(R.id.swipe_dismiss_root);\ntestLayout.addCallback(new SwipeDismissFrameLayout.Callback() {\n @Override\n public void onDismissed(SwipeDismissFrameLayout layout) {\n layout.setVisibility(View.GONE);\n }\n }\n);\n```\n\n### Not recommended: Disable swipe-to-dismiss\n\n\nWe don't generally recommend disabling swipe-to-dismiss, because the user\nexpects to dismiss any screen with a swipe. In an exceptional case,\nyou can extend the default theme\nin a [style resource](/guide/topics/resources/style-resource)\nand set the `android:windowSwipeToDismiss` attribute\nto `false`, as shown in the following code sample: \n\n```xml\n\u003cresources\u003e\n \u003cstyle name=\"AppTheme\" parent=\"@android:style/Theme.DeviceDefault\"\u003e\n \u003citem name=\"android:windowSwipeToDismiss\"\u003efalse\u003c/item\u003e\n \u003c/style\u003e\n\u003c/resources\u003e\n```\n\n\nYou can then inform users on their first use of your app\nthat they can exit the app by pressing the power button.\n\nDismissal with the power button\n-------------------------------\n\n\nA press of the physical power button sends a power key\nevent. Therefore, you can't use the power button as a back\nbutton or for navigation in general.\n\n\nWhen pressed, the power button returns the user to the watch face home screen. There are two exceptions:\n\n- If the user is in an Input Method Editor (IME), such as a handwriting recognition screen, pressing the button closes the IME and returns the user to the app.\n- If the user is at the watch face, pressing the hardware button opens the app launcher.\n\n\n**Note** that when the power button is pressed, the\n[isFinishing()](/reference/android/app/Activity#isFinishing()) method of the `Activity` class does\nnot return `true`, and you can't intercept the key event. \n\nFor more information, see\n[Navigation](/training/wearables/design/navigation)."]]