Some fixes & adding rebuildFactor
Performance tip: rebuildFactor is for those who want to set some breakpoints or to rebuild based on steps
Showing
3 changed files
with
150 additions
and
65 deletions
@@ -16,12 +16,12 @@ class MyApp extends StatelessWidget { | @@ -16,12 +16,12 @@ class MyApp extends StatelessWidget { | ||
16 | // You can use the library anywhere in the app even in theme | 16 | // You can use the library anywhere in the app even in theme |
17 | theme: ThemeData( | 17 | theme: ThemeData( |
18 | primarySwatch: Colors.blue, | 18 | primarySwatch: Colors.blue, |
19 | - textTheme: TextTheme(bodyText2: TextStyle(fontSize: 16.sp)), | 19 | + textTheme: Typography.englishLike2018.apply(fontSizeFactor: 1.sp), |
20 | ), | 20 | ), |
21 | home: child, | 21 | home: child, |
22 | ); | 22 | ); |
23 | }, | 23 | }, |
24 | - child: HomePage(title: 'First Method'), | 24 | + child: const HomePage(title: 'First Method'), |
25 | ); | 25 | ); |
26 | } | 26 | } |
27 | } | 27 | } |
@@ -24,7 +24,7 @@ class HomePageScaffold extends StatelessWidget { | @@ -24,7 +24,7 @@ class HomePageScaffold extends StatelessWidget { | ||
24 | printScreenInformation(); | 24 | printScreenInformation(); |
25 | 25 | ||
26 | /// Uncomment if you wanna force current widget to be rebuilt with updated values | 26 | /// Uncomment if you wanna force current widget to be rebuilt with updated values |
27 | - /// Use it only if you use the second method, or if you use ScreenUtilInit's child. | 27 | + /// Must use it if you use the second method, or if you use ScreenUtilInit's child. |
28 | /// Note: don't use it along with ScreenUtil.init() | 28 | /// Note: don't use it along with ScreenUtil.init() |
29 | // ScreenUtil.registerToBuild(context); | 29 | // ScreenUtil.registerToBuild(context); |
30 | return Scaffold( | 30 | return Scaffold( |
@@ -82,38 +82,54 @@ class HomePageScaffold extends StatelessWidget { | @@ -82,38 +82,54 @@ class HomePageScaffold extends StatelessWidget { | ||
82 | ), | 82 | ), |
83 | ), | 83 | ), |
84 | ), | 84 | ), |
85 | - Text('Device width:${ScreenUtil().screenWidth}dp'), | ||
86 | - Text('Device height:${ScreenUtil().screenHeight}dp'), | ||
87 | - Text('Device pixel density:${ScreenUtil().pixelRatio}'), | ||
88 | - Text('Bottom safe zone distance:${ScreenUtil().bottomBarHeight}dp'), | ||
89 | - Text('Status bar height:${ScreenUtil().statusBarHeight}dp'), | ||
90 | - Text( | ||
91 | - 'The ratio of actual width to UI design:${ScreenUtil().scaleWidth}'), | ||
92 | - Text( | ||
93 | - 'The ratio of actual height to UI design:${ScreenUtil().scaleHeight}'), | ||
94 | - 10.verticalSpace, | ||
95 | - Text('System font scaling factor:${ScreenUtil().textScaleFactor}'), | ||
96 | - 5.verticalSpace, | ||
97 | - Column( | ||
98 | - crossAxisAlignment: CrossAxisAlignment.start, | ||
99 | - children: <Widget>[ | ||
100 | - Text( | ||
101 | - '16sp, will not change with the system.', | ||
102 | - style: TextStyle( | ||
103 | - color: Colors.black, | ||
104 | - fontSize: 16.sp, | 85 | + Padding( |
86 | + padding: const EdgeInsets.all(18).r, | ||
87 | + child: Column( | ||
88 | + crossAxisAlignment: CrossAxisAlignment.stretch, | ||
89 | + children: [ | ||
90 | + TextField( | ||
91 | + decoration: InputDecoration( | ||
92 | + border: OutlineInputBorder(), | ||
93 | + ), | ||
105 | ), | 94 | ), |
106 | - textScaleFactor: 1.0, | ||
107 | - ), | ||
108 | - Text( | ||
109 | - '16sp,if data is not set in MediaQuery,my font size will change with the system.', | ||
110 | - style: TextStyle( | ||
111 | - color: Colors.black, | ||
112 | - fontSize: 16.sp, | 95 | + 18.verticalSpace, |
96 | + Text('Device width:${ScreenUtil().screenWidth}dp'), | ||
97 | + Text('Device height:${ScreenUtil().screenHeight}dp'), | ||
98 | + Text('Device pixel density:${ScreenUtil().pixelRatio}'), | ||
99 | + Text( | ||
100 | + 'Bottom safe zone distance:${ScreenUtil().bottomBarHeight}dp'), | ||
101 | + Text('Status bar height:${ScreenUtil().statusBarHeight}dp'), | ||
102 | + Text( | ||
103 | + 'The ratio of actual width to UI design:${ScreenUtil().scaleWidth}'), | ||
104 | + Text( | ||
105 | + 'The ratio of actual height to UI design:${ScreenUtil().scaleHeight}'), | ||
106 | + 10.verticalSpace, | ||
107 | + Text( | ||
108 | + 'System font scaling factor:${ScreenUtil().textScaleFactor}'), | ||
109 | + 5.verticalSpace, | ||
110 | + Column( | ||
111 | + crossAxisAlignment: CrossAxisAlignment.stretch, | ||
112 | + children: <Widget>[ | ||
113 | + Text( | ||
114 | + '16sp, will not change with the system.', | ||
115 | + style: TextStyle( | ||
116 | + color: Colors.black, | ||
117 | + fontSize: 16.sp, | ||
118 | + ), | ||
119 | + textScaleFactor: 1.0, | ||
120 | + ), | ||
121 | + Text( | ||
122 | + '16sp,if data is not set in MediaQuery,my font size will change with the system.', | ||
123 | + style: TextStyle( | ||
124 | + color: Colors.black, | ||
125 | + fontSize: 16.sp, | ||
126 | + ), | ||
127 | + ), | ||
128 | + ], | ||
113 | ), | 129 | ), |
114 | - ), | ||
115 | - ], | ||
116 | - ) | 130 | + ], |
131 | + ), | ||
132 | + ), | ||
117 | ], | 133 | ], |
118 | ), | 134 | ), |
119 | ), | 135 | ), |
@@ -2,15 +2,21 @@ import 'package:flutter/widgets.dart'; | @@ -2,15 +2,21 @@ import 'package:flutter/widgets.dart'; | ||
2 | 2 | ||
3 | import 'screen_util.dart'; | 3 | import 'screen_util.dart'; |
4 | 4 | ||
5 | -class ScreenUtilInit extends StatelessWidget { | 5 | +typedef RebuildFactor = bool Function(MediaQueryData old, MediaQueryData data); |
6 | + | ||
7 | +bool defaultRebuildFactor(old, data) => old.size != data.size; | ||
8 | + | ||
9 | +class ScreenUtilInit extends StatefulWidget { | ||
6 | /// A helper widget that initializes [ScreenUtil] | 10 | /// A helper widget that initializes [ScreenUtil] |
7 | const ScreenUtilInit({ | 11 | const ScreenUtilInit({ |
12 | + Key? key, | ||
8 | this.builder, | 13 | this.builder, |
9 | this.child, | 14 | this.child, |
15 | + this.rebuildFactor = defaultRebuildFactor, | ||
10 | this.designSize = ScreenUtil.defaultSize, | 16 | this.designSize = ScreenUtil.defaultSize, |
11 | this.splitScreenMode = false, | 17 | this.splitScreenMode = false, |
12 | this.minTextAdapt = false, | 18 | this.minTextAdapt = false, |
13 | - Key? key, | 19 | + this.useInheritedMediaQuery = false, |
14 | }) : assert( | 20 | }) : assert( |
15 | builder != null || child != null, | 21 | builder != null || child != null, |
16 | 'You must either pass builder or child or both', | 22 | 'You must either pass builder or child or both', |
@@ -21,43 +27,106 @@ class ScreenUtilInit extends StatelessWidget { | @@ -21,43 +27,106 @@ class ScreenUtilInit extends StatelessWidget { | ||
21 | final Widget? child; | 27 | final Widget? child; |
22 | final bool splitScreenMode; | 28 | final bool splitScreenMode; |
23 | final bool minTextAdapt; | 29 | final bool minTextAdapt; |
30 | + final bool useInheritedMediaQuery; | ||
31 | + final RebuildFactor rebuildFactor; | ||
24 | 32 | ||
25 | /// The [Size] of the device in the design draft, in dp | 33 | /// The [Size] of the device in the design draft, in dp |
26 | final Size designSize; | 34 | final Size designSize; |
27 | 35 | ||
28 | @override | 36 | @override |
29 | - Widget build(BuildContext context) { | ||
30 | - bool firstFrameAllowed = false; | ||
31 | - final binding = WidgetsFlutterBinding.ensureInitialized(); | ||
32 | - binding.deferFirstFrame(); | ||
33 | - | ||
34 | - final rootMediaQueryData = (context | ||
35 | - .getElementForInheritedWidgetOfExactType<MediaQuery>() | ||
36 | - ?.widget as MediaQuery?) | ||
37 | - ?.data; | ||
38 | - | ||
39 | - return LayoutBuilder( | ||
40 | - builder: (_, constraints) { | ||
41 | - if (constraints.biggest == Size.zero) return const SizedBox.shrink(); | ||
42 | - | ||
43 | - if (!firstFrameAllowed) { | ||
44 | - binding.allowFirstFrame(); | ||
45 | - firstFrameAllowed = true; | ||
46 | - } | ||
47 | - | ||
48 | - return MediaQuery( | ||
49 | - data: rootMediaQueryData ?? MediaQueryData.fromWindow(binding.window), | ||
50 | - child: Builder(builder: (_context) { | 37 | + State<ScreenUtilInit> createState() => _ScreenUtilInitState(); |
38 | +} | ||
39 | + | ||
40 | +class _ScreenUtilInitState extends State<ScreenUtilInit> | ||
41 | + with WidgetsBindingObserver { | ||
42 | + late MediaQueryData mediaQueryData; | ||
43 | + bool wrappedInMediaQuery = false; | ||
44 | + | ||
45 | + WidgetsBinding get binding => WidgetsFlutterBinding.ensureInitialized(); | ||
46 | + | ||
47 | + MediaQueryData get newData { | ||
48 | + if (widget.useInheritedMediaQuery) { | ||
49 | + final el = context.getElementForInheritedWidgetOfExactType<MediaQuery>(); | ||
50 | + final mq = el?.widget as MediaQuery?; | ||
51 | + final data = mq?.data; | ||
52 | + | ||
53 | + if (data != null) { | ||
54 | + wrappedInMediaQuery = true; | ||
55 | + return data; | ||
56 | + } | ||
57 | + } | ||
58 | + | ||
59 | + return MediaQueryData.fromWindow(binding.window); | ||
60 | + } | ||
61 | + | ||
62 | + Widget get child { | ||
63 | + return SizedBox( | ||
64 | + key: GlobalObjectKey( | ||
65 | + hashValues( | ||
66 | + mediaQueryData.size.width, | ||
67 | + mediaQueryData.size.height, | ||
68 | + ), | ||
69 | + ), | ||
70 | + child: widget.builder?.call(widget.child) ?? widget.child!, | ||
71 | + ); | ||
72 | + } | ||
73 | + | ||
74 | + @override | ||
75 | + void initState() { | ||
76 | + super.initState(); | ||
77 | + mediaQueryData = newData; | ||
78 | + binding.addObserver(this); | ||
79 | + } | ||
80 | + | ||
81 | + @override | ||
82 | + void didChangeMetrics() { | ||
83 | + final old = mediaQueryData; | ||
84 | + final data = newData; | ||
85 | + | ||
86 | + if (widget.rebuildFactor(old, data)) setState(() => mediaQueryData = data); | ||
87 | + } | ||
88 | + | ||
89 | + @override | ||
90 | + void didChangeDependencies() { | ||
91 | + super.didChangeDependencies(); | ||
92 | + didChangeMetrics(); | ||
93 | + } | ||
94 | + | ||
95 | + @override | ||
96 | + void dispose() { | ||
97 | + binding.removeObserver(this); | ||
98 | + super.dispose(); | ||
99 | + } | ||
100 | + | ||
101 | + @override | ||
102 | + Widget build(BuildContext _context) { | ||
103 | + if (mediaQueryData.size == Size.zero) return const SizedBox.shrink(); | ||
104 | + | ||
105 | + if (!wrappedInMediaQuery) { | ||
106 | + return MediaQuery( | ||
107 | + // key: GlobalObjectKey('mediaQuery'), | ||
108 | + data: mediaQueryData, | ||
109 | + child: Builder( | ||
110 | + builder: (__context) { | ||
51 | ScreenUtil.init( | 111 | ScreenUtil.init( |
52 | - _context, | ||
53 | - designSize: designSize, | ||
54 | - splitScreenMode: splitScreenMode, | ||
55 | - minTextAdapt: minTextAdapt, | 112 | + __context, |
113 | + designSize: widget.designSize, | ||
114 | + splitScreenMode: widget.splitScreenMode, | ||
115 | + minTextAdapt: widget.minTextAdapt, | ||
56 | ); | 116 | ); |
57 | - return builder?.call(child) ?? child!; | ||
58 | - }), | ||
59 | - ); | ||
60 | - }, | 117 | + return child; |
118 | + }, | ||
119 | + ), | ||
120 | + ); | ||
121 | + } | ||
122 | + | ||
123 | + ScreenUtil.init( | ||
124 | + _context, | ||
125 | + designSize: widget.designSize, | ||
126 | + splitScreenMode: widget.splitScreenMode, | ||
127 | + minTextAdapt: widget.minTextAdapt, | ||
61 | ); | 128 | ); |
129 | + | ||
130 | + return child; | ||
62 | } | 131 | } |
63 | } | 132 | } |
-
Please register or login to post a comment