Как сделать приложение флаттера чувствительным в зависимости от размера экрана?

Я сталкиваюсь с трудностями, чтобы заставить его реагировать в соответствии с различными размерами экрана. Как сделать его отзывчивым?

@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: () {})
                ]),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

Ответы

Ответ 1

Используя класс MediaQuery :

MediaQueryData queryData;
queryData = MediaQuery.of(context);

MediaQuery: устанавливает поддерево, в котором медиа-запросы разрешают данные.

MediaQueryData: информация о фрагменте мультимедиа (например, окне).

Чтобы получить соотношение пикселей устройства:

queryData.devicePixelRatio

Чтобы получить ширину и высоту экрана устройства:

queryData.size.width
queryData.size.height

Чтобы получить масштабный коэффициент текста:

queryData.textScaleFactor

Используя класс AspectRatio :

Из документа:

Виджет, который пытается определить размер дочернего элемента в соответствии с определенным соотношением сторон.

Виджет сначала пробует наибольшую ширину, разрешенную ограничениями макета. Высота виджета определяется путем применения заданного соотношения сторон к ширине, выраженного как отношение ширины к высоте.

Например, соотношение сторон ширина: высота 16: 9 будет иметь значение 16,0/9,0. Если максимальная ширина бесконечна, начальная ширина определяется путем применения соотношения сторон к максимальной высоте.

Теперь рассмотрим второй пример, на этот раз с соотношением сторон 2,0 и ограничениями макета, которые требуют ширины от 0,0 до 100,0 и высоты от 0,0 до 100,0. Мы выберем ширину 100,0 (максимально допустимая) и высоту 50,0 (в соответствии с соотношением сторон).

//example
new Center(
 child: new AspectRatio(
  aspectRatio: 100 / 100,
  child: new Container(
    decoration: new BoxDecoration(
      shape: BoxShape.rectangle,
      color: Colors.orange,
      )
    ),
  ),
),

Также вы можете использовать:

Ответ 2

Что я делаю, так это беру ширину и высоту экрана и вычисляю из него сетку 100 * 100, чтобы позиционировать и масштабировать объекты и сохранять их как статические переменные, которые можно использовать повторно. Работает довольно хорошо в большинстве случаев. Как это:

AppConfig.width = MediaQuery.of(context).size.width;
AppConfig.height = MediaQuery.of(context).size.height;
AppConfig.blockSize = AppConfig.width / 100;
AppConfig.blockSizeVertical = AppConfig.height / 100;

Затем я масштабирую все в соответствии с этими значениями, например так:

double elementWidth = AppConfig.blockSize * 10.0;   // 10% of the screen width

или же

double fontSize = AppConfig.blockSize * 1.2;

Иногда безопасная область (метка и т.д.) Убивает макет, поэтому вы также можете рассмотреть это:

AppConfig.safeAreaHorizontal = MediaQuery.of(context).padding.left +
    MediaQuery.of(context).padding.right;

double screenWidthWithoutSafeArea = AppConfig.width - AppConfig.safeAreaHorizontal;

Это отлично сработало на некоторых недавних проектах.

Ответ 3

Place dependency in pubspec.yaml

flutter_responsive_screen: ^1.0.0

Function hp = Screen(MediaQuery.of(context).size).hp;
Function wp = Screen(MediaQuery.of(context).size).wp;

Example :
return Container(height: hp(27),weight: wp(27));

Ответ 4

Проверить класс MediaQuery

Например, чтобы узнать размер текущего носителя (например, окно, содержащее ваше приложение), вы можете прочитать свойство MediaQueryData.size из MediaQueryData возвращенного MediaQuery.of: MediaQuery.of(context).size.

Таким образом, вы можете сделать следующее:

 new Container(
                      height: MediaQuery.of(context).size.height/2,
..            )

Ответ 5

Этот класс поможет, а затем инициализирует класс с помощью метода init.

import 'package:flutter/widgets.dart';

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

  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;
  }
}

тогда в измерении ваших виджетов сделайте это

Widget build(BuildContext context) {
    SizeConfig().init(context);
    return Container(
    height: SizeConfig.safeBlockVertical * 10, //10 for example
    width: SizeConfig.safeBlockHorizontal * 10, //10 for example
    );}

Все кредиты на этот пост автора:https://medium.com/flutter-community/flutter-effectively-scale-ui-according-to-different-screen-sizes-2cb7c115ea0a

Ответ 6

Здесь я довольно сложно подбираю решения других людей (@datayeah & Vithani Ravi), поэтому я решила поделиться своими собственными попытками решить проблему масштабирования с переменной плотностью экрана или заткнуться. Таким образом, я подхожу к этой проблеме с твердой/фиксированной основы: я основываю все свое масштабирование с фиксированным (неизменным) соотношением 2: 1 (высота: ширина). У меня есть вспомогательный класс "McGyver", который выполняет всю тяжелую работу (и полезный поиск кода) в моем приложении. Этот класс "McGyver" содержит только статические методы и члены класса статических констант.

МЕТОД МАСШТАБИРОВАНИЯ СООТНОШЕНИЯ: Я масштабирую и ширину, и усиление; высота независимо от соотношения сторон 2: 1. Я беру ширину и вводите значения высоты и делите каждое на ширину & константы высоты и, наконец, рассчитать коэффициент регулировки, с помощью которого можно масштабировать соответствующую ширину & значения высоты ввода. Фактический код выглядит следующим образом:

import 'dart:math';
import 'package:flutter/material.dart';

class McGyver {

  static const double _fixedWidth = 410;    // Set to an Aspect Ratio of 2:1 (height:width)
  static const double _fixedHeight = 820;   // Set to an Aspect Ratio of 2:1 (height:width) 

  // Useful rounding method (@andyw solution -> https://stackoverflow.com/questions/28419255/how-do-you-round-a-double-in-dart-to-a-given-degree-of-precision-after-the-decim/53500405#53500405)
  static double roundToDecimals(double val, int decimalPlaces){
    double mod = pow(10.0, decimalPlaces);
    return ((val * mod).round().toDouble() / mod);
  }

  // The 'Ratio-Scaled' Widget method (takes any generic widget and returns a "Ratio-Scaled Widget" - "rsWidget")
  static Widget rsWidget(BuildContext ctx, Widget inWidget, double percWidth, double percHeight) {

    // ---------------------------------------------------------------------------------------------- //
    // INFO: Ratio-Scaled "SizedBox" Widget - Scaling based on device height & width at 2:1 ratio.  //
    // ---------------------------------------------------------------------------------------------- //

    final int _decPlaces = 5;
    final double _fixedWidth = McGyver._fixedWidth;
    final double _fixedHeight = McGyver._fixedHeight;

    Size _scrnSize = MediaQuery.of(ctx).size;                // Extracts Device Screen Parameters.
    double _scrnWidth = _scrnSize.width.floorToDouble();     // Extracts Device Screen maximum width.
    double _scrnHeight = _scrnSize.height.floorToDouble();   // Extracts Device Screen maximum height.

    double _rsWidth = 0;
    if (_scrnWidth == _fixedWidth) {   // If input width matches fixedWidth then do normal scaling.
      _rsWidth = McGyver.roundToDecimals((_scrnWidth * (percWidth / 100)), _decPlaces);
    } else {   // If input width !match fixedWidth then do adjustment factor scaling.
      double _scaleRatioWidth = McGyver.roundToDecimals((_scrnWidth / _fixedWidth), _decPlaces);
      double _scalerWidth = ((percWidth + log(percWidth + 1)) * pow(1, _scaleRatioWidth)) / 100;
      _rsWidth = McGyver.roundToDecimals((_scrnWidth * _scalerWidth), _decPlaces);
    }

    double _rsHeight = 0;
    if (_scrnHeight == _fixedHeight) {   // If input height matches fixedHeight then do normal scaling.
      _rsHeight = McGyver.roundToDecimals((_scrnHeight * (percHeight / 100)), _decPlaces);
    } else {   // If input height !match fixedHeight then do adjustment factor scaling.
      double _scaleRatioHeight = McGyver.roundToDecimals((_scrnHeight / _fixedHeight), _decPlaces);
      double _scalerHeight = ((percHeight + log(percHeight + 1)) * pow(1, _scaleRatioHeight)) / 100;
      _rsHeight = McGyver.roundToDecimals((_scrnHeight * _scalerHeight), _decPlaces);
    }

    // Finally, hand over Ratio-Scaled "SizedBox" widget to method call.
    return SizedBox(
      width: _rsWidth,
      height: _rsHeight,
      child: inWidget,
    );
  }

}

.........

Затем вы индивидуально масштабируете свои виджеты (что для моей перфекционистской болезни ВСЕ из моего пользовательского интерфейса) с помощью простого статического вызова метода "rsWidget()" следующим образом:

  // Step 1: Define your widget however you like (this widget will be supplied as the "inWidget" arg to the "rsWidget" method in Step 2)...
  Widget _btnLogin = RaisedButton(color: Colors.blue, elevation: 9.0, 
                                  shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(McGyver.rsDouble(context, ScaleType.width, 2.5))),
                                  child: McGyver.rsText(context, "LOGIN", percFontSize: EzdFonts.button2_5, textColor: Colors.white, fWeight: FontWeight.bold),
                                  onPressed: () { _onTapBtnLogin(_tecUsrId.text, _tecUsrPass.text); }, );

  // Step 2: Scale your widget by calling the static "rsWidget" method...
  McGyver.rsWidget(context, _btnLogin, 34.5, 10.0)   // ...and Bob your uncle!!

Круто то, что метод rsWidget() возвращает виджет !! Таким образом, вы можете назначить масштабированный виджет другой переменной, такой как _rsBtnLogin, для повселокального использования, или вы можете просто использовать полный вызов метода McGyver.rsWidget() на месте внутри вашего метода build() (именно так, как вам нужно располагаться в дереве виджетов), и он будет работать идеально, как и должно быть.

Для тех более проницательных программистов: вы заметили, что я использовал два дополнительных масштабированных метода отношения McGyver.rsText() и McGyver.rsDouble() (не определены в коде выше) в моем RaisedButton() - так что я в основном схожу с ума от этой вещи масштабирования...потому что я требую, чтобы мои приложения были абсолютно безупречными при любом масштабе и плотности экрана !! Я пропорционально масштабирую свои int, double, padding, text (все, что требует согласованности интерфейса на всех устройствах). Я масштабирую свои тексты только на основе ширины, но указываю, какую ось использовать для всего другого масштабирования (как это было сделано с перечислением ScaleType.width, используемым для вызова McGyver.rsDouble() в примере кода выше).

Я знаю, что это безумие - и много работы над главным потоком - но я надеюсь, что кто-нибудь увидит мою попытку здесь и поможет мне найти лучшее (более легкое) решение для моей плотности экрана 1:1 кошмары.

Ответ 7

ознакомьтесь с этой страницей от flutter wiki:

Создание адаптивных приложений

Используйте класс LayoutBuilder: из свойства своего строителя вы получаете BoxConstraints. Изучите свойства ограничения, чтобы решить, что отображать. Например, если ваш maxWidth больше точки останова ширины, верните объект Scaffold со строкой, которая имеет список слева. Если он уже, верните объект Scaffold с ящиком, содержащим этот список. Вы также можете настроить свой дисплей на основе высоты устройства, соотношения сторон или другого свойства. При изменении ограничений (например, пользователь поворачивает телефон или помещает ваше приложение в пользовательский интерфейс плитки в Нуге), функция сборки будет повторно запущена.

Ответ 9

Эту проблему можно решить с помощью MediaQuery.of(context)

Чтобы получить ширину экрана: MediaQuery.of(context).size.width

Чтобы получить высоту экрана: MediaQuery.of(context).size.height

Для получения дополнительной информации о часах MediaQuery Widget,https://www.youtube.com/watch?v=A3WrA4zAaPw

Ответ 10

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

Это хорошо по рекомендации Google, но может быть не идеально.

Ответ 11

создайте имя файла (app_config.dart) в имени папки (respive_screen) в папке lib:

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;
 }
}

затем:

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'),
      ),
    );
    ...
  }

Ответ 12

Width: MediaQuery.of(context).size.width,

Высота: MediaQuery.of(context).size.height,