Mounir Bouaiche
Committed by GitHub

Major updates & fixes (#491)

* Clean codes & add features & fix bugs

Features/Bugs:
- Feature: You can select what classes needs to be rebuilt instead of rebuilding everything, if you have widget A, either addi SU mixin or add 'A' to list ScreenUtilInit.responsiveWidgets
- Feature: Using ScreenUtilInit.builder is optional (use it only when using library in theme)
- Bug: Second call to ScreenUtil.init ignores any existing values and uses the default values when not provided, use ScreenUtil.configure instead
- Bug: ScreenUtil.ensureScreenSize raises an overflow error

* Update version

* Add List of flutter widgets

* Update logic if allowing widget to being rebuilt

* Little code solidity

* Add scale factors: diagonal & diameter

* Add option for how font size should be scaled

* Update support to Dart >= 2.17.0

* Add fontSizeResolver to init + helpers

* Add ensureScreenSize to ScreenUtilInit constructor

* Fix ensureScreenSize on web

* Update Runner.rc

* Add some methods to extensions

* Update widget_test

* Remove extra deps

* Clean code

* Add ensureScreenSizeAndInit + make init sync

* Update README.md

* Update CHANGELOG.md

* Update version to 5.9.0

* Rename version

* Adding tests

* Changing version in CHANGELOG.md

---------

Co-authored-by: Mounir Bouaiche <mounir-b@dba.ma>
@@ -139,3 +139,6 @@ doc @@ -139,3 +139,6 @@ doc
139 .lock 139 .lock
140 coverage* 140 coverage*
141 *.lock 141 *.lock
  142 +
  143 +# Don't commit .fvm directory containing machine-specific symlink to sdk & flutter version
  144 +**/.fvm
  1 +# 5.9.0-beta
  2 +- ScreenUtilInit won't rebuild the whole widget tree
  3 +- Add `fontSizeResolver` to specify how font size should be scaled
  4 +- Add `diameter` & `diagonal` factors
  5 +- `useInheritedMediaQuery` has not effect, and will be removed in next release
  6 +- Fix `ensureScreenSize` in web platform
  7 +
1 # 5.8.4 8 # 5.8.4
2 - bug fix 9 - bug fix
3 - change useInheritedMediaQuery default value to false 10 - change useInheritedMediaQuery default value to false
@@ -38,28 +38,36 @@ dependencies: @@ -38,28 +38,36 @@ dependencies:
38 import 'package:flutter_screenutil/flutter_screenutil.dart'; 38 import 'package:flutter_screenutil/flutter_screenutil.dart';
39 ``` 39 ```
40 40
41 -### Property 41 +### Properties
42 42
43 | Property | Type | Default Value | Description | 43 | Property | Type | Default Value | Description |
44 -| --------------- |--------------|---------------|-----------------------------------------------------------------------------------------------------------------------------------------------|  
45 -| deviceSize | Size | null | The size of the physical device | 44 +| ---------------- |--------------|---------------|-----------------------------------------------------------------------------------------------------------------------------------------------|
46 | designSize | Size | Size(360,690) | The size of the device screen in the design draft, in dp | 45 | designSize | Size | Size(360,690) | The size of the device screen in the design draft, in dp |
47 | builder | Function | null | Return widget that uses the library in a property (ex: MaterialApp's theme) | 46 | builder | Function | null | Return widget that uses the library in a property (ex: MaterialApp's theme) |
48 | child | Widget | null | A part of builder that its dependencies/properties don't use the library | 47 | child | Widget | null | A part of builder that its dependencies/properties don't use the library |
49 -| rebuildFactor | Function | *default* | Returns whether to rebuild or not when screen metrics changes. |  
50 -| orientation | Orientation | portrait | screen orientation | 48 +| rebuildFactor | Function | *default* | Function that take old and new screen metrics and returns whether to rebuild or not when changes. |
51 | splitScreenMode | bool | false | support for split screen | 49 | splitScreenMode | bool | false | support for split screen |
52 | minTextAdapt | bool | false | Whether to adapt the text according to the minimum of width and height | 50 | minTextAdapt | bool | false | Whether to adapt the text according to the minimum of width and height |
53 | context | BuildContext | null | Get physical device data if not provided, by MediaQuery.of(context) | 51 | context | BuildContext | null | Get physical device data if not provided, by MediaQuery.of(context) |
54 -| useInheritedMediaQuery | bool | false | Recommended use `false` avoid rebuild very frequently <br/><br/> ~~Set this to true for Flutter 3.10 to avoid keyboard overlay on TextField~~ | 52 +| fontSizeResolver | Function | *default* | Function that specify how font size should be adapted. Default is that font size scale with width of screen. |
  53 +| reponsiveWidgets | Iterable<String> | null | List/Set of widget names that should be included in rebuilding tree. (See [How flutter_screenutil marks a widget needs build](#rebuild-list)) |
55 54
56 **Note : You must either provide builder, child or both.** 55 **Note : You must either provide builder, child or both.**
57 56
  57 +### Rebuild list
  58 +Starting from version 5.9.0, ScreenUtilInit won't rebuild the whole widget tree, instead it will mark widget needs build only if:
  59 +- Widget is not a flutter widget (widgets are available in [Flutter Docs](https://docs.flutter.dev/reference/widgets))
  60 +- Widget does not start with underscore (`_`)
  61 +- Widget does not declare `SU` mixin
  62 +- `reponsiveWidgets` does not contains widget name
  63 +
  64 +If you have a widget that uses the library and doesn't meet these options you can either add `SU` mixin or add widget name in responsiveWidgets list.
  65 +
58 ### Initialize and set the fit size and font size to scale according to the system's "font size" accessibility option 66 ### Initialize and set the fit size and font size to scale according to the system's "font size" accessibility option
59 67
60 Please set the size of the design draft before use, the width and height of the design draft. 68 Please set the size of the design draft before use, the width and height of the design draft.
61 69
62 -#### The first way (You must use it once in your app) 70 +#### The first way (You should use it once in your app)
63 71
64 ```dart 72 ```dart
65 void main() => runApp(MyApp()); 73 void main() => runApp(MyApp());
@@ -74,7 +82,8 @@ class MyApp extends StatelessWidget { @@ -74,7 +82,8 @@ class MyApp extends StatelessWidget {
74 designSize: const Size(360, 690), 82 designSize: const Size(360, 690),
75 minTextAdapt: true, 83 minTextAdapt: true,
76 splitScreenMode: true, 84 splitScreenMode: true,
77 - builder: (context , child) { 85 + // Use builder only if you need to use library outside ScreenUtilInit context
  86 + builder: (_ , child) {
78 return MaterialApp( 87 return MaterialApp(
79 debugShowCheckedModeBanner: false, 88 debugShowCheckedModeBanner: false,
80 title: 'First Method', 89 title: 'First Method',
@@ -169,6 +178,8 @@ class _HomePageState extends State<HomePage> { @@ -169,6 +178,8 @@ class _HomePageState extends State<HomePage> {
169 } 178 }
170 ``` 179 ```
171 180
  181 +**Note: calling ScreenUtil.init second time, any non-provided parameter will not be replaced with default value. Use ScreenUtil.configure instead**
  182 +
172 ### API 183 ### API
173 184
174 #### Pass the dp size of the design draft 185 #### Pass the dp size of the design draft
  1 +/////////////////////////////////////////////////////////////////////////
  2 +/// Generated via plugin: flutter_screenutil_generator - Do Not Touch ///
  3 +/////////////////////////////////////////////////////////////////////////
  4 +
  5 +part of 'responsive_widgets.su.dart';
  6 +
  7 +const _responsiveWidgets = {
  8 + 'MyThemedApp',
  9 + 'MyApp',
  10 + 'HomePageScaffold',
  11 +};
  1 +part 'responsive_widgets.g.dart';
  2 +
  3 +get responsiveWidgets => _responsiveWidgets;
  1 +import 'package:example/responsive_widgets.su.dart';
1 import 'package:example/src/home.dart'; 2 import 'package:example/src/home.dart';
2 import 'package:flutter/material.dart'; 3 import 'package:flutter/material.dart';
3 import 'package:flutter_screenutil/flutter_screenutil.dart'; 4 import 'package:flutter_screenutil/flutter_screenutil.dart';
@@ -9,9 +10,9 @@ class MyApp extends StatelessWidget { @@ -9,9 +10,9 @@ class MyApp extends StatelessWidget {
9 Widget build(BuildContext context) { 10 Widget build(BuildContext context) {
10 // In first method you only need to wrap [MaterialApp] with [ScreenUtilInit] and that's it 11 // In first method you only need to wrap [MaterialApp] with [ScreenUtilInit] and that's it
11 return ScreenUtilInit( 12 return ScreenUtilInit(
12 - useInheritedMediaQuery: false,  
13 - builder: (_, child) {  
14 - return MaterialApp( 13 + responsiveWidgets: responsiveWidgets,
  14 + ensureScreenSize: true,
  15 + child: MaterialApp(
15 debugShowCheckedModeBanner: false, 16 debugShowCheckedModeBanner: false,
16 title: 'First Method', 17 title: 'First Method',
17 // You can use the library anywhere in the app even in theme 18 // You can use the library anywhere in the app even in theme
@@ -21,10 +22,8 @@ class MyApp extends StatelessWidget { @@ -21,10 +22,8 @@ class MyApp extends StatelessWidget {
21 .black 22 .black
22 .apply(fontSizeFactor: 1), 23 .apply(fontSizeFactor: 1),
23 ), 24 ),
24 - home: child,  
25 - );  
26 - },  
27 - child: const HomePage(title: 'First Method'), 25 + home: const HomePage(title: 'First Method'),
  26 + ),
28 ); 27 );
29 } 28 }
30 } 29 }
@@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; @@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
2 import 'package:flutter/services.dart'; 2 import 'package:flutter/services.dart';
3 import 'package:flutter_screenutil/flutter_screenutil.dart'; 3 import 'package:flutter_screenutil/flutter_screenutil.dart';
4 4
5 -class HomePageScaffold extends StatelessWidget { 5 +class HomePageScaffold extends StatelessWidget with SU {
6 const HomePageScaffold({Key? key, this.title = ''}) : super(key: key); 6 const HomePageScaffold({Key? key, this.title = ''}) : super(key: key);
7 7
8 void printScreenInformation(BuildContext context) { 8 void printScreenInformation(BuildContext context) {
@@ -43,7 +43,7 @@ void main() { @@ -43,7 +43,7 @@ void main() {
43 data: currentData, 43 data: currentData,
44 child: ScreenUtilInit( 44 child: ScreenUtilInit(
45 designSize: designSize, 45 designSize: designSize,
46 - builder: (context, child) => MaterialApp( 46 + child: MaterialApp(
47 home: Material( 47 home: Material(
48 child: TextButton( 48 child: TextButton(
49 key: _key, 49 key: _key,
@@ -68,6 +68,9 @@ void main() { @@ -68,6 +68,9 @@ void main() {
68 // Tests with initial screen size 68 // Tests with initial screen size
69 testSize(initialSize); 69 testSize(initialSize);
70 70
  71 + // Wait for FutureBuilder to be resolved
  72 + await tester.pumpAndSettle();
  73 +
71 // Click On button to simulate changing screen size 74 // Click On button to simulate changing screen size
72 await tap(); 75 await tap();
73 // Tests with bigger screen size 76 // Tests with bigger screen size
@@ -60,14 +60,14 @@ IDI_APP_ICON ICON "resources\\app_icon.ico" @@ -60,14 +60,14 @@ IDI_APP_ICON ICON "resources\\app_icon.ico"
60 // Version 60 // Version
61 // 61 //
62 62
63 -#ifdef FLUTTER_BUILD_NUMBER  
64 -#define VERSION_AS_NUMBER FLUTTER_BUILD_NUMBER 63 +#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD)
  64 +#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD
65 #else 65 #else
66 -#define VERSION_AS_NUMBER 1,0,0 66 +#define VERSION_AS_NUMBER 1,0,0,0
67 #endif 67 #endif
68 68
69 -#ifdef FLUTTER_BUILD_NAME  
70 -#define VERSION_AS_STRING #FLUTTER_BUILD_NAME 69 +#if defined(FLUTTER_VERSION)
  70 +#define VERSION_AS_STRING FLUTTER_VERSION
71 #else 71 #else
72 #define VERSION_AS_STRING "1.0.0" 72 #define VERSION_AS_STRING "1.0.0"
73 #endif 73 #endif
@@ -10,3 +10,4 @@ export 'src/r_sizedbox.dart'; @@ -10,3 +10,4 @@ export 'src/r_sizedbox.dart';
10 export 'src/screen_util.dart'; 10 export 'src/screen_util.dart';
11 export 'src/screenutil_init.dart'; 11 export 'src/screenutil_init.dart';
12 export 'src/size_extension.dart'; 12 export 'src/size_extension.dart';
  13 +export 'src/screenutil_mixin.dart';
  1 +import 'dart:collection';
  2 +
  3 +final flutterWidgets = HashSet<String>.from({
  4 + 'AbsorbPointer',
  5 + 'Accumulator',
  6 + 'Action',
  7 + 'ActionDispatcher',
  8 + 'ActionListener',
  9 + 'Actions',
  10 + 'ActivateAction',
  11 + 'ActivateIntent',
  12 + 'Align',
  13 + 'Alignment',
  14 + 'AlignmentDirectional',
  15 + 'AlignmentGeometry',
  16 + 'AlignmentGeometryTween',
  17 + 'AlignmentTween',
  18 + 'AlignTransition',
  19 + 'AlwaysScrollableScrollPhysics',
  20 + 'AlwaysStoppedAnimation',
  21 + 'AndroidView',
  22 + 'AndroidViewSurface',
  23 + 'Animatable',
  24 + 'AnimatedAlign',
  25 + 'AnimatedBuilder',
  26 + 'AnimatedContainer',
  27 + 'AnimatedCrossFade',
  28 + 'AnimatedDefaultTextStyle',
  29 + 'AnimatedFractionallySizedBox',
  30 + 'AnimatedGrid',
  31 + 'AnimatedGridState',
  32 + 'AnimatedList',
  33 + 'AnimatedListState',
  34 + 'AnimatedModalBarrier',
  35 + 'AnimatedOpacity',
  36 + 'AnimatedPadding',
  37 + 'AnimatedPhysicalModel',
  38 + 'AnimatedPositioned',
  39 + 'AnimatedPositionedDirectional',
  40 + 'AnimatedRotation',
  41 + 'AnimatedScale',
  42 + 'AnimatedSize',
  43 + 'AnimatedSlide',
  44 + 'AnimatedSwitcher',
  45 + 'AnimatedWidget',
  46 + 'AnimatedWidgetBaseState',
  47 + 'Animation',
  48 + 'AnimationController',
  49 + 'AnimationMax',
  50 + 'AnimationMean',
  51 + 'AnimationMin',
  52 + 'AnnotatedRegion',
  53 + 'AspectRatio',
  54 + 'AssetBundle',
  55 + 'AssetBundleImageKey',
  56 + 'AssetBundleImageProvider',
  57 + 'AssetImage',
  58 + 'AsyncSnapshot',
  59 + 'AutocompleteHighlightedOption',
  60 + 'AutocompleteNextOptionIntent',
  61 + 'AutocompletePreviousOptionIntent',
  62 + 'AutofillGroup',
  63 + 'AutofillGroupState',
  64 + 'AutofillHints',
  65 + 'AutomaticKeepAlive',
  66 + 'AutomaticNotchedShape',
  67 + 'BackButtonDispatcher',
  68 + 'BackButtonListener',
  69 + 'BackdropFilter',
  70 + 'BallisticScrollActivity',
  71 + 'Banner',
  72 + 'BannerPainter',
  73 + 'Baseline',
  74 + 'BaseTapAndDragGestureRecognizer',
  75 + 'BeveledRectangleBorder',
  76 + 'BlockSemantics',
  77 + 'Border',
  78 + 'BorderDirectional',
  79 + 'BorderRadius',
  80 + 'BorderRadiusDirectional',
  81 + 'BorderRadiusGeometry',
  82 + 'BorderRadiusTween',
  83 + 'BorderSide',
  84 + 'BorderTween',
  85 + 'BottomNavigationBarItem',
  86 + 'BouncingScrollPhysics',
  87 + 'BouncingScrollSimulation',
  88 + 'BoxBorder',
  89 + 'BoxConstraints',
  90 + 'BoxConstraintsTween',
  91 + 'BoxDecoration',
  92 + 'BoxPainter',
  93 + 'BoxScrollView',
  94 + 'BoxShadow',
  95 + 'BuildContext',
  96 + 'Builder',
  97 + 'BuildOwner',
  98 + 'ButtonActivateIntent',
  99 + 'CallbackAction',
  100 + 'CallbackShortcuts',
  101 + 'Canvas',
  102 + 'CapturedThemes',
  103 + 'CatmullRomCurve',
  104 + 'CatmullRomSpline',
  105 + 'Center',
  106 + 'ChangeNotifier',
  107 + 'CharacterActivator',
  108 + 'CharacterRange',
  109 + 'Characters',
  110 + 'CheckedModeBanner',
  111 + 'ChildBackButtonDispatcher',
  112 + 'CircleBorder',
  113 + 'CircularNotchedRectangle',
  114 + 'ClampingScrollPhysics',
  115 + 'ClampingScrollSimulation',
  116 + 'ClipboardStatusNotifier',
  117 + 'ClipContext',
  118 + 'ClipOval',
  119 + 'ClipPath',
  120 + 'ClipRect',
  121 + 'ClipRRect',
  122 + 'Color',
  123 + 'ColoredBox',
  124 + 'ColorFilter',
  125 + 'ColorFiltered',
  126 + 'ColorProperty',
  127 + 'ColorSwatch',
  128 + 'ColorTween',
  129 + 'Column',
  130 + 'ComponentElement',
  131 + 'CompositedTransformFollower',
  132 + 'CompositedTransformTarget',
  133 + 'CompoundAnimation',
  134 + 'ConstantTween',
  135 + 'ConstrainedBox',
  136 + 'ConstrainedLayoutBuilder',
  137 + 'ConstraintsTransformBox',
  138 + 'Container',
  139 + 'ContentInsertionConfiguration',
  140 + 'ContextAction',
  141 + 'ContextMenuButtonItem',
  142 + 'ContextMenuController',
  143 + 'ContinuousRectangleBorder',
  144 + 'CopySelectionTextIntent',
  145 + 'Cubic',
  146 + 'Curve',
  147 + 'Curve2D',
  148 + 'Curve2DSample',
  149 + 'CurvedAnimation',
  150 + 'Curves',
  151 + 'CurveTween',
  152 + 'CustomClipper',
  153 + 'CustomMultiChildLayout',
  154 + 'CustomPaint',
  155 + 'CustomPainter',
  156 + 'CustomPainterSemantics',
  157 + 'CustomScrollView',
  158 + 'CustomSingleChildLayout',
  159 + 'DebugCreator',
  160 + 'DecoratedBox',
  161 + 'DecoratedBoxTransition',
  162 + 'Decoration',
  163 + 'DecorationImage',
  164 + 'DecorationImagePainter',
  165 + 'DecorationTween',
  166 + 'DefaultAssetBundle',
  167 + 'DefaultPlatformMenuDelegate',
  168 + 'DefaultSelectionStyle',
  169 + 'DefaultTextEditingShortcuts',
  170 + 'DefaultTextHeightBehavior',
  171 + 'DefaultTextStyle',
  172 + 'DefaultTextStyleTransition',
  173 + 'DefaultTransitionDelegate',
  174 + 'DefaultWidgetsLocalizations',
  175 + 'DeleteCharacterIntent',
  176 + 'DeleteToLineBreakIntent',
  177 + 'DeleteToNextWordBoundaryIntent',
  178 + 'DesktopTextSelectionToolbarLayoutDelegate',
  179 + 'DevToolsDeepLinkProperty',
  180 + 'DiagnosticsNode',
  181 + 'DirectionalCaretMovementIntent',
  182 + 'DirectionalFocusAction',
  183 + 'DirectionalFocusIntent',
  184 + 'Directionality',
  185 + 'DirectionalTextEditingIntent',
  186 + 'DismissAction',
  187 + 'Dismissible',
  188 + 'DismissIntent',
  189 + 'DismissUpdateDetails',
  190 + 'DisplayFeatureSubScreen',
  191 + 'DisposableBuildContext',
  192 + 'DoNothingAction',
  193 + 'DoNothingAndStopPropagationIntent',
  194 + 'DoNothingAndStopPropagationTextIntent',
  195 + 'DoNothingIntent',
  196 + 'DragDownDetails',
  197 + 'DragEndDetails',
  198 + 'Draggable',
  199 + 'DraggableDetails',
  200 + 'DraggableScrollableActuator',
  201 + 'DraggableScrollableController',
  202 + 'DraggableScrollableNotification',
  203 + 'DraggableScrollableSheet',
  204 + 'DragScrollActivity',
  205 + 'DragStartDetails',
  206 + 'DragTarget',
  207 + 'DragTargetDetails',
  208 + 'DragUpdateDetails',
  209 + 'DrivenScrollActivity',
  210 + 'DualTransitionBuilder',
  211 + 'EdgeDraggingAutoScroller',
  212 + 'EdgeInsets',
  213 + 'EdgeInsetsDirectional',
  214 + 'EdgeInsetsGeometry',
  215 + 'EdgeInsetsGeometryTween',
  216 + 'EdgeInsetsTween',
  217 + 'EditableText',
  218 + 'EditableTextState',
  219 + 'ElasticInCurve',
  220 + 'ElasticInOutCurve',
  221 + 'ElasticOutCurve',
  222 + 'Element',
  223 + 'EmptyTextSelectionControls',
  224 + 'ErrorDescription',
  225 + 'ErrorHint',
  226 + 'ErrorSummary',
  227 + 'ErrorWidget',
  228 + 'ExactAssetImage',
  229 + 'ExcludeFocus',
  230 + 'ExcludeFocusTraversal',
  231 + 'ExcludeSemantics',
  232 + 'Expanded',
  233 + 'ExpandSelectionToDocumentBoundaryIntent',
  234 + 'ExpandSelectionToLineBreakIntent',
  235 + 'ExtendSelectionByCharacterIntent',
  236 + 'ExtendSelectionByPageIntent',
  237 + 'ExtendSelectionToDocumentBoundaryIntent',
  238 + 'ExtendSelectionToLineBreakIntent',
  239 + 'ExtendSelectionToNextParagraphBoundaryIntent',
  240 + 'ExtendSelectionToNextParagraphBoundaryOrCaretLocationIntent',
  241 + 'ExtendSelectionToNextWordBoundaryIntent',
  242 + 'ExtendSelectionToNextWordBoundaryOrCaretLocationIntent',
  243 + 'ExtendSelectionVerticallyToAdjacentLineIntent',
  244 + 'ExtendSelectionVerticallyToAdjacentPageIntent',
  245 + 'FadeInImage',
  246 + 'FadeTransition',
  247 + 'FileImage',
  248 + 'FittedBox',
  249 + 'FittedSizes',
  250 + 'FixedColumnWidth',
  251 + 'FixedExtentMetrics',
  252 + 'FixedExtentScrollController',
  253 + 'FixedExtentScrollPhysics',
  254 + 'FixedScrollMetrics',
  255 + 'Flex',
  256 + 'FlexColumnWidth',
  257 + 'Flexible',
  258 + 'FlippedCurve',
  259 + 'FlippedTweenSequence',
  260 + 'Flow',
  261 + 'FlowDelegate',
  262 + 'FlowPaintingContext',
  263 + 'FlutterErrorDetails',
  264 + 'FlutterLogoDecoration',
  265 + 'Focus',
  266 + 'FocusableActionDetector',
  267 + 'FocusAttachment',
  268 + 'FocusManager',
  269 + 'FocusNode',
  270 + 'FocusOrder',
  271 + 'FocusScope',
  272 + 'FocusScopeNode',
  273 + 'FocusTraversalGroup',
  274 + 'FocusTraversalOrder',
  275 + 'FocusTraversalPolicy',
  276 + 'FontWeight',
  277 + 'ForcePressDetails',
  278 + 'Form',
  279 + 'FormField',
  280 + 'FormFieldState',
  281 + 'FormState',
  282 + 'FractionallySizedBox',
  283 + 'FractionalOffset',
  284 + 'FractionalOffsetTween',
  285 + 'FractionalTranslation',
  286 + 'FractionColumnWidth',
  287 + 'FutureBuilder',
  288 + 'GestureDetector',
  289 + 'GestureRecognizerFactory',
  290 + 'GestureRecognizerFactoryWithHandlers',
  291 + 'GlobalKey',
  292 + 'GlobalObjectKey',
  293 + 'GlowingOverscrollIndicator',
  294 + 'Gradient',
  295 + 'GradientRotation',
  296 + 'GradientTransform',
  297 + 'GridPaper',
  298 + 'GridView',
  299 + 'Hero',
  300 + 'HeroController',
  301 + 'HeroControllerScope',
  302 + 'HeroMode',
  303 + 'HoldScrollActivity',
  304 + 'HSLColor',
  305 + 'HSVColor',
  306 + 'HtmlElementView',
  307 + 'Icon',
  308 + 'IconData',
  309 + 'IconDataProperty',
  310 + 'IconTheme',
  311 + 'IconThemeData',
  312 + 'IdleScrollActivity',
  313 + 'IgnorePointer',
  314 + 'Image',
  315 + 'ImageCache',
  316 + 'ImageCacheStatus',
  317 + 'ImageChunkEvent',
  318 + 'ImageConfiguration',
  319 + 'ImageFiltered',
  320 + 'ImageIcon',
  321 + 'ImageInfo',
  322 + 'ImageProvider',
  323 + 'ImageShader',
  324 + 'ImageSizeInfo',
  325 + 'ImageStream',
  326 + 'ImageStreamCompleter',
  327 + 'ImageStreamCompleterHandle',
  328 + 'ImageStreamListener',
  329 + 'ImageTilingInfo',
  330 + 'ImplicitlyAnimatedWidget',
  331 + 'ImplicitlyAnimatedWidgetState',
  332 + 'IndexedSemantics',
  333 + 'IndexedSlot',
  334 + 'IndexedStack',
  335 + 'InheritedElement',
  336 + 'InheritedModel',
  337 + 'InheritedModelElement',
  338 + 'InheritedNotifier',
  339 + 'InheritedTheme',
  340 + 'InheritedWidget',
  341 + 'InlineSpan',
  342 + 'InlineSpanSemanticsInformation',
  343 + 'InspectorSelection',
  344 + 'InspectorSerializationDelegate',
  345 + 'Intent',
  346 + 'InteractiveViewer',
  347 + 'Interval',
  348 + 'IntrinsicColumnWidth',
  349 + 'IntrinsicHeight',
  350 + 'IntrinsicWidth',
  351 + 'IntTween',
  352 + 'KeepAlive',
  353 + 'KeepAliveHandle',
  354 + 'KeepAliveNotification',
  355 + 'Key',
  356 + 'KeyboardInsertedContent',
  357 + 'KeyboardListener',
  358 + 'KeyedSubtree',
  359 + 'KeyEvent',
  360 + 'KeySet',
  361 + 'LabeledGlobalKey',
  362 + 'LayerLink',
  363 + 'LayoutBuilder',
  364 + 'LayoutChangedNotification',
  365 + 'LayoutId',
  366 + 'LeafRenderObjectElement',
  367 + 'LeafRenderObjectWidget',
  368 + 'LexicalFocusOrder',
  369 + 'LimitedBox',
  370 + 'LinearBorder',
  371 + 'LinearBorderEdge',
  372 + 'LinearGradient',
  373 + 'ListBody',
  374 + 'Listenable',
  375 + 'ListenableBuilder',
  376 + 'Listener',
  377 + 'ListView',
  378 + 'ListWheelChildBuilderDelegate',
  379 + 'ListWheelChildDelegate',
  380 + 'ListWheelChildListDelegate',
  381 + 'ListWheelChildLoopingListDelegate',
  382 + 'ListWheelElement',
  383 + 'ListWheelScrollView',
  384 + 'ListWheelViewport',
  385 + 'Locale',
  386 + 'LocalHistoryEntry',
  387 + 'Localizations',
  388 + 'LocalizationsDelegate',
  389 + 'LocalKey',
  390 + 'LogicalKeySet',
  391 + 'LongPressDraggable',
  392 + 'LongPressEndDetails',
  393 + 'LongPressMoveUpdateDetails',
  394 + 'LongPressStartDetails',
  395 + 'LookupBoundary',
  396 + 'MagnifierController',
  397 + 'MagnifierDecoration',
  398 + 'MagnifierInfo',
  399 + 'MaskFilter',
  400 + 'Matrix4',
  401 + 'Matrix4Tween',
  402 + 'MatrixUtils',
  403 + 'MaxColumnWidth',
  404 + 'MediaQuery',
  405 + 'MediaQueryData',
  406 + 'MemoryImage',
  407 + 'MergeSemantics',
  408 + 'MetaData',
  409 + 'MinColumnWidth',
  410 + 'ModalBarrier',
  411 + 'ModalRoute',
  412 + 'MouseCursor',
  413 + 'MouseRegion',
  414 + 'MultiChildLayoutDelegate',
  415 + 'MultiChildRenderObjectElement',
  416 + 'MultiChildRenderObjectWidget',
  417 + 'MultiFrameImageStreamCompleter',
  418 + 'MultiSelectableSelectionContainerDelegate',
  419 + 'NavigationToolbar',
  420 + 'Navigator',
  421 + 'NavigatorObserver',
  422 + 'NavigatorState',
  423 + 'NestedScrollView',
  424 + 'NestedScrollViewState',
  425 + 'NestedScrollViewViewport',
  426 + 'NetworkImage',
  427 + 'NeverScrollableScrollPhysics',
  428 + 'NextFocusAction',
  429 + 'NextFocusIntent',
  430 + 'NotchedShape',
  431 + 'Notification',
  432 + 'NotificationListener',
  433 + 'NumericFocusOrder',
  434 + 'ObjectKey',
  435 + 'Offset',
  436 + 'Offstage',
  437 + 'OneFrameImageStreamCompleter',
  438 + 'Opacity',
  439 + 'OrderedTraversalPolicy',
  440 + 'OrientationBuilder',
  441 + 'OutlinedBorder',
  442 + 'OvalBorder',
  443 + 'OverflowBar',
  444 + 'OverflowBox',
  445 + 'Overlay',
  446 + 'OverlayEntry',
  447 + 'OverlayPortal',
  448 + 'OverlayPortalController',
  449 + 'OverlayRoute',
  450 + 'OverlayState',
  451 + 'OverscrollIndicatorNotification',
  452 + 'OverscrollNotification',
  453 + 'Padding',
  454 + 'Page',
  455 + 'PageController',
  456 + 'PageMetrics',
  457 + 'PageRoute',
  458 + 'PageRouteBuilder',
  459 + 'PageScrollPhysics',
  460 + 'PageStorage',
  461 + 'PageStorageBucket',
  462 + 'PageStorageKey',
  463 + 'PageView',
  464 + 'Paint',
  465 + 'PaintingContext',
  466 + 'ParametricCurve',
  467 + 'ParentDataElement',
  468 + 'ParentDataWidget',
  469 + 'PasteTextIntent',
  470 + 'Path',
  471 + 'PerformanceOverlay',
  472 + 'PhysicalModel',
  473 + 'PhysicalShape',
  474 + 'Placeholder',
  475 + 'PlaceholderDimensions',
  476 + 'PlaceholderSpan',
  477 + 'PlatformMenu',
  478 + 'PlatformMenuBar',
  479 + 'PlatformMenuDelegate',
  480 + 'PlatformMenuItem',
  481 + 'PlatformMenuItemGroup',
  482 + 'PlatformProvidedMenuItem',
  483 + 'PlatformRouteInformationProvider',
  484 + 'PlatformSelectableRegionContextMenu',
  485 + 'PlatformViewCreationParams',
  486 + 'PlatformViewLink',
  487 + 'PlatformViewSurface',
  488 + 'PointerCancelEvent',
  489 + 'PointerDownEvent',
  490 + 'PointerEvent',
  491 + 'PointerMoveEvent',
  492 + 'PointerUpEvent',
  493 + 'PopupRoute',
  494 + 'Positioned',
  495 + 'PositionedDirectional',
  496 + 'PositionedTransition',
  497 + 'PreferredSize',
  498 + 'PreferredSizeWidget',
  499 + 'PreviousFocusAction',
  500 + 'PreviousFocusIntent',
  501 + 'PrimaryScrollController',
  502 + 'PrioritizedAction',
  503 + 'PrioritizedIntents',
  504 + 'ProxyAnimation',
  505 + 'ProxyElement',
  506 + 'ProxyWidget',
  507 + 'RadialGradient',
  508 + 'Radius',
  509 + 'RangeMaintainingScrollPhysics',
  510 + 'RawAutocomplete',
  511 + 'RawDialogRoute',
  512 + 'RawGestureDetector',
  513 + 'RawGestureDetectorState',
  514 + 'RawImage',
  515 + 'RawKeyboardListener',
  516 + 'RawKeyEvent',
  517 + 'RawMagnifier',
  518 + 'RawScrollbar',
  519 + 'RawScrollbarState',
  520 + 'ReadingOrderTraversalPolicy',
  521 + 'Rect',
  522 + 'RectTween',
  523 + 'RedoTextIntent',
  524 + 'RelativePositionedTransition',
  525 + 'RelativeRect',
  526 + 'RelativeRectTween',
  527 + 'RenderBox',
  528 + 'RenderNestedScrollViewViewport',
  529 + 'RenderObject',
  530 + 'RenderObjectElement',
  531 + 'RenderObjectToWidgetAdapter',
  532 + 'RenderObjectToWidgetElement',
  533 + 'RenderObjectWidget',
  534 + 'RenderSemanticsGestureHandler',
  535 + 'RenderSliverOverlapAbsorber',
  536 + 'RenderSliverOverlapInjector',
  537 + 'RenderTapRegion',
  538 + 'RenderTapRegionSurface',
  539 + 'ReorderableDelayedDragStartListener',
  540 + 'ReorderableDragStartListener',
  541 + 'ReorderableList',
  542 + 'ReorderableListState',
  543 + 'RepaintBoundary',
  544 + 'ReplaceTextIntent',
  545 + 'RequestFocusAction',
  546 + 'RequestFocusIntent',
  547 + 'ResizeImage',
  548 + 'ResizeImageKey',
  549 + 'RestorableBool',
  550 + 'RestorableBoolN',
  551 + 'RestorableChangeNotifier',
  552 + 'RestorableDateTime',
  553 + 'RestorableDateTimeN',
  554 + 'RestorableDouble',
  555 + 'RestorableDoubleN',
  556 + 'RestorableEnum',
  557 + 'RestorableEnumN',
  558 + 'RestorableInt',
  559 + 'RestorableIntN',
  560 + 'RestorableListenable',
  561 + 'RestorableNum',
  562 + 'RestorableNumN',
  563 + 'RestorableProperty',
  564 + 'RestorableRouteFuture',
  565 + 'RestorableString',
  566 + 'RestorableStringN',
  567 + 'RestorableTextEditingController',
  568 + 'RestorableValue',
  569 + 'RestorationBucket',
  570 + 'RestorationScope',
  571 + 'ReverseAnimation',
  572 + 'ReverseTween',
  573 + 'RichText',
  574 + 'RootBackButtonDispatcher',
  575 + 'RootRenderObjectElement',
  576 + 'RootRestorationScope',
  577 + 'RotatedBox',
  578 + 'RotationTransition',
  579 + 'RoundedRectangleBorder',
  580 + 'Route',
  581 + 'RouteAware',
  582 + 'RouteInformation',
  583 + 'RouteInformationParser',
  584 + 'RouteInformationProvider',
  585 + 'RouteObserver',
  586 + 'Router',
  587 + 'RouterConfig',
  588 + 'RouterDelegate',
  589 + 'RouteSettings',
  590 + 'RouteTransitionRecord',
  591 + 'Row',
  592 + 'RRect',
  593 + 'RSTransform',
  594 + 'SafeArea',
  595 + 'SawTooth',
  596 + 'ScaleEndDetails',
  597 + 'ScaleStartDetails',
  598 + 'ScaleTransition',
  599 + 'ScaleUpdateDetails',
  600 + 'Scrollable',
  601 + 'ScrollableDetails',
  602 + 'ScrollableState',
  603 + 'ScrollAction',
  604 + 'ScrollActivity',
  605 + 'ScrollActivityDelegate',
  606 + 'ScrollAwareImageProvider',
  607 + 'ScrollbarPainter',
  608 + 'ScrollBehavior',
  609 + 'ScrollConfiguration',
  610 + 'ScrollContext',
  611 + 'ScrollController',
  612 + 'ScrollDragController',
  613 + 'ScrollEndNotification',
  614 + 'ScrollHoldController',
  615 + 'ScrollIncrementDetails',
  616 + 'ScrollIntent',
  617 + 'ScrollMetricsNotification',
  618 + 'ScrollNotification',
  619 + 'ScrollNotificationObserver',
  620 + 'ScrollNotificationObserverState',
  621 + 'ScrollPhysics',
  622 + 'ScrollPosition',
  623 + 'ScrollPositionWithSingleContext',
  624 + 'ScrollSpringSimulation',
  625 + 'ScrollStartNotification',
  626 + 'ScrollToDocumentBoundaryIntent',
  627 + 'ScrollUpdateNotification',
  628 + 'ScrollView',
  629 + 'SelectableRegion',
  630 + 'SelectableRegionState',
  631 + 'SelectAction',
  632 + 'SelectAllTextIntent',
  633 + 'SelectIntent',
  634 + 'SelectionContainer',
  635 + 'SelectionContainerDelegate',
  636 + 'SelectionOverlay',
  637 + 'SelectionRegistrarScope',
  638 + 'Semantics',
  639 + 'SemanticsDebugger',
  640 + 'SemanticsGestureDelegate',
  641 + 'Shader',
  642 + 'ShaderMask',
  643 + 'ShaderWarmUp',
  644 + 'Shadow',
  645 + 'ShapeBorder',
  646 + 'ShapeBorderClipper',
  647 + 'ShapeDecoration',
  648 + 'SharedAppData',
  649 + 'ShortcutActivator',
  650 + 'ShortcutManager',
  651 + 'ShortcutMapProperty',
  652 + 'ShortcutRegistrar',
  653 + 'ShortcutRegistry',
  654 + 'ShortcutRegistryEntry',
  655 + 'Shortcuts',
  656 + 'ShortcutSerialization',
  657 + 'ShrinkWrappingViewport',
  658 + 'Simulation',
  659 + 'SingleActivator',
  660 + 'SingleChildLayoutDelegate',
  661 + 'SingleChildRenderObjectElement',
  662 + 'SingleChildRenderObjectWidget',
  663 + 'SingleChildScrollView',
  664 + 'Size',
  665 + 'SizeChangedLayoutNotification',
  666 + 'SizeChangedLayoutNotifier',
  667 + 'SizedBox',
  668 + 'SizedOverflowBox',
  669 + 'SizeTransition',
  670 + 'SizeTween',
  671 + 'SlideTransition',
  672 + 'SliverAnimatedGrid',
  673 + 'SliverAnimatedGridState',
  674 + 'SliverAnimatedList',
  675 + 'SliverAnimatedListState',
  676 + 'SliverAnimatedOpacity',
  677 + 'SliverChildBuilderDelegate',
  678 + 'SliverChildDelegate',
  679 + 'SliverChildListDelegate',
  680 + 'SliverFadeTransition',
  681 + 'SliverFillRemaining',
  682 + 'SliverFillViewport',
  683 + 'SliverFixedExtentList',
  684 + 'SliverGrid',
  685 + 'SliverGridDelegate',
  686 + 'SliverGridDelegateWithFixedCrossAxisCount',
  687 + 'SliverGridDelegateWithMaxCrossAxisExtent',
  688 + 'SliverIgnorePointer',
  689 + 'SliverLayoutBuilder',
  690 + 'SliverList',
  691 + 'SliverMultiBoxAdaptorElement',
  692 + 'SliverMultiBoxAdaptorWidget',
  693 + 'SliverOffstage',
  694 + 'SliverOpacity',
  695 + 'SliverOverlapAbsorber',
  696 + 'SliverOverlapAbsorberHandle',
  697 + 'SliverOverlapInjector',
  698 + 'SliverPadding',
  699 + 'SliverPersistentHeader',
  700 + 'SliverPersistentHeaderDelegate',
  701 + 'SliverPrototypeExtentList',
  702 + 'SliverReorderableList',
  703 + 'SliverReorderableListState',
  704 + 'SliverSafeArea',
  705 + 'SliverToBoxAdapter',
  706 + 'SliverVisibility',
  707 + 'SliverWithKeepAliveWidget',
  708 + 'SlottedRenderObjectElement',
  709 + 'SnapshotController',
  710 + 'SnapshotPainter',
  711 + 'SnapshotWidget',
  712 + 'Spacer',
  713 + 'SpellCheckConfiguration',
  714 + 'SpringDescription',
  715 + 'Stack',
  716 + 'StadiumBorder',
  717 + 'StarBorder',
  718 + 'State',
  719 + 'StatefulBuilder',
  720 + 'StatefulElement',
  721 + 'StatefulWidget',
  722 + 'StatelessElement',
  723 + 'StatelessWidget',
  724 + 'StatusTransitionWidget',
  725 + 'StepTween',
  726 + 'StreamBuilder',
  727 + 'StreamBuilderBase',
  728 + 'StretchingOverscrollIndicator',
  729 + 'StrutStyle',
  730 + 'SweepGradient',
  731 + 'SystemMouseCursors',
  732 + 'Table',
  733 + 'TableBorder',
  734 + 'TableCell',
  735 + 'TableColumnWidth',
  736 + 'TableRow',
  737 + 'TapAndDragGestureRecognizer',
  738 + 'TapAndHorizontalDragGestureRecognizer',
  739 + 'TapAndPanGestureRecognizer',
  740 + 'TapDownDetails',
  741 + 'TapDragDownDetails',
  742 + 'TapDragEndDetails',
  743 + 'TapDragStartDetails',
  744 + 'TapDragUpdateDetails',
  745 + 'TapDragUpDetails',
  746 + 'TapRegion',
  747 + 'TapRegionRegistry',
  748 + 'TapRegionSurface',
  749 + 'TapUpDetails',
  750 + 'Text',
  751 + 'TextAlignVertical',
  752 + 'TextBox',
  753 + 'TextDecoration',
  754 + 'TextEditingController',
  755 + 'TextEditingValue',
  756 + 'TextFieldTapRegion',
  757 + 'TextHeightBehavior',
  758 + 'TextInputType',
  759 + 'TextMagnifierConfiguration',
  760 + 'TextPainter',
  761 + 'TextPosition',
  762 + 'TextRange',
  763 + 'TextSelection',
  764 + 'TextSelectionControls',
  765 + 'TextSelectionGestureDetector',
  766 + 'TextSelectionGestureDetectorBuilder',
  767 + 'TextSelectionGestureDetectorBuilderDelegate',
  768 + 'TextSelectionOverlay',
  769 + 'TextSelectionPoint',
  770 + 'TextSelectionToolbarAnchors',
  771 + 'TextSelectionToolbarLayoutDelegate',
  772 + 'TextSpan',
  773 + 'TextStyle',
  774 + 'TextStyleTween',
  775 + 'Texture',
  776 + 'ThreePointCubic',
  777 + 'Threshold',
  778 + 'TickerFuture',
  779 + 'TickerMode',
  780 + 'TickerProvider',
  781 + 'Title',
  782 + 'Tolerance',
  783 + 'ToolbarItemsParentData',
  784 + 'ToolbarOptions',
  785 + 'TrackingScrollController',
  786 + 'TrainHoppingAnimation',
  787 + 'Transform',
  788 + 'TransformationController',
  789 + 'TransformProperty',
  790 + 'TransitionDelegate',
  791 + 'TransitionRoute',
  792 + 'TransposeCharactersIntent',
  793 + 'Tween',
  794 + 'TweenAnimationBuilder',
  795 + 'TweenSequence',
  796 + 'TweenSequenceItem',
  797 + 'UiKitView',
  798 + 'UnconstrainedBox',
  799 + 'UndoHistory',
  800 + 'UndoHistoryController',
  801 + 'UndoHistoryState',
  802 + 'UndoHistoryValue',
  803 + 'UndoTextIntent',
  804 + 'UniqueKey',
  805 + 'UniqueWidget',
  806 + 'UnmanagedRestorationScope',
  807 + 'UpdateSelectionIntent',
  808 + 'UserScrollNotification',
  809 + 'ValueKey',
  810 + 'ValueListenableBuilder',
  811 + 'ValueNotifier',
  812 + 'Velocity',
  813 + 'View',
  814 + 'Viewport',
  815 + 'Visibility',
  816 + 'VoidCallbackAction',
  817 + 'VoidCallbackIntent',
  818 + 'Widget',
  819 + 'WidgetInspector',
  820 + 'WidgetOrderTraversalPolicy',
  821 + 'WidgetsApp',
  822 + 'WidgetsBindingObserver',
  823 + 'WidgetsFlutterBinding',
  824 + 'WidgetsLocalizations',
  825 + 'WidgetSpan',
  826 + 'WidgetToRenderBoxAdapter',
  827 + 'WillPopScope',
  828 + 'WordBoundary',
  829 + 'Wrap'
  830 +});
@@ -4,11 +4,12 @@ @@ -4,11 +4,12 @@
4 */ 4 */
5 5
6 import 'dart:math' show min, max; 6 import 'dart:math' show min, max;
7 -import 'dart:ui' show FlutterView;  
8 -import 'dart:async' show Completer; 7 +import 'dart:ui' as ui show FlutterView;
9 8
10 import 'package:flutter/widgets.dart'; 9 import 'package:flutter/widgets.dart';
11 10
  11 +typedef FontSizeResolver = double Function(num fontSize, ScreenUtil instance);
  12 +
12 class ScreenUtil { 13 class ScreenUtil {
13 static const Size defaultSize = Size(360, 690); 14 static const Size defaultSize = Size(360, 690);
14 static ScreenUtil _instance = ScreenUtil._(); 15 static ScreenUtil _instance = ScreenUtil._();
@@ -20,17 +21,14 @@ class ScreenUtil { @@ -20,17 +21,14 @@ class ScreenUtil {
20 ///屏幕方向 21 ///屏幕方向
21 late Orientation _orientation; 22 late Orientation _orientation;
22 23
23 - late double _screenWidth;  
24 - late double _screenHeight;  
25 late bool _minTextAdapt; 24 late bool _minTextAdapt;
26 - BuildContext? _context; 25 + late MediaQueryData _data;
27 late bool _splitScreenMode; 26 late bool _splitScreenMode;
  27 + FontSizeResolver? fontSizeResolver;
28 28
29 ScreenUtil._(); 29 ScreenUtil._();
30 30
31 - factory ScreenUtil() {  
32 - return _instance;  
33 - } 31 + factory ScreenUtil() => _instance;
34 32
35 /// Manually wait for window size to be initialized 33 /// Manually wait for window size to be initialized
36 /// 34 ///
@@ -55,19 +53,25 @@ class ScreenUtil { @@ -55,19 +53,25 @@ class ScreenUtil {
55 /// ) 53 /// )
56 /// ``` 54 /// ```
57 static Future<void> ensureScreenSize([ 55 static Future<void> ensureScreenSize([
58 - FlutterView? window, 56 + ui.FlutterView? window,
59 Duration duration = const Duration(milliseconds: 10), 57 Duration duration = const Duration(milliseconds: 10),
60 ]) async { 58 ]) async {
61 final binding = WidgetsFlutterBinding.ensureInitialized(); 59 final binding = WidgetsFlutterBinding.ensureInitialized();
62 - window ??= WidgetsBinding.instance.platformDispatcher.implicitView;  
63 -  
64 - if (window?.physicalGeometry.isEmpty == true) {  
65 - return Future.delayed(duration, () async {  
66 binding.deferFirstFrame(); 60 binding.deferFirstFrame();
67 - await ensureScreenSize(window, duration);  
68 - return binding.allowFirstFrame();  
69 - }); 61 +
  62 + await Future.doWhile(() {
  63 + if (window == null) {
  64 + window = binding.platformDispatcher.implicitView;
70 } 65 }
  66 +
  67 + if (window == null || window!.physicalSize.isEmpty) {
  68 + return Future.delayed(duration, () => true);
  69 + }
  70 +
  71 + return false;
  72 + });
  73 +
  74 + binding.allowFirstFrame();
71 } 75 }
72 76
73 Set<Element>? _elementsToRebuild; 77 Set<Element>? _elementsToRebuild;
@@ -88,44 +92,78 @@ class ScreenUtil { @@ -88,44 +92,78 @@ class ScreenUtil {
88 } 92 }
89 } 93 }
90 94
91 - /// Initializing the library.  
92 - static Future<void> init(BuildContext context,  
93 - {Size designSize = defaultSize,  
94 - bool splitScreenMode = false,  
95 - bool minTextAdapt = false,  
96 - bool scaleByHeight = false}) async {  
97 - final mediaQueryContext =  
98 - context.getElementForInheritedWidgetOfExactType<MediaQuery>();  
99 -  
100 - final initCompleter = Completer<void>(); 95 + static void configure({
  96 + MediaQueryData? data,
  97 + Size? designSize,
  98 + bool? splitScreenMode,
  99 + bool? minTextAdapt,
  100 + FontSizeResolver? fontSizeResolver,
  101 + }) {
  102 + try {
  103 + if (data != null)
  104 + _instance._data = data;
  105 + else
  106 + data = _instance._data;
101 107
102 - WidgetsFlutterBinding.ensureInitialized().addPostFrameCallback((_) {  
103 - mediaQueryContext?.visitChildElements((el) => _instance._context = el);  
104 - if (_instance._context != null) initCompleter.complete();  
105 - }); 108 + if (designSize != null)
  109 + _instance._uiSize = designSize;
  110 + else
  111 + designSize = _instance._uiSize;
  112 + } catch (_) {
  113 + throw Exception(
  114 + 'You must either use ScreenUtil.init or ScreenUtilInit first');
  115 + }
106 116
107 - final deviceData = MediaQuery.maybeOf(context).nonEmptySizeOrNull(); 117 + final MediaQueryData? deviceData = data.nonEmptySizeOrNull();
  118 + final Size deviceSize = deviceData?.size ?? designSize;
108 119
109 - final deviceSize = deviceData?.size ?? designSize;  
110 final orientation = deviceData?.orientation ?? 120 final orientation = deviceData?.orientation ??
111 (deviceSize.width > deviceSize.height 121 (deviceSize.width > deviceSize.height
112 ? Orientation.landscape 122 ? Orientation.landscape
113 : Orientation.portrait); 123 : Orientation.portrait);
114 124
115 _instance 125 _instance
116 - .._context = scaleByHeight ? null : context  
117 - .._uiSize = designSize  
118 - .._splitScreenMode = splitScreenMode  
119 - .._minTextAdapt = minTextAdapt  
120 - .._orientation = orientation  
121 - .._screenWidth = scaleByHeight  
122 - ? (deviceSize.height * designSize.width) / designSize.height  
123 - : deviceSize.width  
124 - .._screenHeight = deviceSize.height; 126 + ..fontSizeResolver = fontSizeResolver ?? _instance.fontSizeResolver
  127 + .._minTextAdapt = minTextAdapt ?? _instance._minTextAdapt
  128 + .._splitScreenMode = splitScreenMode ?? _instance._splitScreenMode
  129 + .._orientation = orientation;
125 130
126 _instance._elementsToRebuild?.forEach((el) => el.markNeedsBuild()); 131 _instance._elementsToRebuild?.forEach((el) => el.markNeedsBuild());
  132 + }
  133 +
  134 + /// Initializing the library.
  135 + static void init(
  136 + BuildContext context, {
  137 + Size designSize = defaultSize,
  138 + bool splitScreenMode = false,
  139 + bool minTextAdapt = false,
  140 + FontSizeResolver? fontSizeResolver,
  141 + }) {
  142 + return configure(
  143 + data: MediaQuery.maybeOf(context),
  144 + designSize: designSize,
  145 + splitScreenMode: splitScreenMode,
  146 + minTextAdapt: minTextAdapt,
  147 + fontSizeResolver: fontSizeResolver,
  148 + );
  149 + }
127 150
128 - return initCompleter.future; 151 + static Future<void> ensureScreenSizeAndInit(
  152 + BuildContext context, {
  153 + Size designSize = defaultSize,
  154 + bool splitScreenMode = false,
  155 + bool minTextAdapt = false,
  156 + FontSizeResolver? fontSizeResolver,
  157 + }) {
  158 + return ScreenUtil.ensureScreenSize().then((_) {
  159 + return configure(
  160 + data: MediaQuery.maybeOf(context),
  161 + designSize: designSize,
  162 + minTextAdapt: minTextAdapt,
  163 + splitScreenMode: splitScreenMode,
  164 + fontSizeResolver: fontSizeResolver,
  165 + );
  166 + });
129 } 167 }
130 168
131 ///获取屏幕方向 169 ///获取屏幕方向
@@ -134,39 +172,33 @@ class ScreenUtil { @@ -134,39 +172,33 @@ class ScreenUtil {
134 172
135 /// 每个逻辑像素的字体像素数,字体的缩放比例 173 /// 每个逻辑像素的字体像素数,字体的缩放比例
136 /// The number of font pixels for each logical pixel. 174 /// The number of font pixels for each logical pixel.
137 - double get textScaleFactor =>  
138 - _context != null ? MediaQuery.of(_context!).textScaleFactor : 1; 175 + double get textScaleFactor => _data.textScaleFactor;
139 176
140 /// 设备的像素密度 177 /// 设备的像素密度
141 /// The size of the media in logical pixels (e.g, the size of the screen). 178 /// The size of the media in logical pixels (e.g, the size of the screen).
142 - double? get pixelRatio =>  
143 - _context != null ? MediaQuery.of(_context!).devicePixelRatio : 1; 179 + double? get pixelRatio => _data.devicePixelRatio;
144 180
145 /// 当前设备宽度 dp 181 /// 当前设备宽度 dp
146 /// The horizontal extent of this size. 182 /// The horizontal extent of this size.
147 - double get screenWidth =>  
148 - _context != null ? MediaQuery.of(_context!).size.width : _screenWidth; 183 + double get screenWidth => _data.size.width;
149 184
150 ///当前设备高度 dp 185 ///当前设备高度 dp
151 ///The vertical extent of this size. dp 186 ///The vertical extent of this size. dp
152 - double get screenHeight =>  
153 - _context != null ? MediaQuery.of(_context!).size.height : _screenHeight; 187 + double get screenHeight => _data.size.height;
154 188
155 /// 状态栏高度 dp 刘海屏会更高 189 /// 状态栏高度 dp 刘海屏会更高
156 /// The offset from the top, in dp 190 /// The offset from the top, in dp
157 - double get statusBarHeight =>  
158 - _context == null ? 0 : MediaQuery.of(_context!).padding.top; 191 + double get statusBarHeight => _data.padding.top;
159 192
160 /// 底部安全区距离 dp 193 /// 底部安全区距离 dp
161 /// The offset from the bottom, in dp 194 /// The offset from the bottom, in dp
162 - double get bottomBarHeight =>  
163 - _context == null ? 0 : MediaQuery.of(_context!).padding.bottom; 195 + double get bottomBarHeight => _data.padding.bottom;
164 196
165 /// 实际尺寸与UI设计的比例 197 /// 实际尺寸与UI设计的比例
166 /// The ratio of actual width to UI design 198 /// The ratio of actual width to UI design
167 double get scaleWidth => screenWidth / _uiSize.width; 199 double get scaleWidth => screenWidth / _uiSize.width;
168 200
169 - /// /// The ratio of actual height to UI design 201 + /// The ratio of actual height to UI design
170 double get scaleHeight => 202 double get scaleHeight =>
171 (_splitScreenMode ? max(screenHeight, 700) : screenHeight) / 203 (_splitScreenMode ? max(screenHeight, 700) : screenHeight) /
172 _uiSize.height; 204 _uiSize.height;
@@ -195,24 +227,44 @@ class ScreenUtil { @@ -195,24 +227,44 @@ class ScreenUtil {
195 ///Adapt according to the smaller of width or height 227 ///Adapt according to the smaller of width or height
196 double radius(num r) => r * min(scaleWidth, scaleHeight); 228 double radius(num r) => r * min(scaleWidth, scaleHeight);
197 229
  230 + /// Adapt according to the both width and height
  231 + double diagonal(num d) => d * scaleHeight * scaleWidth;
  232 +
  233 + /// Adapt according to the maximum value of scale width and scale height
  234 + double diameter(num d) => d * max(scaleWidth, scaleHeight);
  235 +
198 ///字体大小适配方法 236 ///字体大小适配方法
199 ///- [fontSize] UI设计上字体的大小,单位dp. 237 ///- [fontSize] UI设计上字体的大小,单位dp.
200 ///Font size adaptation method 238 ///Font size adaptation method
201 ///- [fontSize] The size of the font on the UI design, in dp. 239 ///- [fontSize] The size of the font on the UI design, in dp.
202 - double setSp(num fontSize) => fontSize * scaleText; 240 + double setSp(num fontSize) =>
  241 + fontSizeResolver?.call(fontSize, _instance) ?? fontSize * scaleText;
203 242
204 - Widget setVerticalSpacing(num height) => SizedBox(height: setHeight(height)); 243 + SizedBox setVerticalSpacing(num height) =>
  244 + SizedBox(height: setHeight(height));
205 245
206 - Widget setVerticalSpacingFromWidth(num height) => 246 + SizedBox setVerticalSpacingFromWidth(num height) =>
207 SizedBox(height: setWidth(height)); 247 SizedBox(height: setWidth(height));
208 248
209 - Widget setHorizontalSpacing(num width) => SizedBox(width: setWidth(width)); 249 + SizedBox setHorizontalSpacing(num width) => SizedBox(width: setWidth(width));
210 250
211 - Widget setHorizontalSpacingRadius(num width) => 251 + SizedBox setHorizontalSpacingRadius(num width) =>
212 SizedBox(width: radius(width)); 252 SizedBox(width: radius(width));
213 253
214 - Widget setVerticalSpacingRadius(num height) => 254 + SizedBox setVerticalSpacingRadius(num height) =>
215 SizedBox(height: radius(height)); 255 SizedBox(height: radius(height));
  256 +
  257 + SizedBox setHorizontalSpacingDiameter(num width) =>
  258 + SizedBox(width: diameter(width));
  259 +
  260 + SizedBox setVerticalSpacingDiameter(num height) =>
  261 + SizedBox(height: diameter(height));
  262 +
  263 + SizedBox setHorizontalSpacingDiagonal(num width) =>
  264 + SizedBox(width: diagonal(width));
  265 +
  266 + SizedBox setVerticalSpacingDiagonal(num height) =>
  267 + SizedBox(height: diagonal(height));
216 } 268 }
217 269
218 extension on MediaQueryData? { 270 extension on MediaQueryData? {
  1 +import 'dart:async';
  2 +import 'dart:collection';
  3 +
1 import 'package:flutter/widgets.dart'; 4 import 'package:flutter/widgets.dart';
  5 +import './_flutter_widgets.dart';
2 6
  7 +import 'screenutil_mixin.dart';
3 import 'screen_util.dart'; 8 import 'screen_util.dart';
4 9
5 typedef RebuildFactor = bool Function(MediaQueryData old, MediaQueryData data); 10 typedef RebuildFactor = bool Function(MediaQueryData old, MediaQueryData data);
@@ -9,9 +14,7 @@ typedef ScreenUtilInitBuilder = Widget Function( @@ -9,9 +14,7 @@ typedef ScreenUtilInitBuilder = Widget Function(
9 Widget? child, 14 Widget? child,
10 ); 15 );
11 16
12 -class RebuildFactors {  
13 - const RebuildFactors._();  
14 - 17 +abstract class RebuildFactors {
15 static bool size(MediaQueryData old, MediaQueryData data) { 18 static bool size(MediaQueryData old, MediaQueryData data) {
16 return old.size != data.size; 19 return old.size != data.size;
17 } 20 }
@@ -24,35 +27,69 @@ class RebuildFactors { @@ -24,35 +27,69 @@ class RebuildFactors {
24 return old.viewInsets != data.viewInsets; 27 return old.viewInsets != data.viewInsets;
25 } 28 }
26 29
27 - static bool all(MediaQueryData old, MediaQueryData data) { 30 + static bool change(MediaQueryData old, MediaQueryData data) {
28 return old != data; 31 return old != data;
29 } 32 }
  33 +
  34 + static bool always(MediaQueryData _, MediaQueryData __) {
  35 + return true;
  36 + }
  37 +
  38 + static bool none(MediaQueryData _, MediaQueryData __) {
  39 + return false;
  40 + }
  41 +}
  42 +
  43 +abstract class FontSizeResolvers {
  44 + static double width(num fontSize, ScreenUtil instance) {
  45 + return instance.setWidth(fontSize);
  46 + }
  47 +
  48 + static double height(num fontSize, ScreenUtil instance) {
  49 + return instance.setHeight(fontSize);
  50 + }
  51 +
  52 + static double raduis(num fontSize, ScreenUtil instance) {
  53 + return instance.radius(fontSize);
  54 + }
  55 +
  56 + static double diameter(num fontSize, ScreenUtil instance) {
  57 + return instance.diameter(fontSize);
  58 + }
  59 +
  60 + static double diagonal(num fontSize, ScreenUtil instance) {
  61 + return instance.diagonal(fontSize);
  62 + }
30 } 63 }
31 64
32 class ScreenUtilInit extends StatefulWidget { 65 class ScreenUtilInit extends StatefulWidget {
33 /// A helper widget that initializes [ScreenUtil] 66 /// A helper widget that initializes [ScreenUtil]
34 - const ScreenUtilInit(  
35 - {Key? key,  
36 - required this.builder, 67 + const ScreenUtilInit({
  68 + Key? key,
  69 + this.builder,
37 this.child, 70 this.child,
38 this.rebuildFactor = RebuildFactors.size, 71 this.rebuildFactor = RebuildFactors.size,
39 this.designSize = ScreenUtil.defaultSize, 72 this.designSize = ScreenUtil.defaultSize,
40 this.splitScreenMode = false, 73 this.splitScreenMode = false,
41 this.minTextAdapt = false, 74 this.minTextAdapt = false,
42 this.useInheritedMediaQuery = false, 75 this.useInheritedMediaQuery = false,
43 - this.scaleByHeight = false})  
44 - : super(key: key); 76 + this.ensureScreenSize,
  77 + this.responsiveWidgets,
  78 + this.fontSizeResolver = FontSizeResolvers.width,
  79 + }) : super(key: key);
45 80
46 - final ScreenUtilInitBuilder builder; 81 + final ScreenUtilInitBuilder? builder;
47 final Widget? child; 82 final Widget? child;
48 final bool splitScreenMode; 83 final bool splitScreenMode;
49 final bool minTextAdapt; 84 final bool minTextAdapt;
50 final bool useInheritedMediaQuery; 85 final bool useInheritedMediaQuery;
51 - final bool scaleByHeight; 86 + final bool? ensureScreenSize;
52 final RebuildFactor rebuildFactor; 87 final RebuildFactor rebuildFactor;
  88 + final FontSizeResolver fontSizeResolver;
53 89
54 /// The [Size] of the device in the design draft, in dp 90 /// The [Size] of the device in the design draft, in dp
55 final Size designSize; 91 final Size designSize;
  92 + final Iterable<String>? responsiveWidgets;
56 93
57 @override 94 @override
58 State<ScreenUtilInit> createState() => _ScreenUtilInitState(); 95 State<ScreenUtilInit> createState() => _ScreenUtilInitState();
@@ -60,127 +97,103 @@ class ScreenUtilInit extends StatefulWidget { @@ -60,127 +97,103 @@ class ScreenUtilInit extends StatefulWidget {
60 97
61 class _ScreenUtilInitState extends State<ScreenUtilInit> 98 class _ScreenUtilInitState extends State<ScreenUtilInit>
62 with WidgetsBindingObserver { 99 with WidgetsBindingObserver {
  100 + final _canMarkedToBuild = HashSet<String>();
63 MediaQueryData? _mediaQueryData; 101 MediaQueryData? _mediaQueryData;
  102 + final _binding = WidgetsBinding.instance;
  103 + final _screenSizeCompleter = Completer<void>();
64 104
65 - bool wrappedInMediaQuery = false; 105 + @override
  106 + void initState() {
  107 + if (widget.responsiveWidgets != null) {
  108 + _canMarkedToBuild.addAll(widget.responsiveWidgets!);
  109 + }
  110 + _validateSize().then(_screenSizeCompleter.complete);
  111 +
  112 + super.initState();
  113 + _binding.addObserver(this);
  114 + }
66 115
67 - WidgetsBinding get binding => WidgetsFlutterBinding.ensureInitialized(); 116 + @override
  117 + void didChangeMetrics() {
  118 + super.didChangeMetrics();
  119 + _revalidate();
  120 + }
68 121
69 - MediaQueryData get mediaQueryData => _mediaQueryData!; 122 + @override
  123 + void didChangeDependencies() {
  124 + super.didChangeDependencies();
  125 + _revalidate();
  126 + }
70 127
71 - MediaQueryData get newData {  
72 - final data = MediaQuery.maybeOf(context); 128 + MediaQueryData? _newData() {
  129 + MediaQueryData? mq = MediaQuery.maybeOf(context);
  130 + if (mq == null) mq = MediaQueryData.fromView(View.of(context));
73 131
74 - if (data != null) {  
75 - if (widget.useInheritedMediaQuery) {  
76 - wrappedInMediaQuery = true; 132 + return mq;
77 } 133 }
78 - return data; 134 +
  135 + Future<void> _validateSize() async {
  136 + if (widget.ensureScreenSize ?? false) return ScreenUtil.ensureScreenSize();
79 } 137 }
80 138
81 - return MediaQueryData.fromView(View.of(context)); 139 + void _markNeedsBuildIfAllowed(Element el) {
  140 + final widgetName = el.widget.runtimeType.toString();
  141 + final allowed = widget is SU ||
  142 + _canMarkedToBuild.contains(widgetName) ||
  143 + !(widgetName.startsWith('_') || flutterWidgets.contains(widgetName));
  144 +
  145 + if (allowed) el.markNeedsBuild();
82 } 146 }
83 147
84 - _updateTree(Element el) {  
85 - el.markNeedsBuild(); 148 + void _updateTree(Element el) {
  149 + _markNeedsBuildIfAllowed(el);
86 el.visitChildren(_updateTree); 150 el.visitChildren(_updateTree);
87 } 151 }
88 152
89 - @override  
90 - void initState() {  
91 - super.initState();  
92 - binding.addObserver(this);  
93 - } 153 + void _revalidate([void Function()? callback]) {
  154 + final oldData = _mediaQueryData;
  155 + final newData = _newData();
94 156
95 - @override  
96 - void didChangeMetrics() {  
97 - final old = _mediaQueryData!;  
98 - final data = newData; 157 + if (newData == null) return;
99 158
100 - if (widget.scaleByHeight || widget.rebuildFactor(old, data)) {  
101 - _mediaQueryData = data; 159 + if (oldData == null || widget.rebuildFactor(oldData, newData)) {
  160 + setState(() {
  161 + _mediaQueryData = newData;
102 _updateTree(context as Element); 162 _updateTree(context as Element);
  163 + callback?.call();
  164 + });
103 } 165 }
104 } 166 }
105 167
106 @override 168 @override
107 - void didChangeDependencies() {  
108 - super.didChangeDependencies();  
109 - if (_mediaQueryData == null) _mediaQueryData = newData;  
110 - didChangeMetrics();  
111 - } 169 + Widget build(BuildContext context) {
  170 + final mq = _mediaQueryData;
112 171
113 - @override  
114 - void dispose() {  
115 - binding.removeObserver(this);  
116 - super.dispose();  
117 - } 172 + if (mq == null) return const SizedBox.shrink();
118 173
119 - @override  
120 - Widget build(BuildContext _context) {  
121 - if (mediaQueryData.size == Size.zero) return const SizedBox.shrink();  
122 - if (!wrappedInMediaQuery) {  
123 - return MediaQuery(  
124 - data: mediaQueryData,  
125 - child: Builder(  
126 - builder: (__context) {  
127 - ScreenUtil.init(  
128 - __context, 174 + return FutureBuilder<void>(
  175 + future: _screenSizeCompleter.future,
  176 + builder: (c, snapshot) {
  177 + ScreenUtil.configure(
  178 + data: mq,
129 designSize: widget.designSize, 179 designSize: widget.designSize,
130 splitScreenMode: widget.splitScreenMode, 180 splitScreenMode: widget.splitScreenMode,
131 minTextAdapt: widget.minTextAdapt, 181 minTextAdapt: widget.minTextAdapt,
132 - scaleByHeight: widget.scaleByHeight,  
133 - );  
134 - final deviceData = MediaQuery.maybeOf(__context);  
135 - final deviceSize = deviceData?.size ?? widget.designSize;  
136 - return MediaQuery(  
137 - data: MediaQueryData.fromView(View.of(__context)),  
138 - child: Container(  
139 - width: deviceSize.width,  
140 - height: deviceSize.height,  
141 - child: FittedBox(  
142 - fit: BoxFit.none,  
143 - alignment: Alignment.center,  
144 - child: Container(  
145 - width: widget.scaleByHeight  
146 - ? (deviceSize.height * widget.designSize.width) /  
147 - widget.designSize.height  
148 - : deviceSize.width,  
149 - height: deviceSize.height,  
150 - child: widget.builder(__context, widget.child),  
151 - ),  
152 - ),  
153 - ), 182 + fontSizeResolver: widget.fontSizeResolver,
154 ); 183 );
  184 +
  185 + if (snapshot.connectionState == ConnectionState.done) {
  186 + return widget.builder?.call(context, widget.child) ?? widget.child!;
  187 + }
  188 +
  189 + return const SizedBox.shrink();
155 }, 190 },
156 - ),  
157 ); 191 );
158 } 192 }
159 193
160 - ScreenUtil.init(  
161 - _context,  
162 - designSize: widget.designSize,  
163 - splitScreenMode: widget.splitScreenMode,  
164 - minTextAdapt: widget.minTextAdapt,  
165 - scaleByHeight: widget.scaleByHeight,  
166 - );  
167 - final deviceData = MediaQuery.maybeOf(_context);  
168 - final deviceSize = deviceData?.size ?? widget.designSize;  
169 - return Container(  
170 - width: deviceSize.width,  
171 - height: deviceSize.height,  
172 - child: FittedBox(  
173 - fit: BoxFit.none,  
174 - alignment: Alignment.center,  
175 - child: Container(  
176 - width: widget.scaleByHeight  
177 - ? (deviceSize.height * widget.designSize.width) /  
178 - widget.designSize.height  
179 - : deviceSize.width,  
180 - height: deviceSize.height,  
181 - child: widget.builder(_context, widget.child),  
182 - ),  
183 - ),  
184 - ); 194 + @override
  195 + void dispose() {
  196 + _binding.removeObserver(this);
  197 + super.dispose();
185 } 198 }
186 } 199 }
  1 +import 'package:flutter/widgets.dart';
  2 +
  3 +mixin SU on Widget {}
@@ -14,6 +14,12 @@ extension SizeExtension on num { @@ -14,6 +14,12 @@ extension SizeExtension on num {
14 ///[ScreenUtil.radius] 14 ///[ScreenUtil.radius]
15 double get r => ScreenUtil().radius(this); 15 double get r => ScreenUtil().radius(this);
16 16
  17 + ///[ScreenUtil.diagonal]
  18 + double get dg => ScreenUtil().diagonal(this);
  19 +
  20 + ///[ScreenUtil.diameter]
  21 + double get dm => ScreenUtil().diameter(this);
  22 +
17 ///[ScreenUtil.setSp] 23 ///[ScreenUtil.setSp]
18 double get sp => ScreenUtil().setSp(this); 24 double get sp => ScreenUtil().setSp(this);
19 25
@@ -36,22 +42,38 @@ extension SizeExtension on num { @@ -36,22 +42,38 @@ extension SizeExtension on num {
36 double get sh => ScreenUtil().screenHeight * this; 42 double get sh => ScreenUtil().screenHeight * this;
37 43
38 ///[ScreenUtil.setHeight] 44 ///[ScreenUtil.setHeight]
39 - Widget get verticalSpace => ScreenUtil().setVerticalSpacing(this); 45 + SizedBox get verticalSpace => ScreenUtil().setVerticalSpacing(this);
40 46
41 ///[ScreenUtil.setVerticalSpacingFromWidth] 47 ///[ScreenUtil.setVerticalSpacingFromWidth]
42 - Widget get verticalSpaceFromWidth => 48 + SizedBox get verticalSpaceFromWidth =>
43 ScreenUtil().setVerticalSpacingFromWidth(this); 49 ScreenUtil().setVerticalSpacingFromWidth(this);
44 50
45 ///[ScreenUtil.setWidth] 51 ///[ScreenUtil.setWidth]
46 - Widget get horizontalSpace => ScreenUtil().setHorizontalSpacing(this); 52 + SizedBox get horizontalSpace => ScreenUtil().setHorizontalSpacing(this);
47 53
48 ///[ScreenUtil.radius] 54 ///[ScreenUtil.radius]
49 - Widget get horizontalSpaceRadius => 55 + SizedBox get horizontalSpaceRadius =>
50 ScreenUtil().setHorizontalSpacingRadius(this); 56 ScreenUtil().setHorizontalSpacingRadius(this);
51 57
52 ///[ScreenUtil.radius] 58 ///[ScreenUtil.radius]
53 - Widget get verticalSpacingRadius => 59 + SizedBox get verticalSpacingRadius =>
54 ScreenUtil().setVerticalSpacingRadius(this); 60 ScreenUtil().setVerticalSpacingRadius(this);
  61 +
  62 + ///[ScreenUtil.diameter]
  63 + SizedBox get horizontalSpaceDiameter =>
  64 + ScreenUtil().setHorizontalSpacingDiameter(this);
  65 +
  66 + ///[ScreenUtil.diameter]
  67 + SizedBox get verticalSpacingDiameter =>
  68 + ScreenUtil().setVerticalSpacingDiameter(this);
  69 +
  70 + ///[ScreenUtil.diagonal]
  71 + SizedBox get horizontalSpaceDiagonal =>
  72 + ScreenUtil().setHorizontalSpacingDiagonal(this);
  73 +
  74 + ///[ScreenUtil.diagonal]
  75 + SizedBox get verticalSpacingDiagonal =>
  76 + ScreenUtil().setVerticalSpacingDiagonal(this);
55 } 77 }
56 78
57 extension EdgeInsetsExtension on EdgeInsets { 79 extension EdgeInsetsExtension on EdgeInsets {
@@ -63,6 +85,20 @@ extension EdgeInsetsExtension on EdgeInsets { @@ -63,6 +85,20 @@ extension EdgeInsetsExtension on EdgeInsets {
63 left: left.r, 85 left: left.r,
64 ); 86 );
65 87
  88 + EdgeInsets get dm => copyWith(
  89 + top: top.dm,
  90 + bottom: bottom.dm,
  91 + right: right.dm,
  92 + left: left.dm,
  93 + );
  94 +
  95 + EdgeInsets get dg => copyWith(
  96 + top: top.dg,
  97 + bottom: bottom.dg,
  98 + right: right.dg,
  99 + left: left.dg,
  100 + );
  101 +
66 EdgeInsets get w => copyWith( 102 EdgeInsets get w => copyWith(
67 top: top.w, 103 top: top.w,
68 bottom: bottom.w, 104 bottom: bottom.w,
@@ -106,6 +142,10 @@ extension RaduisExtension on Radius { @@ -106,6 +142,10 @@ extension RaduisExtension on Radius {
106 /// Creates adapt Radius using r [SizeExtension]. 142 /// Creates adapt Radius using r [SizeExtension].
107 Radius get r => Radius.elliptical(x.r, y.r); 143 Radius get r => Radius.elliptical(x.r, y.r);
108 144
  145 + Radius get dm => Radius.elliptical(x.dm, y.dm);
  146 +
  147 + Radius get dg => Radius.elliptical(x.dg, y.dg);
  148 +
109 Radius get w => Radius.elliptical(x.w, y.w); 149 Radius get w => Radius.elliptical(x.w, y.w);
110 150
111 Radius get h => Radius.elliptical(x.h, y.h); 151 Radius get h => Radius.elliptical(x.h, y.h);
1 name: flutter_screenutil 1 name: flutter_screenutil
2 description: A flutter plugin for adapting screen and font size.Guaranteed to look good on different models 2 description: A flutter plugin for adapting screen and font size.Guaranteed to look good on different models
3 -version: 5.8.4 3 +version: 5.9.0-beta
4 homepage: https://github.com/OpenFlutter/flutter_screenutil 4 homepage: https://github.com/OpenFlutter/flutter_screenutil
5 5
6 environment: 6 environment:
7 - sdk: ">=2.12.0 <4.0.0" 7 + sdk: ">=2.17.0 <4.0.0"
8 flutter: ">=3.10.0" 8 flutter: ">=3.10.0"
9 9
10 dependencies: 10 dependencies:
  1 +import 'package:flutter/material.dart';
  2 +import 'package:flutter_screenutil/flutter_screenutil.dart';
  3 +import 'package:flutter_test/flutter_test.dart';
  4 +
  5 +import 'home.test.dart';
  6 +
  7 +void main() {
  8 + const smallerDeviceSize = Size(300, 600);
  9 + const smallerDeviceData = MediaQueryData(size: smallerDeviceSize);
  10 +
  11 + const biggerDeviceSize = Size(500, 900);
  12 + const biggerDeviceData = MediaQueryData(size: biggerDeviceSize);
  13 +
  14 + const uiSize = Size(470, 740);
  15 +
  16 + group('[Test calculations]', () {
  17 + test('Test smaller size', () {
  18 + ScreenUtil.configure(
  19 + data: smallerDeviceData,
  20 + designSize: uiSize,
  21 + minTextAdapt: true,
  22 + splitScreenMode: false,
  23 + );
  24 +
  25 + expect(1.w, smallerDeviceSize.width / uiSize.width);
  26 + expect(1.w < 1, true);
  27 + expect(1.h, smallerDeviceSize.height / uiSize.height);
  28 + expect(1.h < 1, true);
  29 + });
  30 +
  31 + test('Test bigger size', () {
  32 + ScreenUtil.configure(
  33 + data: biggerDeviceData,
  34 + designSize: uiSize,
  35 + minTextAdapt: true,
  36 + splitScreenMode: false,
  37 + );
  38 +
  39 + expect(1.w, biggerDeviceSize.width / uiSize.width);
  40 + expect(1.w > 1, true);
  41 + expect(1.h, biggerDeviceSize.height / uiSize.height);
  42 + expect(1.h > 1, true);
  43 + });
  44 + });
  45 +
  46 + group('[Test overflow]', () {
  47 + testWidgets('Test overflow width', (tester) async {
  48 + await tester.pumpWidget(ScreenUtilInit(
  49 + designSize: uiSize,
  50 + child: MaterialApp(home: WidgetTest(width: () => uiSize.width.w)),
  51 + ));
  52 +
  53 + // Wait until all widget rendered
  54 + await tester.pumpAndSettle();
  55 +
  56 + // a Text widget must be present
  57 + expect(find.text('Test'), findsOneWidget);
  58 + });
  59 +
  60 + testWidgets('Test overflow height', (tester) async {
  61 + await tester.pumpWidget(ScreenUtilInit(
  62 + designSize: uiSize,
  63 + child: MaterialApp(home: WidgetTest(height: () => uiSize.height.h)),
  64 + ));
  65 +
  66 + // Wait until all widget rendered
  67 + await tester.pumpAndSettle();
  68 +
  69 + // a Text widget must be present
  70 + expect(find.text('Test'), findsOneWidget);
  71 + });
  72 + });
  73 +
  74 + testWidgets('[Rebuilding]', (tester) async {
  75 + final textFieldKey = UniqueKey();
  76 + final buildCountNotifier = ValueNotifier(0);
  77 + final focusNode = FocusNode();
  78 +
  79 + Finder textField() => find.byKey(textFieldKey);
  80 +
  81 + await tester.pumpWidget(ScreenUtilInit(
  82 + designSize: uiSize,
  83 + rebuildFactor: RebuildFactors.always,
  84 + child: MaterialApp(
  85 + home: Scaffold(
  86 + body: Builder(
  87 + builder: (context) {
  88 + buildCountNotifier.value += 1;
  89 +
  90 + assert(uiSize.width.w == MediaQuery.of(context).size.width);
  91 +
  92 + return SizedBox(
  93 + width: 1.sw,
  94 + child: Column(
  95 + children: [
  96 + ValueListenableBuilder<int>(
  97 + valueListenable: buildCountNotifier,
  98 + builder: (_, count, __) => Text('Built count: $count'),
  99 + ),
  100 + TextField(
  101 + key: textFieldKey,
  102 + focusNode: focusNode,
  103 + ),
  104 + ],
  105 + ),
  106 + );
  107 + },
  108 + ),
  109 + ),
  110 + ),
  111 + ));
  112 +
  113 + await tester.pumpAndSettle();
  114 + expect(buildCountNotifier.value, 1);
  115 +
  116 + expect(textField(), findsOneWidget);
  117 + expect(focusNode.hasFocus, false);
  118 +
  119 + await tester.tap(textField()).then((_) => tester.pumpAndSettle());
  120 + expect(textField(), findsOneWidget);
  121 + expect(focusNode.hasFocus, true);
  122 + expect(buildCountNotifier.value, 1);
  123 +
  124 + // Simulate keyboard
  125 + tester.view.viewInsets = FakeViewPadding(bottom: 20);
  126 +
  127 + await tester.pumpAndSettle();
  128 + expect(focusNode.hasFocus, true);
  129 + expect(buildCountNotifier.value, 1);
  130 + });
  131 +}
  1 +import 'package:flutter/widgets.dart';
  2 +
  3 +class WidgetTest extends StatelessWidget {
  4 + const WidgetTest({
  5 + super.key,
  6 + this.width = _zero,
  7 + this.height = _zero,
  8 + });
  9 +
  10 + final double Function() width;
  11 + final double Function() height;
  12 +
  13 + @override
  14 + Widget build(BuildContext context) {
  15 + return LayoutBuilder(
  16 + builder: (_, c) {
  17 + final w = width(), h = height();
  18 +
  19 + if (c.biggest >= Size(w, h)) {
  20 + return const Text('Test');
  21 + }
  22 +
  23 + throw Error();
  24 + },
  25 + );
  26 + }
  27 +
  28 + static double _zero() => 0;
  29 +}