Flutter - 使用 MediaQuery 时防止重建

Ben*_*elj 7 flutter flutter-widget flutter-build

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

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

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

有没有一种替代方案MediaQuery可以在更改时不会导致重建MediaQueryData

Cal*_*ves 4

我也遇到了这个问题,最初认为 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);
  }
}

Run Code Online (Sandbox Code Playgroud)

我一开始就设置了 mediaQueryData 并ResponsiveApp.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

Run Code Online (Sandbox Code Playgroud)

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

但如果你根本不想使用MediaQuery,你可以检查 Window 类dart:ui