bug: Android Back with a dialog open over a View also pops the View
Maintainer thường phản hồi trong vòng 1 ngày
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 4/5
- Thời gian dự kiến
- 1-2 ngày
- Mức phù hợp với người mới
- 42/100
Hướng nghiên cứu
Start in _handleSystemPopRoute() in packages/flet/lib/src/controls/page.dart, which runs before popRoute() in packages/flet/lib/src/routing/router_delegate.dart. Check whether the Navigator's top route is a pageless dialog before the can_pop and on_confirm_pop checks. Done when a widget test with two Views and an AlertDialog over the second, given one handlePopRoute(), closes only the dialog and sends no view_pop, and a second call pops the View.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Duplicate Check
- I have searched the opened issues and there are no duplicates (#3353 is about
on_view_popfiring on a desktop dialog close, a different path)
Describe the bug
On Android, with two or more Views and a dialog open over the top View (an AlertDialog, a DatePicker, a TimePicker, a BottomSheet or a PopupMenuButton's menu), one Back key press (or a committed Back gesture) closes the dialog and pops the View under it. Material and Flutter's own Navigator close only the topmost route: the dialog.
Cause
PageControl._handleSystemPopRoute() (packages/flet/lib/src/controls/page.dart, added in #5915) is the popRouteHandler of SimpleRouterDelegate (packages/flet/lib/src/routing/router_delegate.dart), so it runs on every system Back before PopNavigatorRouterDelegateMixin.popRoute()'s Navigator.maybePop(). With views.length > 1, when the top View has can_pop true and no on_confirm_pop handler, it calls _markViewAsPopped() (the View leaves the Navigator's pages at once and view_pop is sent) and returns true, so the Navigator is never asked. It does not check for pageless routes above that View's page: dialogs, pickers, sheets and menus are pushed on the same Navigator (useRootNavigator: false in alert_dialog.dart, date_picker.dart, time_picker.dart), and when the View's page is removed the routes attached to it go with it.
The Android Back gesture ends there too: with a dialog on top the page route is not current, so PredictiveBackPageTransitionsBuilder's detector declines the gesture (_isEnabled is route.isCurrent && popGestureEnabled) and the commit falls back to handlePopRoute() → popRoute().
A View that has can_pop=False or an on_confirm_pop handler is not affected: _handleSystemPopRoute() returns null and maybePop() pops the dialog.
Code sample
import flet as ft
def main(page: ft.Page):
def build_views():
page.views.clear()
page.views.append(
ft.View(
route="/",
appbar=ft.AppBar(title=ft.Text("Home")),
controls=[
ft.Button("Open details", on_click=lambda: page.navigate("/details"))
],
)
)
if page.route == "/details":
page.views.append(
ft.View(
route="/details",
appbar=ft.AppBar(title=ft.Text("Details")),
controls=[
ft.Button(
"Open dialog",
on_click=lambda: page.show_dialog(
ft.AlertDialog(
title=ft.Text("Back should close only this"),
on_dismiss=lambda e: print("dialog dismissed"),
)
),
),
ft.Button(
"Open date picker",
on_click=lambda: page.show_dialog(ft.DatePicker()),
),
],
)
)
page.update()
def on_view_pop(e: ft.ViewPopEvent):
print("view_pop", e.route)
page.views.pop()
page.navigate(page.views[-1].route)
page.on_route_change = lambda e: build_views()
page.on_view_pop = on_view_pop
build_views()
ft.run(main)
To reproduce
flet build apk(orflet debug android) and run it on an Android device or emulator.- Tap Open details, then Open dialog (or Open date picker).
- Press Back once (
adb shell input keyevent KEYCODE_BACK).
Expected behavior
The dialog closes and Details stays. A second Back pops Details.
Actual behavior
The dialog closes and Details is popped too: the app shows Home, and the log has view_pop /details with the dismiss.
Seen with the code above, built with flet build apk at 15854a0ac on an Android 14 emulator (API 34, gesture navigation): after one Back with the AlertDialog open, the screen showed Home and the log had view_pop /details then dialog dismissed; with the DatePicker open, Home and view_pop /details. The Back gesture (an edge swipe) did the same in the app where this was found.
Suggested fix
Let the Navigator close a pageless route first: in _handleSystemPopRoute(), return null when the Navigator's top route is not a page (so super.popRoute() → maybePop() pops it), before the can_pop / confirm_pop checks:
final navigator = _navigatorKey.currentState;
if (navigator != null && !_isTopRoutePageBased(navigator)) {
// A dialog, picker, sheet or menu is open over the top view:
// Navigator.maybePop() closes it, and the view stays.
return null;
}
bool _isTopRoutePageBased(NavigatorState navigator) {
Route<dynamic>? top;
navigator.popUntil((route) {
top = route;
return true; // stops at the top route: nothing is popped
});
return top?.settings is Page;
}
A test: two Views, an AlertDialog shown over the second, tester.binding.handlePopRoute() once: the dialog is gone, both Views remain and no view_pop was sent; a second handlePopRoute() sends view_pop for the second View.
Operating system
Android
Flet version
1.1 from the flet-1.1.0 branch at 15854a0ac; the same code is on main.
Regression
Likely since #5915 (December 2025), which added popRouteHandler: before it, popRoute() went straight to Navigator.maybePop().
Additional details
Found in an app that works around it by giving every pushed View an on_confirm_pop that calls confirm_pop(True): with a handler, _handleSystemPopRoute() returns null, maybePop() closes the dialog first, and the View's own pop still goes through onDidRemovePage → view_pop (the handler itself is never called while can_pop is true). With the fix above, that workaround is no longer needed.
Written by Claude Code (AI agent).
- Ngôn ngữ chính
- Python
- Star
- 17.5k
- Fork
- 740
- Merge trung bình
- 1 ngày 8 giờ
- Pull request đã merge (30 ngày)
- 74
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của flet-dev/flet
-
feature: python 3.15 supportĐang mởfeature request
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 66/100
flet-dev/flet#6985 · 3 bình luận · 1 reaction ·
Maintainer thường phản hồi trong vòng 1 ngày
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Web: `TextField.focus()` after `on_submit` discards keys typed while the focus request is in flightĐang mở
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 45/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Web: TextField values set through the DOM (autofill-like) are lost; on_submit carries an empty valueĐang mở
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 48/100
Maintainer thường phản hồi trong vòng 1 ngày
-
feature request
Độ khó 5/5 Hơn một tuần Mức phù hợp với người mới 25/100
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của flet-dev/flet
Issue tương tự
-
integration: logger
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
home-assistant/core#191147 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
Maintainer thường phản hồi trong vòng 1 ngày
-
documentation p4
Độ khó 1/5 1-3 giờ Mức phù hợp với người mới 88/100
MillenniumDawn/focus-tree-creation-tool#417 ·
Maintainer thường phản hồi trong vòng 3 ngày
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
CharlesP44/Beem_Energy#96 ·
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 88/100
rheeloaded/paperpull#153 ·
Maintainer thường phản hồi trong vòng 1 ngày