375 lines
11 KiB
Dart
375 lines
11 KiB
Dart
/// Created by @Haoyi on 2021/7/7
|
|
///
|
|
|
|
part of "design.dart";
|
|
|
|
class _DeviceMetrics {
|
|
final double wScale;
|
|
final double hScale;
|
|
final Size size;
|
|
final TextDirection? direction;
|
|
final Offset offset;
|
|
final SystemAdaptation? adaptation;
|
|
|
|
const _DeviceMetrics(this.wScale, this.hScale, this.size, this.direction,
|
|
{this.offset = Offset.zero, this.adaptation});
|
|
}
|
|
|
|
enum DesignFit { fitWidth, fitHeight, fill }
|
|
|
|
enum _DesignMethod {
|
|
width,
|
|
height,
|
|
average,
|
|
fontSize,
|
|
absoluteFontSize,
|
|
widthScale,
|
|
heightScale,
|
|
combine,
|
|
origin,
|
|
statusBarHeight,
|
|
wrappedInSafeAreaStatusBarHeight,
|
|
navigationBarHeight,
|
|
wrappedInSafeAreaNavigationBarHeight
|
|
}
|
|
|
|
class SystemAdaptation {
|
|
final double? pixelRatio;
|
|
|
|
final double? textScaleFactor;
|
|
|
|
const SystemAdaptation({this.pixelRatio, this.textScaleFactor});
|
|
|
|
static SystemAdaptation? defaultSystemAdaptation;
|
|
|
|
static double? get globalPixelRation => defaultSystemAdaptation?.pixelRatio;
|
|
|
|
static double? get globalTextScaleFactor => defaultSystemAdaptation?.textScaleFactor;
|
|
}
|
|
|
|
class DesignMetrics {
|
|
Size designResolution = Size.zero;
|
|
final List<DesignObject> objects = [];
|
|
final SystemAdaptation? adaptation;
|
|
late Size measuredSize;
|
|
|
|
static Map<num, DesignField> originFields = {
|
|
0: DesignField._origin(0),
|
|
1: DesignField._origin(1),
|
|
2: DesignField._origin(2),
|
|
3: DesignField._origin(3),
|
|
4: DesignField._origin(4),
|
|
5: DesignField._origin(5),
|
|
6: DesignField._origin(6),
|
|
7: DesignField._origin(7),
|
|
8: DesignField._origin(8),
|
|
9: DesignField._origin(9),
|
|
};
|
|
|
|
DesignMetrics.create(this.designResolution, {this.adaptation});
|
|
|
|
DesignMetrics.dynamic({this.adaptation}) : designResolution = Size.zero;
|
|
|
|
DesignField origin(num value) {
|
|
final result = originFields[value];
|
|
if (result != null) {
|
|
return result;
|
|
}
|
|
final field = DesignField._origin(value);
|
|
originFields[value] = field;
|
|
return field;
|
|
}
|
|
|
|
DesignField designWidth(double size) {
|
|
final field = DesignField._width(size);
|
|
_add(field);
|
|
return field;
|
|
}
|
|
|
|
DesignField designHorizontal(double size) {
|
|
final field = DesignField._width(size);
|
|
_add(field);
|
|
return field;
|
|
}
|
|
|
|
DesignField designHeight(double size) {
|
|
final field = DesignField._height(size);
|
|
_add(field);
|
|
return field;
|
|
}
|
|
|
|
DesignField designVertical(double size) {
|
|
final field = DesignField._height(size);
|
|
_add(field);
|
|
return field;
|
|
}
|
|
|
|
DesignField designFontSize(double size) {
|
|
final field = DesignField._average(size);
|
|
_add(field);
|
|
return field;
|
|
}
|
|
|
|
DesignField designAverageSize(double size) {
|
|
final field = DesignField._average(size);
|
|
_add(field);
|
|
return field;
|
|
}
|
|
|
|
DesignField design(DesignField field) {
|
|
_add(field);
|
|
return field;
|
|
}
|
|
|
|
DesignField widthScale(double scale) {
|
|
final field = DesignField._widthScale(scale);
|
|
_add(field);
|
|
return field;
|
|
}
|
|
|
|
DesignField heightScale(double scale) {
|
|
final field = DesignField._heightScale(scale);
|
|
_add(field);
|
|
return field;
|
|
}
|
|
|
|
DesignField relativeRatio(DesignField relative, double ratio) {
|
|
final field = DesignField._relativeRatio(relative, ratio);
|
|
_add(field);
|
|
return field;
|
|
}
|
|
|
|
DesignSize designSize(double width, double height) {
|
|
final size = _DesignExplicitSize(width, height);
|
|
_add(size);
|
|
return size;
|
|
}
|
|
|
|
DesignSize designFieldSize(DesignField width, DesignField height) {
|
|
final size = _DesignFieldSize(width, height);
|
|
_add(size);
|
|
return size;
|
|
}
|
|
|
|
DesignSize widthRatioSize({required double width, required double ratio}) {
|
|
final size = _DesignWidthRatioSize(width, ratio);
|
|
_add(size);
|
|
return size;
|
|
}
|
|
|
|
DesignSize heightRatioSize({required double height, required double ratio}) {
|
|
final size = _DesignHeightRatioSize(height, ratio);
|
|
_add(size);
|
|
return size;
|
|
}
|
|
|
|
DesignRect fromLTRB(double left, double top, double right, double bottom) {
|
|
final rect = _DesignExplicitRect.fromLTRB(left, top, right, bottom);
|
|
_add(rect);
|
|
return rect;
|
|
}
|
|
|
|
DesignRect fromLTWH(double left, double top, double width, double height) {
|
|
return fromLTRB(left, top, left + width, top + height);
|
|
}
|
|
|
|
DesignRect fromCenter(Offset center, double width, double height) {
|
|
return fromLTRB(center.dx - width * 0.5, center.dy - height * 0.5, center.dx + width * 0.5,
|
|
center.dy + height * 0.5);
|
|
}
|
|
|
|
DesignRect fromFieldLTRB(
|
|
DesignField left, DesignField top, DesignField right, DesignField bottom) {
|
|
final rect = _DesignFieldRect.fromLTRB(left, top, right, bottom);
|
|
_add(rect);
|
|
return rect;
|
|
}
|
|
|
|
DesignRect fromFieldLTWH(
|
|
DesignField left, DesignField top, DesignField width, DesignField height) {
|
|
return fromFieldLTRB(left, top, left + width, top + height);
|
|
}
|
|
|
|
DesignRect fromFieldCenter(
|
|
DesignField centerX, DesignField centerY, DesignField width, DesignField height) {
|
|
return fromFieldLTRB(
|
|
centerX - DesignField._relativeRatio(width, 0.5),
|
|
centerY - DesignField._relativeRatio(height, 0.5),
|
|
centerX + DesignField._relativeRatio(width, 0.5),
|
|
centerY + DesignField._relativeRatio(height, 0.5));
|
|
}
|
|
|
|
DesignOffset fieldOffset(DesignField dx, DesignField dy) {
|
|
final offset = DesignOffset(dx, dy);
|
|
_add(offset);
|
|
return offset;
|
|
}
|
|
|
|
DesignOffset offset(double dx, double dy) {
|
|
return fieldOffset(designHorizontal(dx), designVertical(dy));
|
|
}
|
|
|
|
DesignField statusBarHeight({double defaultHeight = 0, bool wrappedInSafeArea = false}) {
|
|
final field = wrappedInSafeArea
|
|
? DesignField.wrappedInSafeAreaStatusBarHeight(defaultHeight)
|
|
: DesignField.statusBarHeight(defaultHeight: defaultHeight);
|
|
_add(field);
|
|
return field;
|
|
}
|
|
|
|
DesignField fakeStatusBarHeight({double fakeHeight = 0}) {
|
|
final field = DesignField.wrappedInSafeAreaStatusBarHeight(fakeHeight);
|
|
_add(field);
|
|
return field;
|
|
}
|
|
|
|
DesignField navigationBarHeight({double defaultHeight = 0, bool wrappedInSafeArea = false}) {
|
|
final field = wrappedInSafeArea
|
|
? DesignField.wrappedInSafeAreaNavigationBarHeight(defaultHeight)
|
|
: DesignField.navigationBarHeight(defaultHeight: defaultHeight);
|
|
_add(field);
|
|
return field;
|
|
}
|
|
|
|
DesignField combineAdd(DesignField field1, DesignField field2) {
|
|
final field = field1 + field2;
|
|
_add(field);
|
|
return field;
|
|
}
|
|
|
|
void _add(DesignObject object) {
|
|
objects.add(object);
|
|
}
|
|
|
|
MeasuredMetrics measure(Size size) {
|
|
measuredSize = size;
|
|
final deviceMetrics = _DeviceMetrics(
|
|
size.width / designResolution.width, size.height / designResolution.height, size, null,
|
|
adaptation: adaptation);
|
|
for (var field in objects) {
|
|
field.measure(deviceMetrics);
|
|
}
|
|
// print("size:$size designResolution:$designResolution ${deviceMetrics.wScale} ${deviceMetrics.hScale}");
|
|
return MeasuredMetrics(deviceMetrics, designResolution);
|
|
}
|
|
|
|
MeasuredMetrics adaptiveMeasure(Size screenSize,
|
|
{DesignFit fit = DesignFit.fill, double scale = 1.0, double? limitSize, Size? designSize}) {
|
|
Size size;
|
|
designResolution = designSize ?? designResolution;
|
|
switch (fit) {
|
|
case DesignFit.fitWidth:
|
|
final newWidth = min(screenSize.width * scale, limitSize ?? screenSize.width);
|
|
final newHeight = newWidth * (designResolution.height / designResolution.width);
|
|
size = Size(newWidth, newHeight);
|
|
break;
|
|
case DesignFit.fitHeight:
|
|
final newHeight = screenSize.height * scale;
|
|
final newWidth = newHeight * (designResolution.width / designResolution.height);
|
|
size = Size(newWidth, newHeight);
|
|
break;
|
|
default:
|
|
size = screenSize;
|
|
break;
|
|
}
|
|
return measure(size);
|
|
}
|
|
}
|
|
|
|
class MeasuredMetrics {
|
|
final _DeviceMetrics metrics;
|
|
|
|
final Size designResolution;
|
|
|
|
Size get size => metrics.size;
|
|
|
|
double get measuredWidth => size.width;
|
|
|
|
double get measuredHeight => size.height;
|
|
|
|
// 宽高比
|
|
double get aspectRatio => size.width / size.height;
|
|
|
|
double get designAspectRatio => designResolution.width / designResolution.height;
|
|
|
|
double get deviceInverseAspectRatio => 1 / aspectRatio;
|
|
|
|
double get designInverseAspectRatio => 1 / designAspectRatio;
|
|
|
|
double get layoutHeightScaleFactor => designInverseAspectRatio / deviceInverseAspectRatio;
|
|
|
|
double get layoutWidthScaleFactor => deviceInverseAspectRatio / designInverseAspectRatio;
|
|
|
|
MeasuredMetrics(this.metrics, this.designResolution);
|
|
|
|
Size measureSize(double width, double height) {
|
|
return Size(metrics.wScale * width, metrics.hScale * height);
|
|
}
|
|
|
|
Offset measureOffset(double x, double y) {
|
|
return Offset(metrics.wScale * x, metrics.hScale * y);
|
|
}
|
|
|
|
double measureWidth(double width, {bool consistent = false}) {
|
|
// 宽度暂不支持这个参数
|
|
return metrics.wScale * width;
|
|
}
|
|
|
|
double measureHeight(double height, {bool consistent = false}) {
|
|
return metrics.hScale * height * (consistent ? layoutHeightScaleFactor : 1.0);
|
|
}
|
|
|
|
double measureVertical(double vertical, {bool consistent = false}) {
|
|
return metrics.hScale * vertical * (consistent ? layoutHeightScaleFactor : 1.0);
|
|
}
|
|
|
|
double measureHorizontal(double horizontal, {bool consistent = false}) {
|
|
// 宽度暂不支持这个参数
|
|
return metrics.wScale * horizontal;
|
|
}
|
|
|
|
double measureFontSize(double fontSize) {
|
|
return DesignField._calculate(_DesignMethod.fontSize, metrics, fontSize);
|
|
}
|
|
|
|
double measureAbsoluteFontSize(double fontSize, {bool consistent = false}) {
|
|
if (consistent) {
|
|
return fontSize *
|
|
metrics.hScale /
|
|
(metrics.adaptation?.textScaleFactor ?? Get.textScaleFactor);
|
|
}
|
|
return DesignField._calculate(_DesignMethod.absoluteFontSize, metrics, fontSize);
|
|
}
|
|
|
|
double statusBarHeight(double ifAbsent) {
|
|
return DesignField._calculate(_DesignMethod.statusBarHeight, metrics, ifAbsent);
|
|
}
|
|
|
|
double wrappedInSafeAreaStatusBarHeight(double ifAbsent) {
|
|
return DesignField._calculate(
|
|
_DesignMethod.wrappedInSafeAreaStatusBarHeight, metrics, ifAbsent);
|
|
}
|
|
|
|
double navigationBarHeight(double navigationBarHeight) {
|
|
return DesignField._calculate(_DesignMethod.navigationBarHeight, metrics, navigationBarHeight);
|
|
}
|
|
|
|
double relativeWidthRatio(double width, double ratio) {
|
|
return metrics.wScale * width * ratio;
|
|
}
|
|
|
|
double relativeHeightRatio(double height, double ratio) {
|
|
return metrics.hScale * height * ratio;
|
|
}
|
|
|
|
Rect fromLTWH(double left, double top, double width, double height) {
|
|
return Rect.fromLTWH(left * metrics.wScale, top * metrics.hScale, width * metrics.wScale,
|
|
height * metrics.hScale);
|
|
}
|
|
|
|
Rect fromLTRB(double left, double top, double right, double bottom) {
|
|
return Rect.fromLTRB(left * metrics.wScale, top * metrics.hScale, right * metrics.wScale,
|
|
bottom * metrics.hScale);
|
|
}
|
|
}
|