From 2415eca4d208802e97b23f7e5f8becc361f99fcb Mon Sep 17 00:00:00 2001 From: Anurag Roy <44899587+RoyARG02@users.noreply.github.com> Date: Wed, 24 Mar 2021 02:01:02 +0530 Subject: [PATCH] [FloatingActionButtonLocation] Avoid docked FAB to be clipped by the software keyboard (#77769) --- .../floating_action_button_location.dart | 18 +++++++++++- .../floating_action_button_location_test.dart | 29 +++++++++++++++++-- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/packages/flutter/lib/src/material/floating_action_button_location.dart b/packages/flutter/lib/src/material/floating_action_button_location.dart index dc6350cdc5..d8cb9df184 100644 --- a/packages/flutter/lib/src/material/floating_action_button_location.dart +++ b/packages/flutter/lib/src/material/floating_action_button_location.dart @@ -584,7 +584,23 @@ mixin FabDockedOffsetY on StandardFabLocation { final double bottomSheetHeight = scaffoldGeometry.bottomSheetSize.height; final double fabHeight = scaffoldGeometry.floatingActionButtonSize.height; final double snackBarHeight = scaffoldGeometry.snackBarSize.height; - final double safeMargin = bottomViewPadding > contentMargin ? bottomViewPadding : 0.0; + final double bottomMinInset = scaffoldGeometry.minInsets.bottom; + + double safeMargin; + + if (contentMargin > bottomMinInset + fabHeight / 2.0) { + // If contentMargin is higher than bottomMinInset enough to display the + // FAB without clipping, don't provide a margin + safeMargin = 0.0; + } else if (bottomMinInset == 0.0) { + // If bottomMinInset is zero(the software keyboard is not on the screen) + // provide bottomViewPadding as margin + safeMargin = bottomViewPadding; + } else { + // Provide a margin that would shift the FAB enough so that it stays away + // from the keyboard + safeMargin = fabHeight / 2.0 + kFloatingActionButtonMargin; + } double fabY = contentBottom - fabHeight / 2.0 - safeMargin; // The FAB should sit with a margin between it and the snack bar. diff --git a/packages/flutter/test/material/floating_action_button_location_test.dart b/packages/flutter/test/material/floating_action_button_location_test.dart index 09e3791c54..23b7cd3c05 100644 --- a/packages/flutter/test/material/floating_action_button_location_test.dart +++ b/packages/flutter/test/material/floating_action_button_location_test.dart @@ -1037,7 +1037,9 @@ void main() { ); }); - // Test docked locations, for each (6), keyboard presented or not: + // Test docked locations, for each (6), keyboard presented or not. + // If keyboard is presented and resizeToAvoidBottomInset: true, test whether + // the FAB is away from the keyboard(and thus not clipped): // - Default // - Default with resizeToAvoidBottomInset: false // - docked with BottomNavigationBar @@ -1057,6 +1059,7 @@ void main() { const double keyboardHeight = 200.0; const double viewPadding = 50.0; const double bottomNavHeight = 106.0; + const double scaffoldHeight = 600.0; final Key floatingActionButton = UniqueKey(); final double fabHeight = mini ? 48.0 : 56.0; // Default @@ -1084,9 +1087,14 @@ void main() { tester.getRect(find.byKey(floatingActionButton)), rectMoreOrLessEquals(defaultRect.translate( 0.0, - viewPadding - keyboardHeight + fabHeight / 2.0, + viewPadding - keyboardHeight - kFloatingActionButtonMargin, )), ); + // The FAB should be away from the keyboard + expect( + tester.getRect(find.byKey(floatingActionButton)).bottom, + lessThan(scaffoldHeight - keyboardHeight), + ); // With resizeToAvoidBottomInset: false // With keyboard presented, should maintain default position @@ -1136,9 +1144,14 @@ void main() { tester.getRect(find.byKey(floatingActionButton)), rectMoreOrLessEquals(bottomNavigationBarRect.translate( 0.0, - -keyboardHeight + bottomNavHeight, + bottomNavHeight + fabHeight / 2.0 - keyboardHeight - kFloatingActionButtonMargin - fabHeight, )), ); + // The FAB should be away from the keyboard + expect( + tester.getRect(find.byKey(floatingActionButton)).bottom, + lessThan(scaffoldHeight - keyboardHeight), + ); // BottomNavigationBar with resizeToAvoidBottomInset: false // With keyboard presented, should maintain default position @@ -1195,6 +1208,11 @@ void main() { -keyboardHeight + bottomNavHeight, )), ); + // The FAB should be away from the keyboard + expect( + tester.getRect(find.byKey(floatingActionButton)).bottom, + lessThan(scaffoldHeight - keyboardHeight), + ); // BottomNavigationBar + BottomSheet with resizeToAvoidBottomInset: false // With keyboard presented, should maintain default position @@ -1264,6 +1282,11 @@ void main() { tester.getRect(find.byKey(floatingActionButton)), rectMoreOrLessEquals(snackBarRect.translate(0.0, -keyboardHeight)), ); + // The FAB should be away from the keyboard + expect( + tester.getRect(find.byKey(floatingActionButton)).bottom, + lessThan(scaffoldHeight - keyboardHeight), + ); } testWidgets('startDocked', (WidgetTester tester) async {