使用 MediaQuery 的响应式元素对齐 - 使用不包含它的上下文调用

Posted

技术标签:

【中文标题】使用 MediaQuery 的响应式元素对齐 - 使用不包含它的上下文调用【英文标题】:Responsive element alignment with MediaQuery - called with a context that does not contain it 【发布时间】:2019-11-23 06:10:19 【问题描述】:

我目前正在设计一个在 dart 中使用 Flutter 的应用程序,并且我一直在使用 Flutter Speed Dial 包尝试使用 marginRight 和 marginBottom 值将其对齐到屏幕的左下角。 marginBottom 很简单,但 marginRight 的问题在于,根据屏幕大小,相同的静态值最终可能会将小部件置于中心,一直向左,甚至离开屏幕,具体取决于屏幕大小。

所以我调用了 mediaQuery 来获取屏幕尺寸并以此为基础小部件,边距略小于它所在屏幕的宽度,以使值响应。

但是,它说 MediaQuery 是在上下文之外调用的,即使我在 SpeedDial 中调用它,它位于 Scaffold 的 FloatingActionButton 下,设置为 MaterialApp 的主页,如下所示:

Widget build(BuildContext context) 
    return MaterialApp(
      home:Scaffold(
        body: Stack(
            children: [...]
          ),
        floatingActionButton:
        SpeedDial(
          marginRight: MediaQuery.of(context).size.width - 20,
          marginBottom: 65,
          [...]
          children: [
            SpeedDialChild(
                [...]
            ),
            SpeedDialChild(
              [...]
            ),
          ],
        ),
      )
    );
  

下面详述的完整错误:

MediaQuery.of() 使用不包含 MediaQuery 的上下文调用。从传递给 MediaQuery.of() 的上下文开始,找不到 MediaQuery 祖先。这可能是因为您没有 WidgetsApp 或 MaterialApp 小部件(这些小部件引入了 MediaQuery),或者如果您使用的上下文来自这些小部件上方的小部件,则可能会发生这种情况。

在此先感谢,这很令人沮丧 :) 非常感谢任何帮助。

【问题讨论】:

您使用了错误的上下文:您应该使用 MaterialApp 的子上下文 - 在您的情况下,您使用的上下文是 MaterialApp 的父级 【参考方案1】:

要解决您的问题,只需将主小部件包装为 homeMaterialApp 小部件,如下所示:

ma​​in.dart

void main() 
  runApp(
    MaterialApp(home: YourWidget()),
  );

并在此处删除 MaterialApp 小部件

yourwidget.dart


class YourWidget extends StatelessWidget 

Widget build(BuildContext context) 
    return Scaffold(
        body: Stack(
            children: [...]
          ),
        floatingActionButton:
        SpeedDial(
          marginRight: MediaQuery.of(context).size.width - 20,
          marginBottom: 65,
          [...]
          children: [
            SpeedDialChild(
                [...]
            ),
            SpeedDialChild(
              [...]
            ),
          ],
        ),
    );
  

【讨论】:

【参考方案2】:

您正在丢失上下文,因为 Speeddial 正在使用它自己的上下文。要获取上下文,您可以使用构建器。

或修改 SpeedDial 以接受 BuildContext。

Widget build(BuildContext context) 
        return MaterialApp(
          home:Scaffold(
            body: Stack(
                children: [...]
              ),
            floatingActionButton: Builder(context) 
           return SpeedDial(
              marginRight: MediaQuery.of(context).size.width - 20,
              marginBottom: 65,
              [...]
              children: [
                SpeedDialChild(
                    [...]
                ),
                SpeedDialChild(
                  [...]
                ),
              ],
            ),
           
          )
        );
      

【讨论】:

以上是关于使用 MediaQuery 的响应式元素对齐 - 使用不包含它的上下文调用的主要内容,如果未能解决你的问题,请参考以下文章

第一章 响应式设计之Media Quer

如何使元素响应式在左侧对齐

垂直对齐内容与浮动元素 + 响应式布局

响应式布局

Flutter中的响应式UI

响应式布局@media screen and ( max-width: 像素值 ) {}