响应式设计
使用 MediaQuery 的响应式移动应用程序
简介
让应用响应式对于每个开发者来说都非常重要。使用MediaQuery,您可以让应用适应各种屏幕尺寸。
步骤 - 1
首先,您需要了解如何获取设备的尺寸 - 宽度和高度。使用此打印语句,您可以在终端中获取设备尺寸。
print("Height: ${MediaQuery.of(context).size.height}, Width: ${MediaQuery.of(context).size.width}");
注意:如果您不想使用此方法来查找宽度和高度,您可以使用默认值
double deviceHeight = 690;
double deviceWidth = 360;
步骤 - 2
在lib文件夹中创建一个名为responsive.dart的文件,并将此代码放入您的文件中。
import 'dart:math';
import 'package:flutter/material.dart';
@immutable
class Responsive {
final BuildContext context;
final double deviceHeight;
final double deviceWidth;
const Responsive({
required this.context,
required this.deviceHeight,
required this.deviceWidth,
});
// general size
Size get size => MediaQuery.of(context).size;
// responsive width
double setWidth({required double width}) {
return size.width / (deviceWidth / width);
}
// responsive height
double setHeight({required double height}) {
return size.height / (deviceHeight / height);
}
// responsive font based on Width - it works but not a good solution
// double setFontSize({required double fontSize}) {
// return size.width / (deviceWidth / fontSize);
// }
// don't use it
double setTextScaleFactor({required double textScaleFactor}) {
return MediaQuery.of(context).textScaleFactor / textScaleFactor;
}
// remove padding all
MediaQueryData removeAllPadding() => MediaQuery.of(context).removePadding(
removeLeft: true, removeRight: true, removeBottom: true, removeTop: true);
// set devicePixel ration
double setDevicePixelRatio() => MediaQuery.of(context).devicePixelRatio;
// responsive bottom padding
double setBottomPadding({required double padding}) {
return MediaQuery.of(context).padding.bottom + padding;
}
// responsive Let Padding
double setLeftPadding({required double padding}) {
return MediaQuery.of(context).padding.left + padding;
}
// responsive right padding
double setRightPadding({required double padding}) {
return MediaQuery.of(context).padding.right + padding;
}
// responsive top padding
double setTopPadding({required double padding}) {
return MediaQuery.of(context).padding.top + padding - 20;
}
// scaling the font size based on scale factor - use for scaling fontSize
double setFontSize({required double fontSize}) {
final double sWidth = MediaQuery.of(context).size.width;
final double sHeight = MediaQuery.of(context).size.height;
// if i divide the deviceHeight / sHeight.. than the font will adjust it's self inside box
// but in blow case it is working only the font size.
final scaleH = sHeight / deviceHeight;
final scaleW = sWidth / deviceWidth;
final double scale = max(scaleW, scaleH);
final textScaleFactor = MediaQuery.of(context).textScaleFactor;
return fontSize * scale * textScaleFactor;
}
double setHeightWithoutSafeArea({required double heightWithoutSafeArea}) {
EdgeInsets padding = MediaQuery.of(context).viewPadding;
double height = size.height;
return height -
(deviceHeight / heightWithoutSafeArea) -
padding.top -
padding.bottom;
}
double setWidthWithoutSafeArea({required double heightWithoutSafeArea}) {
EdgeInsets padding = MediaQuery.of(context).viewPadding;
double width = size.width;
return width -
(deviceHeight / heightWithoutSafeArea) -
padding.top -
padding.bottom;
}
double setHeightWithoutStatusBar({required double heightWithoutSafeArea}) {
EdgeInsets padding = MediaQuery.of(context).viewPadding;
double height = size.height;
return height - (deviceHeight / heightWithoutSafeArea) - padding.top;
}
double setHeightWithoutStatusBarToolbar(
{required double heightWithoutSafeArea}) {
EdgeInsets padding = MediaQuery.of(context).viewPadding;
double height = size.height;
return height -
(deviceHeight / heightWithoutSafeArea) -
padding.top -
kToolbarHeight;
}
// for different values such as the using this you can pass even a widget
getResponsiveValue({
dynamic forShortScreen,
dynamic forMediumScreen,
dynamic forLargeScreen,
dynamic forMobLandScapeMode,
dynamic forTabletScreen,
required 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;
}
// getting full width
static double getWidth(BuildContext context) =>
MediaQuery.of(context).size.width;
}
最后一步 - 实现与示例
将此初始化在Scaffold上方的BuildContext下。注意:上面提到了设备的高度和宽度,您可以将其作为变量传递
Responsive rs = Responsive(
context: context,
deviceHeight: deviceHeight,
deviceWidth: deviceWidth,
);
示例
Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
width: rs.setWidth(width: 100),
height: rs.setHeight(height: 200),
alignment: Alignment.center,
color: Colors.black,
child: Text(
"H",
style: TextStyle(
fontSize: rs.setFontSize(fontSize: 20),
color: Colors.white),
),
),
Container(
width: rs.setWidth(width: 100),
height: rs.setHeight(height: 200),
alignment: Alignment.center,
color: Colors.blue,
child: Text(
"ScalerPixel",
style: TextStyle(
fontSize: rs.setFontSize(fontSize: 20),
color: Colors.white),
),
),
Container(
width: 100,
height: 100,
alignment: Alignment.center,
// color will also change
color: rs.getResponsiveValue(
forLargeScreen: Colors.red,
forTabletScreen: Colors.pink,
forMediumScreen: Colors.green,
forShortScreen: Colors.yellow,
forMobLandScapeMode: Colors.blue,
context: context,
),
// text will change according to screen Sizes but it is only necessary in case of web
child: Text(
rs.getResponsiveValue(
context: context,
forLargeScreen: 'LargeScreen',
forShortScreen: 'ShortScreen',
forMediumScreen: 'MediumScreen',
forTabletScreen: 'Tablet',
forMobLandScapeMode: 'LandScape'),
),
),
],
),
方向
Orientation currentOrientation = MediaQuery.of(context).orientation;
if (currentOrientation == Orientation.portrait) {
setState(() {
deviceHeight = MediaQuery.of(context).size.height;
});
} else {
setState(() {
deviceHeight = MediaQuery.of(context).size.width;
});
}
这不是一个完美的解决方案,因为我们需要考虑许多因素,例如LayoutBuilder、AspectRatio、OrientationBuilder和Constraints,并且还需要根据平台进行一些调整。但这是使事情正常工作最基本和最快的方法。希望它有所帮助。