Mounir-Bouaiche

Some fixes & adding rebuildFactor

Performance tip: rebuildFactor is for those who want to set some breakpoints or to rebuild based on steps
... ... @@ -16,12 +16,12 @@ class MyApp extends StatelessWidget {
// You can use the library anywhere in the app even in theme
theme: ThemeData(
primarySwatch: Colors.blue,
textTheme: TextTheme(bodyText2: TextStyle(fontSize: 16.sp)),
textTheme: Typography.englishLike2018.apply(fontSizeFactor: 1.sp),
),
home: child,
);
},
child: HomePage(title: 'First Method'),
child: const HomePage(title: 'First Method'),
);
}
}
... ...
... ... @@ -24,7 +24,7 @@ class HomePageScaffold extends StatelessWidget {
printScreenInformation();
/// Uncomment if you wanna force current widget to be rebuilt with updated values
/// Use it only if you use the second method, or if you use ScreenUtilInit's child.
/// Must use it if you use the second method, or if you use ScreenUtilInit's child.
/// Note: don't use it along with ScreenUtil.init()
// ScreenUtil.registerToBuild(context);
return Scaffold(
... ... @@ -82,38 +82,54 @@ class HomePageScaffold extends StatelessWidget {
),
),
),
Text('Device width:${ScreenUtil().screenWidth}dp'),
Text('Device height:${ScreenUtil().screenHeight}dp'),
Text('Device pixel density:${ScreenUtil().pixelRatio}'),
Text('Bottom safe zone distance:${ScreenUtil().bottomBarHeight}dp'),
Text('Status bar height:${ScreenUtil().statusBarHeight}dp'),
Text(
'The ratio of actual width to UI design:${ScreenUtil().scaleWidth}'),
Text(
'The ratio of actual height to UI design:${ScreenUtil().scaleHeight}'),
10.verticalSpace,
Text('System font scaling factor:${ScreenUtil().textScaleFactor}'),
5.verticalSpace,
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'16sp, will not change with the system.',
style: TextStyle(
color: Colors.black,
fontSize: 16.sp,
Padding(
padding: const EdgeInsets.all(18).r,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
TextField(
decoration: InputDecoration(
border: OutlineInputBorder(),
),
),
textScaleFactor: 1.0,
),
Text(
'16sp,if data is not set in MediaQuery,my font size will change with the system.',
style: TextStyle(
color: Colors.black,
fontSize: 16.sp,
18.verticalSpace,
Text('Device width:${ScreenUtil().screenWidth}dp'),
Text('Device height:${ScreenUtil().screenHeight}dp'),
Text('Device pixel density:${ScreenUtil().pixelRatio}'),
Text(
'Bottom safe zone distance:${ScreenUtil().bottomBarHeight}dp'),
Text('Status bar height:${ScreenUtil().statusBarHeight}dp'),
Text(
'The ratio of actual width to UI design:${ScreenUtil().scaleWidth}'),
Text(
'The ratio of actual height to UI design:${ScreenUtil().scaleHeight}'),
10.verticalSpace,
Text(
'System font scaling factor:${ScreenUtil().textScaleFactor}'),
5.verticalSpace,
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Text(
'16sp, will not change with the system.',
style: TextStyle(
color: Colors.black,
fontSize: 16.sp,
),
textScaleFactor: 1.0,
),
Text(
'16sp,if data is not set in MediaQuery,my font size will change with the system.',
style: TextStyle(
color: Colors.black,
fontSize: 16.sp,
),
),
],
),
),
],
)
],
),
),
],
),
),
... ...
... ... @@ -2,15 +2,21 @@ import 'package:flutter/widgets.dart';
import 'screen_util.dart';
class ScreenUtilInit extends StatelessWidget {
typedef RebuildFactor = bool Function(MediaQueryData old, MediaQueryData data);
bool defaultRebuildFactor(old, data) => old.size != data.size;
class ScreenUtilInit extends StatefulWidget {
/// A helper widget that initializes [ScreenUtil]
const ScreenUtilInit({
Key? key,
this.builder,
this.child,
this.rebuildFactor = defaultRebuildFactor,
this.designSize = ScreenUtil.defaultSize,
this.splitScreenMode = false,
this.minTextAdapt = false,
Key? key,
this.useInheritedMediaQuery = false,
}) : assert(
builder != null || child != null,
'You must either pass builder or child or both',
... ... @@ -21,43 +27,106 @@ class ScreenUtilInit extends StatelessWidget {
final Widget? child;
final bool splitScreenMode;
final bool minTextAdapt;
final bool useInheritedMediaQuery;
final RebuildFactor rebuildFactor;
/// The [Size] of the device in the design draft, in dp
final Size designSize;
@override
Widget build(BuildContext context) {
bool firstFrameAllowed = false;
final binding = WidgetsFlutterBinding.ensureInitialized();
binding.deferFirstFrame();
final rootMediaQueryData = (context
.getElementForInheritedWidgetOfExactType<MediaQuery>()
?.widget as MediaQuery?)
?.data;
return LayoutBuilder(
builder: (_, constraints) {
if (constraints.biggest == Size.zero) return const SizedBox.shrink();
if (!firstFrameAllowed) {
binding.allowFirstFrame();
firstFrameAllowed = true;
}
return MediaQuery(
data: rootMediaQueryData ?? MediaQueryData.fromWindow(binding.window),
child: Builder(builder: (_context) {
State<ScreenUtilInit> createState() => _ScreenUtilInitState();
}
class _ScreenUtilInitState extends State<ScreenUtilInit>
with WidgetsBindingObserver {
late MediaQueryData mediaQueryData;
bool wrappedInMediaQuery = false;
WidgetsBinding get binding => WidgetsFlutterBinding.ensureInitialized();
MediaQueryData get newData {
if (widget.useInheritedMediaQuery) {
final el = context.getElementForInheritedWidgetOfExactType<MediaQuery>();
final mq = el?.widget as MediaQuery?;
final data = mq?.data;
if (data != null) {
wrappedInMediaQuery = true;
return data;
}
}
return MediaQueryData.fromWindow(binding.window);
}
Widget get child {
return SizedBox(
key: GlobalObjectKey(
hashValues(
mediaQueryData.size.width,
mediaQueryData.size.height,
),
),
child: widget.builder?.call(widget.child) ?? widget.child!,
);
}
@override
void initState() {
super.initState();
mediaQueryData = newData;
binding.addObserver(this);
}
@override
void didChangeMetrics() {
final old = mediaQueryData;
final data = newData;
if (widget.rebuildFactor(old, data)) setState(() => mediaQueryData = data);
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
didChangeMetrics();
}
@override
void dispose() {
binding.removeObserver(this);
super.dispose();
}
@override
Widget build(BuildContext _context) {
if (mediaQueryData.size == Size.zero) return const SizedBox.shrink();
if (!wrappedInMediaQuery) {
return MediaQuery(
// key: GlobalObjectKey('mediaQuery'),
data: mediaQueryData,
child: Builder(
builder: (__context) {
ScreenUtil.init(
_context,
designSize: designSize,
splitScreenMode: splitScreenMode,
minTextAdapt: minTextAdapt,
__context,
designSize: widget.designSize,
splitScreenMode: widget.splitScreenMode,
minTextAdapt: widget.minTextAdapt,
);
return builder?.call(child) ?? child!;
}),
);
},
return child;
},
),
);
}
ScreenUtil.init(
_context,
designSize: widget.designSize,
splitScreenMode: widget.splitScreenMode,
minTextAdapt: widget.minTextAdapt,
);
return child;
}
}
... ...