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

pra*_* Dp 29 dart flutter

我面临着根据各种屏幕尺寸使其响应的困难.如何使其响应?提前致谢

@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: () {})
                ]),
              ),
            ),
          ),
        ],
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

小智 40

此类将帮助然后使用 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;
  }
}
Run Code Online (Sandbox Code Playgroud)

然后在您的小部件维度中执行此操作

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

本文作者的所有功劳:https : //medium.com/flutter-community/flutter-effectively-scale-ui-according-to-different-screen-sizes-2cb7c115ea0a

  • @vontdeux你可以用“late”替换所有“static”,但我不确定这是否是最好的方法 (2认同)

Bla*_*nka 34

使用MediaQuery课程:

MediaQueryData queryData;
queryData = MediaQuery.of(context);
Run Code Online (Sandbox Code Playgroud)

MediaQuery:建立媒体查询解析给定数据的子树.

MediaQueryData:有关媒体的信息(例如,窗口).

要获得设备像素比率:

queryData.devicePixelRatio
Run Code Online (Sandbox Code Playgroud)

要获取设备屏幕的宽度和高度:

queryData.size.width
queryData.size.height
Run Code Online (Sandbox Code Playgroud)

获取文本比例因子:

queryData.textScaleFactor
Run Code Online (Sandbox Code Playgroud)

使用AspectRatio课程:

来自doc:

尝试将子项调整为特定宽高比的小部件.

小部件首先尝试布局约束所允许的最大宽度.通过将给定的宽高比应用于宽度来确定小部件的高度,表示为宽度与高度的比率.

例如,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,
      )
    ),
  ),
),
Run Code Online (Sandbox Code Playgroud)

你也可以使用:

  • 我能够获得设备的宽度和高度,如何通过 `queryData` 设置测试大小、填充、边距。 (5认同)

azi*_*iza 16

检查MediaQuery

例如,要了解当前媒体的大小(例如,包含您的应用程序的窗口),您可以MediaQueryData.sizeMediaQueryData返回的MediaQuery.of: 中读取属性MediaQuery.of(context).size

因此,您可以执行以下操作:

 new Container(
                      height: MediaQuery.of(context).size.height/2,
..            )
Run Code Online (Sandbox Code Playgroud)


urm*_*tel 16

为不同屏幕尺寸制作响应式 UI 的最简单方法是Sizer插件。 Sizer 截图

在任何屏幕尺寸的设备和平板电脑上制作响应式 UI。检查它这个插件?
https://pub.dev/packages/sizer

.h  - for widget height
.w  - for widget width
.sp - for font size
Run Code Online (Sandbox Code Playgroud)

使用.h.w.sp像这样的值之后?

例子:

Container(
  height: 10.0.h,  //10% of screen height
  width: 80.0.w,   //80% of screen width
  child: Text('Sizer', style: TextStyle(fontSize: 12.0.sp)),
);
Run Code Online (Sandbox Code Playgroud)

我用这个插件构建了许多响应式应用程序。

  • 这种方法很棒,我会尝试观察这种行为,如果它令我满意,然后将其投入生产。 (3认同)
  • 我正在使用这个包,但它总是给出 The method '*' was called on null 错误。 (3认同)
  • 总是得到一个示例字段“高度”或“宽度”尚未初始化,有人可以指导我做错了什么吗? (3认同)
  • 非常感谢@urmish patel,这是使应用程序响应的最简单方法。 (2认同)

Gen*_* Bo 9

您可以将宽度或高度的百分比作为比例大小的输入。

fontSize: MediaQuery.of(_ctxt).size.height * 0.065
Run Code Online (Sandbox Code Playgroud)

最后的乘数有一个值,使文本对于活动模拟器看起来很好。

下面是我如何设置它,以便所有缩放的维度都集中在一个地方。通过这种方式,您可以轻松快速地调整它们并使用 Hot Reload 重新运行,而无需在Media.of()整个代码中查找调用。

  1. 创建文件以存储所有映射appScale.dart

    class AppScale {
      BuildContext _ctxt;
    
      AppScale(this._ctxt);
    
      double get labelDim => scaledWidth(.04);
      double get popupMenuButton => scaledHeight(.065); 

      double scaledWidth(double widthScale) {
        return MediaQuery.of(_ctxt).size.width * widthScale;
      }
    
      double scaledHeight(double heightScale) {
        return MediaQuery.of(_ctxt).size.height * heightScale;
      }
    }

Run Code Online (Sandbox Code Playgroud)
  1. 然后参考您需要缩放值的地方

    AppScale _scale = AppScale(context);

    // ... 

    Widget label1 = Text(
      "Some Label",
      style: TextStyle(fontSize: _scale.labelDim),
    );

Run Code Online (Sandbox Code Playgroud)

感谢这篇文章中的回答


dat*_*eah 7

我要做的是获取屏幕的宽度和高度,并从中计算出一个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;
Run Code Online (Sandbox Code Playgroud)

然后我根据这些值缩放所有内容,如下所示:

double elementWidth = AppConfig.blockSize * 10.0;   // 10% of the screen width
Run Code Online (Sandbox Code Playgroud)

要么

double fontSize = AppConfig.blockSize * 1.2;
Run Code Online (Sandbox Code Playgroud)

有时安全区域(凹口等)会杀死布局,因此您也可以考虑以下几点:

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

double screenWidthWithoutSafeArea = AppConfig.width - AppConfig.safeAreaHorizontal;
Run Code Online (Sandbox Code Playgroud)

这在最近的一些项目中效果很好。


小智 7

经过大量研究和测试,我为我目前正在从 Android/iOS 转换为 Flutter 的应用程序开发了一个解决方案。

对于 Android 和 iOS,我使用了应用于基本字体大小的“缩放因子”,呈现相对于屏幕大小的文本大小。

这篇文章很有帮助:https : //medium.com/flutter-community/flutter-effectively-scale-ui-according-to-different-screen-sizes-2cb7c115ea0a

我创建了一个 StatelessWidget 来获取 Material Design 印刷样式的字体大小。使用 MediaQuery 获取设备尺寸,计算缩放因子,然后重置 Material Design 文本大小。Widget 可用于定义自定义 Material Design 主题。

使用的模拟器:

  • Pixel C - 9.94" 平板电脑
  • Pixel 3 - 5.46" 手机
  • iPhone 11 Pro Max - 5.8" 手机

使用标准字体大小

使用缩放字体大小

set_app_theme.dart(SetAppTheme 小部件)

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

class SetAppTheme extends StatelessWidget {

  final Widget child;

  SetAppTheme({this.child});

  @override
  Widget build(BuildContext context) {

    final _divisor = 400.0;

    final MediaQueryData _mediaQueryData = MediaQuery.of(context);

    final _screenWidth = _mediaQueryData.size.width;
    final _factorHorizontal = _screenWidth / _divisor;

    final _screenHeight = _mediaQueryData.size.height;
    final _factorVertical = _screenHeight / _divisor;

    final _textScalingFactor = min(_factorVertical, _factorHorizontal);

    final _safeAreaHorizontal = _mediaQueryData.padding.left + _mediaQueryData.padding.right;
    final _safeFactorHorizontal = (_screenWidth - _safeAreaHorizontal) / _divisor;

    final _safeAreaVertical = _mediaQueryData.padding.top + _mediaQueryData.padding.bottom;
    final _safeFactorVertical = (_screenHeight - _safeAreaVertical) / _divisor;

    final _safeAreaTextScalingFactor = min(_safeFactorHorizontal, _safeFactorHorizontal);

    print('Screen Scaling Values:' + '_screenWidth: $_screenWidth');
    print('Screen Scaling Values:' + '_factorHorizontal: $_factorHorizontal ');

    print('Screen Scaling Values:' + '_screenHeight: $_screenHeight');
    print('Screen Scaling Values:' + '_factorVertical: $_factorVertical ');

    print('_textScalingFactor: $_textScalingFactor ');

    print('Screen Scaling Values:' + '_safeAreaHorizontal: $_safeAreaHorizontal ');
    print('Screen Scaling Values:' + '_safeFactorHorizontal: $_safeFactorHorizontal ');

    print('Screen Scaling Values:' + '_safeAreaVertical: $_safeAreaVertical ');
    print('Screen Scaling Values:' + '_safeFactorVertical: $_safeFactorVertical ');

    print('_safeAreaTextScalingFactor: $_safeAreaTextScalingFactor ');

    print('Default Material Design Text Themes');
    print('display4: ${Theme.of(context).textTheme.display4}');
    print('display3: ${Theme.of(context).textTheme.display3}');
    print('display2: ${Theme.of(context).textTheme.display2}');
    print('display1: ${Theme.of(context).textTheme.display1}');
    print('headline: ${Theme.of(context).textTheme.headline}');
    print('title: ${Theme.of(context).textTheme.title}');
    print('subtitle: ${Theme.of(context).textTheme.subtitle}');
    print('body2: ${Theme.of(context).textTheme.body2}');
    print('body1: ${Theme.of(context).textTheme.body1}');
    print('caption: ${Theme.of(context).textTheme.caption}');
    print('button: ${Theme.of(context).textTheme.button}');

    TextScalingFactors _textScalingFactors = TextScalingFactors(
        display4ScaledSize: (Theme.of(context).textTheme.display4.fontSize * _safeAreaTextScalingFactor),
        display3ScaledSize: (Theme.of(context).textTheme.display3.fontSize * _safeAreaTextScalingFactor),
        display2ScaledSize: (Theme.of(context).textTheme.display2.fontSize * _safeAreaTextScalingFactor),
        display1ScaledSize: (Theme.of(context).textTheme.display1.fontSize * _safeAreaTextScalingFactor),
        headlineScaledSize: (Theme.of(context).textTheme.headline.fontSize * _safeAreaTextScalingFactor),
        titleScaledSize: (Theme.of(context).textTheme.title.fontSize * _safeAreaTextScalingFactor),
        subtitleScaledSize: (Theme.of(context).textTheme.subtitle.fontSize * _safeAreaTextScalingFactor),
        body2ScaledSize: (Theme.of(context).textTheme.body2.fontSize * _safeAreaTextScalingFactor),
        body1ScaledSize: (Theme.of(context).textTheme.body1.fontSize * _safeAreaTextScalingFactor),
        captionScaledSize: (Theme.of(context).textTheme.caption.fontSize * _safeAreaTextScalingFactor),
        buttonScaledSize: (Theme.of(context).textTheme.button.fontSize * _safeAreaTextScalingFactor));

    return Theme(
      child: child,
      data: _buildAppTheme(_textScalingFactors),
    );
  }
}

final ThemeData customTheme = ThemeData(
  primarySwatch: appColorSwatch,
  // fontFamily: x,
);

final MaterialColor appColorSwatch = MaterialColor(0xFF3787AD, appSwatchColors);

Map<int, Color> appSwatchColors =
{
  50  : Color(0xFFE3F5F8),
  100 : Color(0xFFB8E4ED),
  200 : Color(0xFF8DD3E3),
  300 : Color(0xFF6BC1D8),
  400 : Color(0xFF56B4D2),
  500 : Color(0xFF48A8CD),
  600 : Color(0xFF419ABF),
  700 : Color(0xFF3787AD),
  800 : Color(0xFF337799),
  900 : Color(0xFF285877),
};

_buildAppTheme (TextScalingFactors textScalingFactors) {

  return customTheme.copyWith(

    accentColor: appColorSwatch[300],
    buttonTheme: customTheme.buttonTheme.copyWith(buttonColor: Colors.grey[500],),
    cardColor: Colors.white,
    errorColor: Colors.red,
    inputDecorationTheme: InputDecorationTheme(border: OutlineInputBorder(),),
    primaryColor: appColorSwatch[700],
    primaryIconTheme: customTheme.iconTheme.copyWith(color: appColorSwatch),
    scaffoldBackgroundColor: Colors.grey[100],
    textSelectionColor: appColorSwatch[300],
    textTheme: _buildAppTextTheme(customTheme.textTheme, textScalingFactors),
    appBarTheme: customTheme.appBarTheme.copyWith(
        textTheme: _buildAppTextTheme(customTheme.textTheme, textScalingFactors)),

//    accentColorBrightness: ,
//    accentIconTheme: ,
//    accentTextTheme: ,
//    appBarTheme: ,
//    applyElevationOverlayColor: ,
//    backgroundColor: ,
//    bannerTheme: ,
//    bottomAppBarColor: ,
//    bottomAppBarTheme: ,
//    bottomSheetTheme: ,
//    brightness: ,
//    buttonBarTheme: ,
//    buttonColor: ,
//    canvasColor: ,
//    cardTheme: ,
//    chipTheme: ,
//    colorScheme: ,
//    cupertinoOverrideTheme: ,
//    cursorColor: ,
//    dialogBackgroundColor: ,
//    dialogTheme: ,
//    disabledColor: ,
//    dividerColor: ,
//    dividerTheme: ,
//    floatingActionButtonTheme: ,
//    focusColor: ,
//    highlightColor: ,
//    hintColor: ,
//    hoverColor: ,
//    iconTheme: ,
//    indicatorColor: ,
//    materialTapTargetSize: ,
//    pageTransitionsTheme: ,
//    platform: ,
//    popupMenuTheme: ,
//    primaryColorBrightness: ,
//    primaryColorDark: ,
//    primaryColorLight: ,
//    primaryTextTheme: ,
//    secondaryHeaderColor: ,
//    selectedRowColor: ,
//    sliderTheme: ,
//    snackBarTheme: ,
//    splashColor: ,
//    splashFactory: ,
//    tabBarTheme: ,
//    textSelectionHandleColor: ,
//    toggleableActiveColor: ,
//    toggleButtonsTheme: ,
//    tooltipTheme: ,
//    typography: ,
//    unselectedWidgetColor: ,
  );
}

class TextScalingFactors {

  final double display4ScaledSize;
  final double display3ScaledSize;
  final double display2ScaledSize;
  final double display1ScaledSize;
  final double headlineScaledSize;
  final double titleScaledSize;
  final double subtitleScaledSize;
  final double body2ScaledSize;
  final double body1ScaledSize;
  final double captionScaledSize;
  final double buttonScaledSize;

  TextScalingFactors({

    @required this.display4ScaledSize,
    @required this.display3ScaledSize,
    @required this.display2ScaledSize,
    @required this.display1ScaledSize,
    @required this.headlineScaledSize,
    @required this.titleScaledSize,
    @required this.subtitleScaledSize,
    @required this.body2ScaledSize,
    @required this.body1ScaledSize,
    @required this.captionScaledSize,
    @required this.buttonScaledSize
  });
}

TextTheme _buildAppTextTheme(

    TextTheme _customTextTheme,
    TextScalingFactors _scaledText) {

  return _customTextTheme.copyWith(

    display4: _customTextTheme.display4.copyWith(fontSize: _scaledText.display4ScaledSize),
    display3: _customTextTheme.display3.copyWith(fontSize: _scaledText.display3ScaledSize),
    display2: _customTextTheme.display2.copyWith(fontSize: _scaledText.display2ScaledSize),
    display1: _customTextTheme.display1.copyWith(fontSize: _scaledText.display1ScaledSize),
    headline: _customTextTheme.headline.copyWith(fontSize: _scaledText.headlineScaledSize),
    title: _customTextTheme.title.copyWith(fontSize: _scaledText.titleScaledSize),
    subtitle: _customTextTheme.subtitle.copyWith(fontSize: _scaledText.subtitleScaledSize),
    body2: _customTextTheme.body2.copyWith(fontSize: _scaledText.body2ScaledSize),
    body1: _customTextTheme.body1.copyWith(fontSize: _scaledText.body1ScaledSize),
    caption: _customTextTheme.caption.copyWith(fontSize: _scaledText.captionScaledSize),
    button: _customTextTheme.button.copyWith(fontSize: _scaledText.buttonScaledSize),

  ).apply(bodyColor: Colors.black);
}

Run Code Online (Sandbox Code Playgroud)

main.dart(演示应用程序)

import 'package:flutter/material.dart';
import 'package:scaling/set_app_theme.dart';


void main() => runApp(MyApp());


class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {

    return MaterialApp(
      home: SetAppTheme(child: HomePage()),
    );
  }
}


class HomePage extends StatelessWidget {

  final demoText = '0123456789';

  @override
  Widget build(BuildContext context) {

    return SafeArea(
      child: Scaffold(
        appBar: AppBar(
          title: Text('Text Scaling with SetAppTheme',
            style: TextStyle(color: Colors.white),),
        ),
        body: SingleChildScrollView(
          child: Center(
            child: Padding(
              padding: const EdgeInsets.all(8.0),
              child: Column(
                children: <Widget>[
                  Text(
                    demoText,
                    style: TextStyle(
                      fontSize: Theme.of(context).textTheme.display4.fontSize,
                    ),
                  ),
                  Text(
                    demoText,
                    style: TextStyle(
                      fontSize: Theme.of(context).textTheme.display3.fontSize,
                    ),
                  ),
                  Text(
                    demoText,
                    style: TextStyle(
                      fontSize: Theme.of(context).textTheme.display2.fontSize,
                    ),
                  ),
                  Text(
                    demoText,
                    style: TextStyle(
                      fontSize: Theme.of(context).textTheme.display1.fontSize,
                    ),
                  ),
                  Text(
                    demoText,
                    style: TextStyle(
                      fontSize: Theme.of(context).textTheme.headline.fontSize,
                    ),
                  ),
                  Text(
                    demoText,
                    style: TextStyle(
                      fontSize: Theme.of(context).textTheme.title.fontSize,
                    ),
                  ),
                  Text(
                    demoText,
                    style: TextStyle(
                      fontSize: Theme.of(context).textTheme.subtitle.fontSize,
                    ),
                  ),
                  Text(
                    demoText,
                    style: TextStyle(
                      fontSize: Theme.of(context).textTheme.body2.fontSize,
                    ),
                  ),
                  Text(
                    demoText,
                    style: TextStyle(
                      fontSize: Theme.of(context).textTheme.body1.fontSize,
                    ),
                  ),
                  Text(
                    demoText,
                    style: TextStyle(
                      fontSize: Theme.of(context).textTheme.caption.fontSize,
                    ),
                  ),
                  Text(
                    demoText,
                    style: TextStyle(
                      fontSize: Theme.of(context).textTheme.button.fontSize,
                    ),
                  ),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)


小智 5

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));
Run Code Online (Sandbox Code Playgroud)

  • 也许下次您发布“解决方案”时解释一下幕后发生的事情会很棒?不管怎样,我在 GitHub 上查看了这个依赖项。它基本上是一个类(有 16 行代码),它接受输入宽度和高度值,并根据屏幕宽度和高度的百分比对其进行缩放。它本质上与 @datayeah 的解决方案相同 - 唯一的区别是这个解决方案包装得很整齐。与 datayeah 相同的问题也适用于此 - 对于不同屏幕密度设备上的 1:1 缩放来说根本不是一个好的解决方案。此“解决方案”无法解决屏幕密度问题。 (8认同)

Sil*_*Sur 5

我一直在这里敲别人(@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 -> /sf/ask/1989347881/#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's 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,
    );
  }

}
Run Code Online (Sandbox Code Playgroud)

…………

然后,您将通过对“rsWidget()”方法的简单静态调用来单独缩放您的小部件(对于我的完美主义者来说,这就是我的所有 UI),如下所示:

  // 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's your uncle!!
Run Code Online (Sandbox Code Playgroud)

很酷的事情是“rsWidget()”方法返回一个小部件!!因此,您可以将缩放的小部件分配给另一个变量,例如_rsBtnLogin在整个地方使用 - 或者您可以简单McGyver.rsWidget()地在您的build()方法中就地使用完整的方法调用(正是您需要它在小部件树中定位的方式)和它将正常工作。

对于那些高一筹程序员:你会注意到,我用了两个额外的比例缩放的方法McGyver.rsText()McGyver.rsDouble()我的(而不是在上面的代码定义)RaisedButton()-所以我基本上发疯这个比例的东西......因为我要求我的应用程序是在任何比例或屏幕密度下绝对像素完美!!我对整数、双精度、填充、文本(所有需要跨设备的 UI 一致性的所有内容)进行比例缩放。我仅根据宽度缩放文本,但指定用于所有其他缩放的轴(如上面代码示例中ScaleType.width用于McGyver.rsDouble()调用的枚举所做的那样)。

我知道这很疯狂 - 并且在主线程上有很多工作要做 - 但我希望有人能看到我的尝试并帮助我找到一个更好(更轻量级)的解决方案来解决我的屏幕密度 1:1 缩放噩梦。