4

我想用来MediaQuery根据屏幕高度和宽度构建小部件。#26004中也提到的问题是我只想查询一次大小数据,例如在initState. MediaQuery文件状态

使用 MediaQuery.of 查询当前媒体将导致您的小部件在 MediaQueryData 更改时自动重建(例如,如果用户旋转他们的设备)。

,但这会在我的应用程序中导致不必要的重建。具体来说,如果插入或填充发生变化(例如显示键盘时),它会导致小部件的重建。

是否有替代方案在更改MediaQuery时不会导致重建MediaQueryData

4

3 回答 3

3

我也遇到过这个问题,最初认为 MediaQuery 会导致不必要的重建,但如果您考虑一下,您确实希望小部件重建(在设备旋转、键盘弹出的情况下)以使应用程序具有响应式设计。

你可以这样做:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: Builder(builder: (context) {
        ResponsiveApp.setMq(context);
        return MyHomePage(title: 'Flutter Demo Home Page');
      }),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Flex(
          direction:
              ResponsiveApp().mq.size.width > ResponsiveApp().mq.size.height
                  ? Axis.horizontal
                  : Axis.vertical,
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

class ResponsiveApp {
  static MediaQueryData _mediaQueryData;

  MediaQueryData get mq => _mediaQueryData;

  static void setMq(BuildContext context) {
    _mediaQueryData = MediaQuery.of(context);
  }
}

我在开始时设置了 mediaQueryDataResponsiveApp.setMq(context)并使用了 Builder,因为您只能使用小部件context下方的MediaQuery 之一MaterialApp。设置后,_mediaQueryData您可以随时根据屏幕尺寸构建小部件。

在这段代码中,我只是在设备旋转时更改轴方向,并且小部件需要重建以显示更改的方向。

你也可以有类似的东西:


    if (_mediaQueryData.size.shortestSide < 400)
         //phone layout
    else if(_mediaQueryData.size.shortestSide >= 400 && _mediaQueryData.size.shortestSide < 600)
          //tablet layout
    else
          //web layout

并且在 web 中调整窗口大小将导致小部件多次重建并显示所需的布局。

但是如果你根本不想使用MediaQuery,你可以从dart:ui.

于 2021-01-14T20:33:03.497 回答
1

LayoutBuilder 似乎比每次使用 MediaQuery 来调整视口大小(整个屏幕,或列或其他布局中的剩余空间)都更可取。

如果大小没有改变并且父母不必重新布局,LayoutBuilder 也会努力避免重建它的孩子。

builder函数在以下情况下被调用:

  • 第一次布局小部件。
  • 当父小部件传递不同的布局约束时。
  • 当父小部件更新此小部件时。
  • 当构建器函数订阅的依赖项发生变化时。

如果父级重复传递相同的约束,则不会在布局期间调用构建器函数。

而且您不必再考虑“应用栏的高度”,因为您得到的是剩余空间,而不是屏幕上的总空间。

看看:https ://api.flutter.dev/flutter/widgets/LayoutBuilder-class.html

于 2021-01-14T21:01:12.117 回答
0

就我而言,问题正在发生,因为我使用以下方法手动控制焦点:

onEditingComplete: () {
   FocusScope.of(context).nextFocus();
}

使用的context是父母的context,它正在导致重建。不知道为什么会发生,但是一旦我TextFormField用 a包裹Builder并开始使用它,它就停止了context

注意:我也MediaQuery.of(context).size.height正常使用(没有重建副作用)来设置小部件的父高度

于 2021-05-24T17:50:47.530 回答