Mounir-Bouaiche

Bug Fix: Assertion Failed (Find MediaQuery in ancestors)

1 -import 'package:flutter/widgets.dart'; 1 +/*import 'package:flutter/widgets.dart';
2 import 'src/first_method.dart' as firstMethod; 2 import 'src/first_method.dart' as firstMethod;
3 import 'src/second_method.dart' as secondMethod; 3 import 'src/second_method.dart' as secondMethod;
4 4
@@ -6,3 +6,106 @@ void main() { @@ -6,3 +6,106 @@ void main() {
6 const method = int.fromEnvironment('method', defaultValue: 1); 6 const method = int.fromEnvironment('method', defaultValue: 1);
7 runApp(method == 1 ? firstMethod.MyApp() : secondMethod.MyApp()); 7 runApp(method == 1 ? firstMethod.MyApp() : secondMethod.MyApp());
8 } 8 }
  9 +*/
  10 +
  11 +import 'dart:async';
  12 +
  13 +import 'package:flutter/material.dart';
  14 +import 'package:flutter_screenutil/flutter_screenutil.dart';
  15 +
  16 +void main() {
  17 + runApp(ScreenUtilInit(
  18 + builder: (child) => MaterialApp(
  19 + key: GlobalObjectKey('screenutil'),
  20 + theme: ThemeData(
  21 + textTheme: TextTheme(
  22 + bodyText2: TextStyle(fontSize: 32.sp),
  23 + ),
  24 + ),
  25 + home: child,
  26 + ),
  27 + child: ThirdPage(),
  28 + ));
  29 +}
  30 +
  31 +class MyStatelessElement<T extends TestPage> extends StatelessElement {
  32 + MyStatelessElement(T widget) : super(widget);
  33 +
  34 + @override
  35 + T get widget => super.widget as T;
  36 +
  37 + @override
  38 + void mount(Element? parent, Object? newSlot) {
  39 + super.mount(parent, newSlot);
  40 + print('${widget.text()} is mounted');
  41 + }
  42 +
  43 + @override
  44 + void unmount() {
  45 + print('${widget.text()} is unmounted');
  46 + super.unmount();
  47 + }
  48 +}
  49 +
  50 +abstract class TestPage extends StatelessWidget {
  51 + String text() => runtimeType.toString();
  52 +
  53 + Widget goto();
  54 +
  55 + @override
  56 + StatelessElement createElement() => MyStatelessElement(this);
  57 +
  58 + @override
  59 + Widget build(BuildContext context) {
  60 + Timer(const Duration(seconds: 5), () {
  61 + Navigator.of(context).pushAndRemoveUntil(
  62 + MaterialPageRoute(builder: (context) => goto()),
  63 + (route) => false,
  64 + );
  65 + });
  66 + return Scaffold(
  67 + body: SafeArea(
  68 + child: Padding(
  69 + padding: const EdgeInsets.all(20).r,
  70 + child: Column(
  71 + mainAxisSize: MainAxisSize.min,
  72 + children: [
  73 + TextField(),
  74 + Text(
  75 + text(),
  76 + style: TextStyle(fontSize: 32.sp),
  77 + ),
  78 + Text(text()),
  79 + Expanded(
  80 + child: ListView.separated(
  81 + shrinkWrap: true,
  82 + itemBuilder: (context, index) => Text('$index'),
  83 + separatorBuilder: (_, __) => Container(
  84 + height: 50.h,
  85 + color: Colors.green,
  86 + ),
  87 + itemCount: 10,
  88 + ),
  89 + ),
  90 + ],
  91 + ),
  92 + ),
  93 + ),
  94 + );
  95 + }
  96 +}
  97 +
  98 +class FirstPage extends TestPage {
  99 + @override
  100 + Widget goto() => SecondPage();
  101 +}
  102 +
  103 +class SecondPage extends TestPage {
  104 + @override
  105 + Widget goto() => FirstPage();
  106 +}
  107 +
  108 +class ThirdPage extends TestPage {
  109 + @override
  110 + Widget goto() => FirstPage();
  111 +}
@@ -9,20 +9,19 @@ class MyApp extends StatelessWidget { @@ -9,20 +9,19 @@ class MyApp extends StatelessWidget {
9 Widget build(BuildContext context) { 9 Widget build(BuildContext context) {
10 // In first method you only need to wrap [MaterialApp] with [ScreenUtilInit] and that's it 10 // In first method you only need to wrap [MaterialApp] with [ScreenUtilInit] and that's it
11 return ScreenUtilInit( 11 return ScreenUtilInit(
12 - builder: (context) { 12 + builder: (child) {
13 return MaterialApp( 13 return MaterialApp(
14 debugShowCheckedModeBanner: false, 14 debugShowCheckedModeBanner: false,
15 - // Use this line to prevent extra rebuilds  
16 - useInheritedMediaQuery: true,  
17 title: 'First Method', 15 title: 'First Method',
18 // 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
19 theme: ThemeData( 17 theme: ThemeData(
20 primarySwatch: Colors.blue, 18 primarySwatch: Colors.blue,
21 textTheme: TextTheme(bodyText2: TextStyle(fontSize: 16.sp)), 19 textTheme: TextTheme(bodyText2: TextStyle(fontSize: 16.sp)),
22 ), 20 ),
23 - home: HomePage(title: 'First Method'), 21 + home: child,
24 ); 22 );
25 }, 23 },
  24 + child: HomePage(title: 'First Method'),
26 ); 25 );
27 } 26 }
28 } 27 }
@@ -9,7 +9,7 @@ class MyApp extends StatelessWidget { @@ -9,7 +9,7 @@ class MyApp extends StatelessWidget {
9 Widget build(BuildContext context) { 9 Widget build(BuildContext context) {
10 // In first method you only need to wrap [MaterialApp] with [ScreenUtilInit] and that's it 10 // In first method you only need to wrap [MaterialApp] with [ScreenUtilInit] and that's it
11 return ScreenUtilInit( 11 return ScreenUtilInit(
12 - builder: (context) { 12 + builder: (child) {
13 return MaterialApp( 13 return MaterialApp(
14 debugShowCheckedModeBanner: false, 14 debugShowCheckedModeBanner: false,
15 title: '第一种方法', 15 title: '第一种方法',
@@ -18,9 +18,10 @@ class MyApp extends StatelessWidget { @@ -18,9 +18,10 @@ class MyApp extends StatelessWidget {
18 primarySwatch: Colors.blue, 18 primarySwatch: Colors.blue,
19 textTheme: TextTheme(bodyText2: TextStyle(fontSize: 30.sp)), 19 textTheme: TextTheme(bodyText2: TextStyle(fontSize: 30.sp)),
20 ), 20 ),
21 - home: HomePage(title: '第一种方法'), 21 + home: child,
22 ); 22 );
23 }, 23 },
  24 + child: HomePage(title: '第一种方法'),
24 ); 25 );
25 } 26 }
26 } 27 }
@@ -69,8 +69,19 @@ class ScreenUtil { @@ -69,8 +69,19 @@ class ScreenUtil {
69 } 69 }
70 } 70 }
71 71
72 - static void setContext(BuildContext context) {  
73 - _instance.context = context; 72 + /// ### Experimental
  73 + /// Register current page and all its descendants to rebuild
  74 + /// Helpful when building for web and desktop
  75 + static void registerToBuild(
  76 + BuildContext context, [
  77 + bool withDescendants = false,
  78 + ]) {
  79 + MediaQuery.maybeOf(context);
  80 + if (withDescendants) {
  81 + (context as Element).visitChildren((element) {
  82 + registerToBuild(element, true);
  83 + });
  84 + }
74 } 85 }
75 86
76 /// Initializing the library. 87 /// Initializing the library.
@@ -89,6 +100,8 @@ class ScreenUtil { @@ -89,6 +100,8 @@ class ScreenUtil {
89 ? MediaQuery.of(context!).nonEmptySizeOrNull() 100 ? MediaQuery.of(context!).nonEmptySizeOrNull()
90 : null; 101 : null;
91 102
  103 + mediaQueryContext?.visitChildren((el) => context = el);
  104 +
92 deviceSize ??= deviceData?.size ?? designSize; 105 deviceSize ??= deviceData?.size ?? designSize;
93 orientation ??= deviceData?.orientation ?? 106 orientation ??= deviceData?.orientation ??
94 (deviceSize.width > deviceSize.height 107 (deviceSize.width > deviceSize.height
@@ -102,7 +115,7 @@ class ScreenUtil { @@ -102,7 +115,7 @@ class ScreenUtil {
102 .._orientation = orientation 115 .._orientation = orientation
103 .._screenWidth = deviceSize.width 116 .._screenWidth = deviceSize.width
104 .._screenHeight = deviceSize.height 117 .._screenHeight = deviceSize.height
105 - ..context = mediaQueryContext; 118 + ..context = mediaQueryContext != null ? context : null;
106 } 119 }
107 120
108 ///获取屏幕方向 121 ///获取屏幕方向
@@ -6,14 +6,16 @@ import 'screen_util.dart'; @@ -6,14 +6,16 @@ import 'screen_util.dart';
6 class ScreenUtilInit extends StatelessWidget { 6 class ScreenUtilInit extends StatelessWidget {
7 /// A helper widget that initializes [ScreenUtil] 7 /// A helper widget that initializes [ScreenUtil]
8 const ScreenUtilInit({ 8 const ScreenUtilInit({
9 - required this.builder, 9 + this.builder,
  10 + this.child,
10 this.designSize = ScreenUtil.defaultSize, 11 this.designSize = ScreenUtil.defaultSize,
11 this.splitScreenMode = false, 12 this.splitScreenMode = false,
12 this.minTextAdapt = false, 13 this.minTextAdapt = false,
13 Key? key, 14 Key? key,
14 }) : super(key: key); 15 }) : super(key: key);
15 16
16 - final WidgetBuilder builder; 17 + final Widget Function(Widget? child)? builder;
  18 + final Widget? child;
17 final bool splitScreenMode; 19 final bool splitScreenMode;
18 final bool minTextAdapt; 20 final bool minTextAdapt;
19 21
@@ -25,11 +27,13 @@ class ScreenUtilInit extends StatelessWidget { @@ -25,11 +27,13 @@ class ScreenUtilInit extends StatelessWidget {
25 bool firstFrameAllowed = false; 27 bool firstFrameAllowed = false;
26 RendererBinding.instance!.deferFirstFrame(); 28 RendererBinding.instance!.deferFirstFrame();
27 29
28 - return MediaQuery.fromWindow(  
29 - child: Builder(builder: (context) {  
30 - if (MediaQuery.of(context).size == Size.zero) return const SizedBox(); 30 + return LayoutBuilder(
  31 + builder: (context, constraints) {
  32 + if (constraints.biggest == Size.zero) return const SizedBox.shrink();
  33 +
31 ScreenUtil.init( 34 ScreenUtil.init(
32 - context, 35 + null,
  36 + deviceSize: constraints.biggest,
33 designSize: designSize, 37 designSize: designSize,
34 splitScreenMode: splitScreenMode, 38 splitScreenMode: splitScreenMode,
35 minTextAdapt: minTextAdapt, 39 minTextAdapt: minTextAdapt,
@@ -40,8 +44,8 @@ class ScreenUtilInit extends StatelessWidget { @@ -40,8 +44,8 @@ class ScreenUtilInit extends StatelessWidget {
40 firstFrameAllowed = true; 44 firstFrameAllowed = true;
41 } 45 }
42 46
43 - return builder(context);  
44 - }), 47 + return builder?.call(child) ?? child!;
  48 + },
45 ); 49 );
46 } 50 }
47 } 51 }