flutter 如何将showModalBottomSheet设置为全高但低于状态栏?

rseugnpd  于 2023-02-25  发布在  Flutter
关注(0)|答案(9)|浏览(222)

我可以使用showModalBottomSheet(...)并设置属性isScrollControlled:true来使bottomSheet达到全高。
然而,底部的表单在状态栏上方,这并不是我所期望的。

是否可以将其设置在状态栏下方?

s2j5cfk0

s2j5cfk01#

作为一个选项,你可以修改底部表单1.创建新文件custom_bottom_sheet.dart 2.复制粘贴所有代码从bottom_sheet类到你的定制类3.修改buildPage()方法,如下所示

@override
  Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
    final BottomSheetThemeData sheetTheme = theme?.bottomSheetTheme ?? Theme.of(context).bottomSheetTheme;
    Widget bottomSheet = SafeArea(
      child: _ModalBottomSheet<T>(
        route: this,
        backgroundColor: backgroundColor ?? sheetTheme?.modalBackgroundColor ?? sheetTheme?.backgroundColor,
        elevation: elevation ?? sheetTheme?.modalElevation ?? sheetTheme?.elevation,
        shape: shape,
        clipBehavior: clipBehavior,
        isScrollControlled: isScrollControlled,
        enableDrag: enableDrag,
      ),
    );
    if (theme != null) bottomSheet = Theme(data: theme, child: bottomSheet);
    return bottomSheet;
  }

1.使用你的类

import 'package:flutter/material.dart';
    import 'custom_bottom_sheet.dart' as bs;

    void main() => runApp(MyApp());

    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            body: SafeArea(child: Page()),
          ),
        );
      }
    }

    class Page extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Center(
          child: RaisedButton(
            child: Text('show'),
            onPressed: () {
              bs.showModalBottomSheet(
                context: context,
                isScrollControlled: true,
                builder: (context) => Container(color: Colors.red),
              );
            },
          ),
        );
      }
    }

此处为修改后的bottom_sheet类https://pastebin.com/5U7fsqCw
我还认为您需要添加属性

barrierColor: Colors.white.withOpacity(0),

防止状态栏变暗

yzxexxkh

yzxexxkh2#

    • 无需创建新类。**只需在构建视图时为填充分配一个变量,并在打开对话框时使用它。
class MyHomeScreenState extends State<MyHomeScreen> {
  double? topPadding;
  
  @override
  Widget build(BuildContext context) {
    topPadding = MediaQuery.of(context).padding.top;
  //...
  }
showModalBottomSheet(
        context: context,
        useRootNavigator: true,
        isScrollControlled: true,
        builder: (context) {
          return Container(
            height: MediaQuery.of(context).size.height -
                topPadding!,
            color: Colors.green,
          );
});

如果你看一下SafeArea的源代码,这就是正在发生的事情。确保你的构建在小部件树的"根"级,因为后代小部件可能没有顶部填充,因为它们不在边缘之下。

jrcvhitl

jrcvhitl3#

自2022年7月20日起,您可以将useSafeArea参数设置为true,以在状态栏you can find details here下显示模态。

showModalBottomSheet<void>(
  useSafeArea: true, // <<<<< use this
  // ....
);

注:现在仅在master通道上可用,以后将在stable通道上可用。

wf82jlnq

wf82jlnq4#

另一个简单的圆边框解决方案

showModalBottomSheet(
    context: context,
    isScrollControlled: true,
    backgroundColor: Colors.transparent,
    builder: (context) => Container(
         height: MediaQuery.of(context).size.height * 0.965,
         decoration: new BoxDecoration(
              color: Colors.white,
              borderRadius: new BorderRadius.only(
                 topLeft: const Radius.circular(16.0),
                 topRight: const Radius.circular(16.0),
              ),
          ),
          child: Center(
              child: Text("Your content goes here"),
    ),
),

);

mzillmmw

mzillmmw5#

我认为这个解决方案最适合现在:(使用FractionallySizedBox

showModalBottomSheet(
  context: context,
  enableDrag: true,
  isScrollControlled: true,
  builder: (context) => FractionallySizedBox(
    heightFactor: 0.9,
    child: Container()
  )
);
6yoyoihd

6yoyoihd6#

您可以使用约束参数并设置所需的高度

showModalBottomSheet(
      context: context,
      isScrollControlled: true,
      shape: const RoundedRectangleBorder(
        borderRadius: BorderRadius.only(
          topLeft: Radius.circular(35),
          topRight: Radius.circular(35),
        ),
      ),
      constraints: BoxConstraints(maxHeight: 
           MediaQuery.of(context).size.height - 50),
      builder: (context) {
         //continue coding..
      }
cvxl0en2

cvxl0en27#

最好和最简单的方法是从状态栏高度中减去设备的总高度。您可以通过MediaQuery.of(context). www.example.com获得statusBarHeightviewPadding.top,通过MediaQuery.of(context).size.height获得整个设备的高度

uwopmtnx

uwopmtnx8#

就像@Roddy R的回答,只是简单一点

showModalBottomSheet(
            context: context,
            isScrollControlled: true,
            shape: RoundedRectangleBorder(borderRadius: BorderRadius.vertical(top: Radius.circular(20))),
            builder: (ctx) => Padding(
              padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top),
              child: YourCustomBottomSheet(),
            ),
          ),

谢谢,罗迪!

jucafojl

jucafojl9#

正如AnasSafi的回答所说,使用useSafeArea: true来解决这个问题。然而,在创建底部表单时,还有许多其他棘手的问题需要解决。下面是我完整的工作底部表单创建器函数,希望能对大家有所帮助。

import 'package:flutter/material.dart';

Future Function() openBottomSheet(BuildContext context, Widget child,
    {String? title}) {
  return () => showModalBottomSheet(
        // Don't let bottom sheet extend past the top of the safe area
        useSafeArea: true,
        context: context,
        // Round the top of the bottom sheet
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(12.0),
        ),
        // Add scrollbar when necessary
        isScrollControlled: true,
        builder: (context) => ScrollableWidget(
          child: Container(
            // Move bottom sheet above on-screen keyboard, if keyboard is open
            padding: EdgeInsets.only(
                bottom: MediaQuery.of(context).viewInsets.bottom),
            child: Stack(
              children: [
                // Add back button at top left of bottom sheet (since it's
                // not obvious that sheet can be swiped down to close it)
                const BackButton(),
                Padding(
                  // Pad the main widget (larger padding on the top to leave
                  // space for the back button)
                  padding: const EdgeInsets.fromLTRB(20.0, 35.0, 20.0, 25.0),
                  child: Column(
                    children: [
                      // Make content full-width, so that main widget is
                      // centered even if it doesn't expand
                      Row(
                        mainAxisSize: MainAxisSize.max,
                        children: const [SizedBox(height: 0)],
                      ),
                      // Add title text to top of bottom sheet, if provided
                      title == null
                          ? Container()
                          : Column(
                              children: [
                                Text(
                                  title,
                                  style: const TextStyle(
                                      fontWeight: FontWeight.bold,
                                      fontSize: 18),
                                  textAlign: TextAlign.center,
                                ),
                                const SizedBox(height: 8),
                              ],
                            ),
                      // Add the main widget
                      child,
                    ],
                  ),
                ),
              ],
            ),
          ),
        ),
      );
}

/// A scrollable widget with a scrollbar that is shown when necessary
class ScrollableWidget extends StatefulWidget {
  const ScrollableWidget({super.key, required this.child});

  final Widget child;

  @override
  State<ScrollableWidget> createState() => _ScrollableWidgetState();
}

class _ScrollableWidgetState extends State<ScrollableWidget> {
  final controller = ScrollController();

  @override
  Widget build(BuildContext context) {
    return Scrollbar(
      thumbVisibility: true,
      thickness: 15,
      radius: const Radius.circular(8),
      controller: controller,
      child: SingleChildScrollView(
        // Same controller must be used on Scrollbar and SingleChildScrollView
        controller: controller,
        child: widget.child,
      ),
    );
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }
}

相关问题