如何使颤动应用程序响应根据不同的屏幕大小?

根据不同的屏幕尺寸,我面临着让它响应的困难。如何让它响应?

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

检查 MediaQuery

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

所以你可以这样做:

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

看看这个来自 flutter wiki 的页面:

创建响应式应用程序

使用 LayoutBuilder 类: 从其生成器属性获取 检查约束的属性以决定执行哪些操作 例如,如果您的 maxWidth 大于宽度 属性上有列表的行返回一个脚手架对象 如果它比较窄,返回一个带抽屉的脚手架对象 包含该列表。您还可以基于 设备的高度、长宽比或其他属性。当 约束条件改变(例如,用户旋转手机,或把你的应用程序 在 Nougat 的平铺用户界面中) ,构建函数将重新运行。

使用 MediaQuery类:

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

MediaQuery : 建立一个子树,解析媒体查询 给定的数据。

MediaQueryData : 关于一段媒体的信息(例如,a 窗户)。

获取设备像素比率:

queryData.devicePixelRatio

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

queryData.size.width
queryData.size.height

获取文本比例因子:

queryData.textScaleFactor

使用 AspectRatio类:

来自文档:

一个小部件,它尝试根据特定的长宽比来调整子级的大小。

小部件首先尝试布局允许的最大宽度 属性确定小部件的高度 给定长宽比,表示为宽宽比 身高。

例如,16:9的宽高高高宽比值将为 16.0/9.0.如果最大宽度为无限大,则通过将纵横比应用于最大高度来确定初始宽度。

现在考虑第二个示例,这次的高宽比为2.0 以及布局约束,这些约束要求宽度在0.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,
)
),
),
),

你也可以使用 :

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

我要做的就是取出屏幕的宽度和高度然后计算出一个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;

这在最近的一些项目中非常有效。

宽度: MediaQuery.of(context).size.width,

身高: MediaQuery.of(context).size.height,

在 lib 文件夹的文件夹名(response _ 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;
}
}

然后:

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

在这里,我已经对其他人(@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'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,
);
}


}

... ... ...

然后通过对“ rsWidget ()”方法的简单静态调用,你可以单独调整你的 widget (对于我的完美主义者来说,它就是我所有的 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!!

最酷的事情是“ rsWidget ()”方法返回一个小部件! !因此,你可以将缩放的小部件分配给另一个变量,比如 _rsBtnLogin,以便在任何地方都可以使用——或者你可以简单地在 build()方法中就地使用完整的 McGyver.rsWidget()方法调用(确切地说,你需要它在小部件树中的位置) ,它将完美地工作,因为它应该。

对于那些更精明的程序员: 你可能已经注意到我在我的 RaisedButton()中使用了两个额外的比例缩放方法 McGyver.rsText()McGyver.rsDouble()(在上面的代码中没有定义)——所以我基本上对这个缩放的东西疯狂了... 因为我要求我的应用程序在任何比例或屏幕密度下都是绝对完美的像素!我比例缩放我的整型、双精度、填充、文本(所有需要跨设备 UI 一致性的东西)。我只根据宽度缩放文本,但是指定其他缩放使用哪个轴(就像上面代码示例中用于 McGyver.rsDouble()调用的 ScaleType.width枚举所做的那样)。

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

这个问题可以用 (上下文)来解决

要获得屏幕宽度: MediaQuery.of(context).size.width

要获得屏幕高度: MediaQuery.of(context).size.height

有关 MediaQuery Widget watch 的更多信息, Https://www.youtube.com/watch?v=a3wra4zaapw

该类将提供帮助,然后使用 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

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

按照谷歌的建议,这是可以接受的,但可能并不完美。

您可以使用 MediaQuery 作为父维度或 FractionallySizedBox 作为容器。

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

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

其中708是特定设备的高度。

经过大量的研究和测试,我已经开发了一个应用程序的解决方案,我目前正在从安卓/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 文本大小。这个小部件可以用来定义一个自定义的材质设计主题。

使用的仿真器:

  • 像素 C-9.94“平板电脑
  • 像素3-5.46”手机
  • IPhone 11 Pro Max-5.8“ Phone

使用标准字体大小

带缩放字体大小

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


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

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

fontSize: MediaQuery.of(_ctxt).size.height * 0.065

其中最后的乘法器有一个值,使得 Text 对于活动模拟器看起来很好。

下面是我如何设置它,使所有的比例尺寸集中在一个地方。通过这种方式,您可以轻松地调整它们,并使用 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;
}
}


  1. 然后在需要缩放值的地方引用它

AppScale _scale = AppScale(context);


// ...


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


感谢本文的回答

使用响应生成器或 屏幕类型布局

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(),
);

您可以使用 Response _ helper软件包来使您的应用程序响应。

这是一个非常简单的方法,使您的应用程序响应。只要看一下 示例页,然后你就会知道如何使用它。

另一种方法:)更容易扑网

class SampleView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Container(
width: 200,
height: 200,
color: Responsive().getResponsiveValue(
forLargeScreen: Colors.red,
forTabletScreen : Colors.pink,
forMediumScreen: Colors.green,
forShortScreen: Colors.yellow,
forMobLandScapeMode: Colors.blue,
context: context),
// You dodn't need to provide the values for every
//parameter(except shortScreen & context)
// but default its provide the value as ShortScreen for Larger and
//mediumScreen
),
);
}
}

效用:

import 'package:flutter/widgets.dart';


class Responsive {
// function reponsible for providing value according to screensize
getResponsiveValue(
{dynamic forShortScreen,
dynamic forMediumScreen,
dynamic forLargeScreen,
dynamic forMobLandScapeMode,
dynamic forTabletScreen,
BuildContext context}) {


if (isLargeScreen(context)) {


return forLargeScreen ?? forShortScreen;
} else if (isMediumScreen(context)) {


return forMediumScreen ?? forShortScreen;
}
else if (isTabletScreen(context)) {


return forTabletScreen ??  forMediumScreen ?? forShortScreen;


}
else if (isSmallScreen(context) && isLandScapeMode(context)) {


return forMobLandScapeMode ?? forShortScreen;


} else {
return forShortScreen;
}
}


isLandScapeMode(BuildContext context) {
if (MediaQuery.of(context).orientation == Orientation.landscape) {
return true;
} else {
return false;
}
}


static bool isLargeScreen(BuildContext context) {
return getWidth(context) > 1200;
}


static bool isSmallScreen(BuildContext context) {
return getWidth(context) < 800;
}




static bool isMediumScreen(BuildContext context) {
return getWidth(context) > 800 && getWidth(context) < 1200;
}
static bool isTabletScreen(BuildContext context) {
return getWidth(context) > 450 && getWidth(context) < 800;
}


static double getWidth(BuildContext context) {
return MediaQuery.of(context).size.width;
}

}

为不同屏幕大小制作响应式用户界面的最简单方法是 西泽插件。 Sizer Screenshot

在任何屏幕大小的设备上都可以制作响应式用户界面,请检查此插件
Https://pub.dev/packages/sizer

.h  - for widget height
.w  - for widget width
.sp - for font size

在这样的值之后使用 .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)),
);

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

double height, width;
height = MediaQuery.of(context).size.height;
width = MediaQuery.of(context).size.width;
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% 的屏幕宽度的高度

在 flutter 2.0中,使用 Widget build (BuildContext 上下文)下的代码

use it where you want in it or see pictures

不需要为多种屏幕尺寸编写 UI,你可以使用这个包 下一个只编写一次 UI。它有一些很酷的扩展,可以快速进行 UI 开发,文档也很好。

他们甚至有一个例子是用这个包 n 制作的 链接: < a href = “ https://one-page-with-flutter.netlify.app/”rel = “ nofollow norefrer”> https://one-page-with-flutter.netlify.app/

为了澄清@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
);
}