fujidaiti / smooth_sheets

Sheet widgets with smooth motion and great flexibility.
https://pub.dev/packages/smooth_sheets
MIT License
181 stars 14 forks source link

Popup menu on NavigationSheet overflows screen bounds #167

Open fujidaiti opened 1 month ago

fujidaiti commented 1 month ago

If the navigation sheet is not fullscreen, a popup menu may exceed the screen boundaries, depending on where the popup appears.

https://github.com/fujidaiti/smooth_sheets/assets/68946713/315af548-eef3-4909-81ff-06e598cf29a6

Code ```dart import 'package:flutter/material.dart'; import 'package:smooth_sheets/smooth_sheets.dart'; void main() { runApp(const _MyApp()); } class _MyApp extends StatelessWidget { const _MyApp(); @override Widget build(BuildContext context) { return const MaterialApp( home: Stack( children: [ Scaffold(), _Sheet(), ], ), ); } } final _transitionObserver = NavigationSheetTransitionObserver(); class _Sheet extends StatelessWidget { const _Sheet(); @override Widget build(BuildContext context) { return NavigationSheet( transitionObserver: _transitionObserver, child: Material( color: Colors.blue, child: Navigator( observers: [_transitionObserver], onGenerateRoute: (settings) { return DraggableNavigationSheetRoute( builder: (context) => const _NestedPage(), ); }, ), ), ); } } class _NestedPage extends StatelessWidget { const _NestedPage(); @override Widget build(BuildContext context) { return Container( color: Colors.lightBlue[100], width: double.infinity, height: 500, child: SafeArea( child: Align( alignment: Alignment.bottomCenter, child: Row( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ DropdownMenu( initialSelection: 'Red', label: const Text('Color'), onSelected: (color) {}, dropdownMenuEntries: ['Red', 'Green', 'Blue', 'Grey'].map((color) { return DropdownMenuEntry(value: color, label: color); }).toList(), ), DropdownButton( value: 'Option 1', menuMaxHeight: 150, onChanged: (newValue) {}, items: ['Option 1', 'Option 2', 'Option 3', 'Option 4'] .map((value) { return DropdownMenuItem( value: value, child: Text(value), ); }).toList(), ), ], ), ), ), ); } } ```
fujidaiti commented 1 month ago

If the sheet content is wrapped in a widget with a predefined height (e.g. the Container in the above code), we can workaround this issue by inserting an Overlay widget directly below it (see the following patch). This only works for DropdownMenu and not for DropdownMenuButton, due to the differences in their internal implementations.

class _NestedPage extends StatelessWidget {
  const _NestedPage();

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.lightBlue[100],
      width: double.infinity,
      height: 500,
-       child: SafeArea(
+      child: Overlay(
+        initialEntries: [
+          OverlayEntry(
+            opaque: true,
+            maintainState: true,
+            builder: (_) {
+              return SafeArea(
                child: Align(
                  alignment: Alignment.bottomCenter,
                  child: Row(
                    mainAxisSize: MainAxisSize.max,
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      DropdownMenu(
                        initialSelection: 'Red',
                        label: const Text('Color'),
                        onSelected: (color) {},
                        dropdownMenuEntries:
                            ['Red', 'Green', 'Blue', 'Grey'].map((color) {
                          return DropdownMenuEntry(value: color, label: color);
                        }).toList(),
                      ),
                      DropdownButton(
                        value: 'Option 1',
                        menuMaxHeight: 150,
                        onChanged: (newValue) {},
                        items: ['Option 1', 'Option 2', 'Option 3', 'Option 4']
                            .map((value) {
                          return DropdownMenuItem(
                            value: value,
                            child: Text(value),
                          );
                        }).toList(),
                      ),
                    ],
                  ),
                ),
+              );
+            },
+          )
+        ],
      ),
    );
  }
}

https://github.com/fujidaiti/smooth_sheets/assets/68946713/1e8e18c2-acdb-4625-807d-2dcf98929d6c

fujidaiti commented 1 month ago

An idea to resolve this issue:

  1. Change SheetContentScaffold to have an Overlay widget.
  2. Change SheetContentScaffold to resize itself to fit the content widget. This will also resize the Overlay, ensuring that popup menus appear within the content viewport.