Android 預測性返回
- 摘要
- 背景
- 遷移指南
- 從 WillPopScope 遷移到 PopScope
- 為巢狀 Navigator 從 WillPopScope 遷移到 NavigatorPopHandler
- 從 Form.onWillPop 遷移到 Form.canPop 和 Form.onPopInvoked
- 從 Route.willPop 遷移到 Route.popDisposition
- 從 ModalRoute.add/removeScopedWillPopCallback 遷移到 ModalRoute.(un)registerPopEntry
- 從 ModalRoute.hasScopedWillPopCallback 遷移到 ModalRoute.popDisposition
- 遷移返回確認對話框
- 支援預測性返回
- 時間軸
- 參考資料
摘要
#為了支援 Android 14 的預測性返回功能,一組預先 (ahead-of-time) 的 API 已取代即時 (just-in-time) 的導航 API,例如 WillPopScope
和 Navigator.willPop
。
背景
#Android 14 引入了預測性返回功能,它允許使用者在有效的返回手勢期間預覽目前路由後面的內容,並決定是否繼續返回或取消手勢。這與 Flutter 的導航 API 不相容,因為 Flutter 的導航 API 允許開發人員在接收到返回手勢後取消返回手勢。
使用預測性返回時,返回動畫會在使用者發起手勢且尚未提交之前立即開始。Flutter 應用程式沒有機會決定此時是否允許發生。必須預先知道。
因此,所有允許 Flutter 應用程式開發人員在收到返回手勢時取消返回導航的 API 現在都已棄用。它們已被等效的 API 取代,這些 API 會一直維持一個布林值狀態,該狀態指示是否有可能進行返回導航。當有可能時,預測性返回動畫會像往常一樣發生。否則,導航會停止。在這兩種情況下,都會通知應用程式開發人員已嘗試返回以及是否成功。
PopScope
#PopScope
類別直接取代 WillPopScope
,以便啟用預測性返回。它不是在發生彈出時才決定是否可行,而是使用 canPop
布林值預先設定。您仍然可以使用 onPopInvoked
來監聽彈出。
PopScope(
canPop: _myPopDisableEnableLogic(),
onPopInvoked: (bool didPop) {
// Handle the pop. If `didPop` is false, it was blocked.
},
)
Form.canPop 和 Form.onPopInvoked
#這兩個新參數基於 PopScope
,並取代已棄用的 Form.onWillPop
參數。它們以與上述相同的方式與 PopScope
一起使用。
Form(
canPop: _myPopDisableEnableLogic(),
onPopInvoked: (bool didPop) {
// Handle the pop. If `didPop` is false, it was blocked.
},
)
Route.popDisposition
#此 getter 會同步傳回路由的 RoutePopDisposition
,它描述彈出的行為方式。
if (myRoute.popDisposition == RoutePopDisposition.doNotPop) {
// Back gestures are disabled.
}
ModalRoute.registerPopEntry 和 ModalRoute.unregisterPopEntry
#使用這些方法來註冊 PopScope
小工具,以便在路由決定是否可以彈出時進行評估。在實作自訂的 PopScope
小工具時,可能會使用此功能。
@override
void didChangeDependencies() {
super.didChangeDependencies();
final ModalRoute<dynamic>? nextRoute = ModalRoute.of(context);
if (nextRoute != _route) {
_route?.unregisterPopEntry(this);
_route = nextRoute;
_route?.registerPopEntry(this);
}
}
遷移指南
#從 WillPopScope
遷移到 PopScope
#WillPopScope
小工具的直接替代品是 PopScope
小工具。在許多情況下,在 onWillPop
中返回手勢時執行的邏輯可以在建構時完成並設定為 canPop
。
遷移前的程式碼
WillPopScope(
onWillPop: () async {
return _myCondition;
},
child: ...
),
遷移後的程式碼
PopScope(
canPop: _myCondition,
child: ...
),
對於需要通知已嘗試彈出的情況,可以使用 onPopInvoked
方法,其方式與 onWillPop
類似。請記住,雖然 onWillPop
是在處理彈出之前呼叫的,並且可以取消它,但 onPopInvoked
是在彈出處理完成後呼叫的。
遷移前的程式碼
WillPopScope(
onWillPop: () async {
_myHandleOnPopMethod();
return true;
},
child: ...
),
遷移後的程式碼
PopScope(
canPop: true,
onPopInvoked: (bool didPop) {
_myHandleOnPopMethod();
},
child: ...
),
為巢狀 Navigator 從 WillPopScope 遷移到 NavigatorPopHandler
#WillPopScope
的一個非常常見的用例是在使用巢狀 Navigator
小工具時正確處理返回手勢。也可以使用 PopScope
來執行此操作,但現在有一個包裝小工具可以使此操作更容易:NavigatorPopHandler
。
遷移前的程式碼
WillPopScope(
onWillPop: () async => !(await _nestedNavigatorKey.currentState!.maybePop()),
child: Navigator(
key: _nestedNavigatorKey,
…
),
)
遷移後的程式碼
NavigatorPopHandler(
onPop: () => _nestedNavigatorKey.currentState!.pop(),
child: Navigator(
key: _nestedNavigatorKey,
…
),
)
從 Form.onWillPop 遷移到 Form.canPop 和 Form.onPopInvoked
#先前,Form
在底層使用 WillPopScope
實例並公開其 onWillPop
方法。這已被 PopScope
取代,PopScope
公開其 canPop
和 onPopInvoked
方法。遷移與從 WillPopScope
遷移到 PopScope
相同,詳情如上所述。
從 Route.willPop 遷移到 Route.popDisposition
#Route
的 willPop
方法會傳回 Future<RoutePopDisposition>
,以適應彈出可能被取消的事實。既然不再如此,此邏輯已簡化為同步 getter。
遷移前的程式碼
if (await myRoute.willPop() == RoutePopDisposition.doNotPop) {
...
}
遷移後的程式碼
if (myRoute.popDisposition == RoutePopDisposition.doNotPop) {
...
}
從 ModalRoute.add/removeScopedWillPopCallback 遷移到 ModalRoute.(un)registerPopEntry
#在內部,ModalRoute
會透過使用 addScopedWillPopCallback
和 removeScopedWillPopCallback
註冊它們,來追蹤其小工具子樹中 WillPopScope
的存在。由於 PopScope
取代了 WillPopScope
,這些方法已分別被 registerPopEntry
和 unregisterPopEntry
取代。
PopEntry
由 PopScope
實作,以便僅公開 ModalRoute
所需的最低資訊。任何撰寫自己的 PopScope
的人都應實作 PopEntry
,並向其封閉的 ModalRoute
註冊和取消註冊其小工具。
遷移前的程式碼
@override
void didChangeDependencies() {
super.didChangeDependencies();
if (widget.onWillPop != null) {
_route?.removeScopedWillPopCallback(widget.onWillPop!);
}
_route = ModalRoute.of(context);
if (widget.onWillPop != null) {
_route?.addScopedWillPopCallback(widget.onWillPop!);
}
}
遷移後的程式碼
@override
void didChangeDependencies() {
super.didChangeDependencies();
_route?.unregisterPopEntry(this);
_route = ModalRoute.of(context);
_route?.registerPopEntry(this);
}
從 ModalRoute.hasScopedWillPopCallback 遷移到 ModalRoute.popDisposition
#此方法先前用於與預測性返回非常相似的用例,但在 Cupertino 程式庫中,某些返回轉換允許取消導航。當甚至有可能 WillPopScope
小工具取消彈出時,路由轉換會被停用。
既然 API 要求預先決定,這不再需要以推測的方式基於 PopScope
小工具的存在。ModalRoute
是否被 PopScope
小工具封鎖彈出的明確邏輯已納入 ModalRoute.popDisposition
。
遷移前的程式碼
if (_route.hasScopedWillPopCallback) {
// Disable predictive route transitions.
}
遷移後的程式碼
if (_route.popDisposition == RoutePopDisposition.doNotPop) {
// Disable predictive route transitions.
}
遷移返回確認對話框
#WillPopScope
有時會用於在收到返回手勢時顯示確認對話方塊。使用 PopScope
仍然可以使用類似的模式來完成此操作。
遷移前的程式碼
WillPopScope(
onWillPop: () async {
final bool? shouldPop = await _showBackDialog();
return shouldPop ?? false;
},
child: child,
)
遷移後的程式碼
return PopScope(
canPop: false,
onPopInvoked: (bool didPop) async {
if (didPop) {
return;
}
final NavigatorState navigator = Navigator.of(context);
final bool? shouldPop = await _showBackDialog();
if (shouldPop ?? false) {
navigator.pop();
}
},
child: child,
)
支援預測性返回
#- 執行 Android 14 (API 層級 34) 或以上版本。
- 在裝置上的「開發人員選項」下啟用預測性返回的功能旗標。在未來的 Android 版本上,這將是不必要的。
- 在
android/app/src/main/AndroidManifest.xml
中設定android:enableOnBackInvokedCallback="true"
。如果需要,請參閱Android 的完整指南,以了解如何遷移 Android 應用程式以支援預測性返回。 - 請確定您使用的是 Flutter
3.14.0-7.0.pre
或更高版本。 - 請確定您的 Flutter 應用程式未使用
WillPopScope
小工具。使用它會停用預測性返回。如果需要,請改用PopScope
。 - 執行應用程式並執行返回手勢(從螢幕左側滑動)。
時間軸
#在版本中加入:3.14.0-7.0.pre
在穩定版本中:3.16
參考資料
#API 文件
PopScope
NavigatorPopHandler
PopScope
NavigatorPopHandler
PopEntry
Form.canPop
Form.onPopInvoked
Route.popDisposition
ModalRoute.registerPopEntry
ModalRoute.unregisterPopEntry
相關問題
相關的 PR
除非另有說明,否則此網站上的文件反映 Flutter 的最新穩定版本。頁面上次更新時間為 2024-08-19。 檢視原始碼 或 回報問題。