如何使Flutter应用程序根据不同的屏幕尺寸具有响应性?

178

我在尝试使它适应各种屏幕大小时遇到了困难。如何让它变得响应式?

@override
       Widget build(BuildContext context) {
       return new Container(
       decoration: new BoxDecoration(color: Colors.white),
       child: new Stack(
        children: [
          new Padding(
            padding: const EdgeInsets.only(bottom: 350.0),
            child: new GradientAppBar(" "),
          ),
          new Positioned(
            bottom: 150.0,
            height: 260.0,
            left: 10.0,
            right: 10.0,
            child: new Padding(
              padding: new EdgeInsets.all(10.0),
              child: new Card(
                child: new Column(
                  mainAxisSize: MainAxisSize.min,
                  children: <Widget>[
                    const ListTile(
                      title: const Text(
                        'LOGIN',
                        textAlign: TextAlign.center,
                        style: const TextStyle(
                          fontSize: 16.50,
                          fontFamily: "Helvetica",
                          fontWeight: FontWeight.bold,
                          color: Colors.black87,
                          letterSpacing: 1.00,
                        ),
                      ),
                    ),
                    new ListTile(
                      leading: const Icon(Icons.person),
                      title: new TextField(
                        controller: _user1,
                        decoration: new InputDecoration(
                            labelText: '     Enter a username'),
                      ),
                    ),
                    new ListTile(
                      leading: const Icon(Icons.person_pin),
                      title: new TextField(
                        controller: _pass1,
                        decoration: new InputDecoration(
                            labelText: '     Enter a password'),
                        obscureText: true,
                      ),
                    ),
                  ],
                ),
              ),
            ),
          ),
          new Positioned(
            bottom: 70.0,
            left: 15.0,
            right: 05.0,
            child: new ButtonTheme.bar(
            // make buttons use the appropriate styles for cards
              child: new ButtonBar(
                children: <Widget>[
                  new FlatButton(
                    padding: new EdgeInsets.only(right: 13.0),
                    child: new Text(
                      'REGISTER HERE',
                      style: new TextStyle(
                          color: Colors.black87,
                          fontFamily: "Helvetica",
                          fontSize: 15.00,
                          fontWeight: FontWeight.bold),
                    ),
                    onPressed: () {
                      Navigator.of(context).pushNamed('/facebook');
                    },
                  ),
                  new FlatButton(
                    padding: new EdgeInsets.only(right: 22.0),
                    child: new Text(
                      'FORGOT PASSWORD?',
                      style: new TextStyle(
                          color: Colors.black87,
                          fontFamily: "Helvetica",
                          fontSize: 15.00,
                          fontWeight: FontWeight.bold),
                    ),
                    onPressed: () {
                      Navigator.of(context).pushNamed('/Forgot');
                    },
                  ),
                ],
              ),
            ),
          ),
          new Positioned(
            bottom: 73.0,
            height: 180.0,
            left: 20.0,
            right: 52.0,
            child: new Padding(
              padding: new EdgeInsets.all(0.00),
              child: new ButtonTheme(
                minWidth: 10.0,
                height: 20.0,
                padding: new EdgeInsets.only(right: 37.0),
                child: new ButtonBar(children: <Widget>[
                  new CupertinoButton(
                      borderRadius:
                          const BorderRadius.all(const Radius.circular(36.0)),
                      padding: new EdgeInsets.only(left: 70.0),
                      color: const Color(0xFF426DB7),
                      child: new Text(
                        "     LOGIN                            ",
                        style: new TextStyle(
                            color: Colors.white,
                            fontSize: 12.50,
                            fontFamily: "Handwriting",
                            fontWeight: FontWeight.w500,
                            letterSpacing: 0.00),
                      ),
                      onPressed: () {})
                ]),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

6
我在这里写了一个简单的解决方案 https://jaycoding.tech/tutorials/guides/how-to-create-a-responsive-app-in-flutte-xmafdg ,因为我认为MediaQuery不足以解决问题。你可能想要去看一下。 - NduJay
4
你知道你的链接被以下网站分享了吗:Flutter Docs - Pratik Butani
@PratikButani - 在我看来,可能不应该将它们链接在一起... 这里没有明确的答案。再加上文档中缺乏具体的示例,链接到五年前的文章,以及来自Flutter团队的解决方案 = 可以理解为什么新手会感到困惑。 - undefined
还有@NduJay的链接已经失效。 - undefined
25个回答

3
double height, width;
height = MediaQuery.of(context)

Container(
  height: height * 0.3,
  width: width * 0.2,
  child: PriorityWidget(
    priorityLevel: "High",
    conBackColor: ColorConstants.kMediumRedColor,
    textColor: ColorConstants.kWhiteColor,
    borderColor: selectedPriority == Constants.HIGH_PRIORITY ?
      ColorConstants.kWhiteColor : ColorConstants.kMediumRedColor,
  ),
), 

容器会占用总屏幕高度的3%和屏幕宽度的2%


3

我的解决问题的方法类似于datayeah的方法。我有很多硬编码的宽度和高度数值,应用程序在特定设备上看起来不错。所以我获取了设备的屏幕高度,并创建了一个因子来缩放硬编码的数值。

double heightFactor = MediaQuery.of(context).size.height/708

708是特定设备的高度。


3

使用了ResponsiveBuilder或ScreenTypeLayout

import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:responsive_builder/responsive_builder.dart';

class Sample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        elevation: 0,
        backgroundColor: Colors.black,
      ),
      body: ResponsiveBuilder(
        builder: (context, info) {
          var screenType = info.deviceScreenType;
          String _text;
          switch (screenType){
            case DeviceScreenType.desktop: {
              _text = 'Desktop';
              break;
            }
            case DeviceScreenType.tablet: {
              _text = 'Tablet';
              break;
            }
            case DeviceScreenType.mobile: {
              _text = 'Mobile';
              break;
            }
            case DeviceScreenType.watch: {
              _text = 'Watch';
              break;
            }
            default:
              return null;
          }
          return Center(child: Text(_text, style: TextStyle(fontSize: 32, color: Colors.black),));
        },
      ),
    );
  }
}

// screen type layout
ScreenTypeLayout.builder(
  mobile: MobilePage(),
  tablet: TabletPage(),
  desktop: DesktopPage(),
  watch: Watchpage(),
);

2

针对@user10768752的回答进行澄清:

static double screenWidth  gives you some error, so you have to initialize your data like this below


import 'package:flutter/widgets.dart';

class SizeConfig{
  static MediaQueryData _mediaQueryData = MediaQueryData();
  static double screenWidth = 0;
  static double screenHeight = 0;
  static double blockSizeHorizontal = 0;
  static double blockSizeVertical = 0;
  static double _safeAreaHorizontal = 0;
  static double _safeAreaVertical = 0;
  static double safeBlockHorizontal = 0;
  static double safeBlockVertical = 0;

  void init(BuildContext context){
    _mediaQueryData = MediaQuery.of(context);
    screenWidth = _mediaQueryData.size.width;
    screenHeight = _mediaQueryData.size.height;
    blockSizeHorizontal = screenWidth/100;
    blockSizeVertical = screenHeight/100;
    _safeAreaHorizontal = _mediaQueryData.padding.left +
        _mediaQueryData.padding.right;
    _safeAreaVertical = _mediaQueryData.padding.top +
        _mediaQueryData.padding.bottom;
    safeBlockHorizontal = (screenWidth - _safeAreaHorizontal)/100;
    safeBlockVertical = (screenHeight - _safeAreaVertical)/100;
  }
}

别忘了初始化它。

@override
  Widget build(BuildContext context){
  SizeConfig().init(context);
  return Sizebox(
    width: SizeConfig.safeBlockVertical * 8,
    height: SizeConfig.safeBlockVertical * 8, <-- change value depends on your usecase
);
}

2
这个问题可以使用 MediaQuery.of(context) 解决。
获取屏幕宽度:MediaQuery.of(context).size.width 获取屏幕高度:MediaQuery.of(context).size.height 想要了解更多关于 MediaQuery Widget 的信息,请观看https://www.youtube.com/watch?v=A3WrA4zAaPw

2

您可以使用MediaQuery来获取父容器的尺寸,或使用FractionallySizedBox作为容器。


2
在Flutter 2.0中,在Widget build(BuildContext context)下使用以下代码:

在任何地方使用它或查看图片


2

查看这个 Flutter Wiki 页面:

创建自适应的应用

使用 LayoutBuilder 类:从其 builder 属性中,您可以获得 BoxConstraints 对象。检查约束属性以决定要显示什么。例如,如果您的 maxWidth 大于宽度断点,则返回具有左侧列表的行的 Scaffold 对象。如果较窄,则返回包含该列表的抽屉式 Scaffold 对象。您还可以根据设备的高度、纵横比或其他属性调整显示效果。当约束条件发生更改(例如用户旋转手机或将您的应用程序放入 Nougat 的平铺 UI 中),则 build 函数将重新运行。


2
在lib文件夹中的responsive_screen文件夹内创建名为app_config.dart的文件: "在lib文件夹下的responsive_screen文件夹中,创建名为app_config.dart的文件:"
import 'package:flutter/material.dart';

class AppConfig {
  BuildContext _context;
  double _height;
  double _width;
  double _heightPadding;
  double _widthPadding;

  AppConfig(this._context) {
    MediaQueryData _queryData = MediaQuery.of(_context);
    _height = _queryData.size.height / 100.0;
    _width = _queryData.size.width / 100.0;
    _heightPadding =
    _height - ((_queryData.padding.top + _queryData.padding.bottom) / 100.0);
    _widthPadding =
      _width - (_queryData.padding.left + _queryData.padding.right) / 100.0;
  }

  double rH(double v) {
   return _height * v;
  }

  double rW(double v) {
    return _width * v;
  }

  double rHP(double v) {
    return _heightPadding * v;
  }

 double rWP(double v) {
   return _widthPadding * v;
 }
}

then:

import 'responsive_screen/app_config.dart';
 ...
class RandomWordsState extends State<RandomWords> {
  AppConfig _ac;
  ...
  @override
  Widget build(BuildContext context) {
    _ac = AppConfig(context);
    ...
    return Scaffold(
      body: Container(
        height: _ac.rHP(50),
        width: _ac.rWP(50),
        color: Colors.red,
        child: Text('Test'),
      ),
    );
    ...
  }

1
  padding: EdgeInsets.only(
      left: 4.0,
      right: ResponsiveWidget.isSmallScreen(context) ? 4: 74, //Check for screen type
      top: 10,
      bottom: 40),

这符合Google的建议,但可能并不完美。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接