OrientationBuilder
reports the orientation change after the full transformation has taken place, then the rebuild occurs after that.
Is there a way to act before the orientation initiates? I am not trying to pre-empt the rotation, but make changes simutaneously, not after.
The goal:
The challenge, how to fulfil point 2 before 3 occurs?
Yes, you can get the orientation change earlier using WidgetsBindingObserver
by overriding didChangeMetrics
.
didChangeMetrics
You can simply mixin WidgetBindingObserver
in a State
implementation of a stateful widget:
class _FooState extends State with WidgetsBindingObserver {
@override
void didChangeMetrics() {
// This will be triggered by changes in orientation.
}
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
}
Orientation is determined by the aspect ratio of the available size. This means that you can get the orientation in didChangeMetrics
using the following code:
final orientation = WidgetsBinding.instance.window.physicalSize
.aspectRatio > 1 ? Orientation.landscape : Orientation.portrait;
I have constructed an example StatefulWidget
that compares the OrientationBuilder
callback to didChangeMetrics
:
import 'package:flutter/material.dart';
void main() {
runApp(OrientationListener());
}
class OrientationListener extends StatefulWidget {
@override
_OrientationListenerState createState() => _OrientationListenerState();
}
class _OrientationListenerState extends State<OrientationListener>
with WidgetsBindingObserver {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@override
void didChangeMetrics() {
print('$WidgetsBindingObserver metrics changed ${DateTime.now()}: '
'${WidgetsBinding.instance.window.physicalSize.aspectRatio > 1 ? Orientation.landscape : Orientation.portrait}');
}
@override
Widget build(BuildContext context) {
return MediaQuery(
data: MediaQueryData.fromWindow(WidgetsBinding.instance.window),
child: OrientationBuilder(
builder: (context, orientation) {
print('$OrientationBuilder rebuild ${DateTime.now()}: $orientation');
return Container();
},
),
);
}
}
Running this example shows the following times for the two functions:
WidgetsBindingObserver metrics changed 2020-08-22 14:47:01.690172: Orientation.portrait
WidgetsBindingObserver metrics changed 2020-08-22 14:47:01.706574: Orientation.landscape
OrientationBuilder rebuild 2020-08-22 14:47:01.760589: Orientation.landscape
WidgetsBindingObserver metrics changed 2020-08-22 14:47:06.537083: Orientation.landscape
WidgetsBindingObserver metrics changed 2020-08-22 14:47:06.549545: Orientation.portrait
OrientationBuilder rebuild 2020-08-22 14:47:06.603859: Orientation.portrait
WidgetsBindingObserver metrics changed 2020-08-22 14:47:10.423787: Orientation.portrait
WidgetsBindingObserver metrics changed 2020-08-22 14:47:10.442866: Orientation.landscape
OrientationBuilder rebuild 2020-08-22 14:47:10.501729: Orientation.landscape
WidgetsBindingObserver metrics changed 2020-08-22 14:47:13.639545: Orientation.landscape
WidgetsBindingObserver metrics changed 2020-08-22 14:47:13.658906: Orientation.landscape
WidgetsBindingObserver metrics changed 2020-08-22 14:47:13.672025: Orientation.portrait
OrientationBuilder rebuild 2020-08-22 14:47:13.730771: Orientation.portrait
So in my case, the difference in detection was about 0.06
seconds.
As you can see from above, the difference is insignificant (I would say). So I am not even sure if this will be useful to you.
Moreover, I have observed that the OrientationBuilder
callback is actually called at the start of the device rotation - at least on my Android emulator. This would mean that you can rebuild your UI before the rotation happens.
I hope this was somehow helpful to you :)
As you can see in this link, there is no "natural" way to do what you want:
https://github.com/flutter/flutter/issues/16322
Try to make something using this:
You may try animated container for a better effect, but you would need to handle all the screen position and rotation manually before set the new orientation:
https://api.flutter.dev/flutter/widgets/AnimatedContainer-class.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With