@@ -10,6 +10,7 @@ import 'package:ui/ui.dart' as ui;
10
10
import 'package:ui/ui_web/src/ui_web.dart' as ui_web;
11
11
12
12
import '../engine.dart' show DimensionsProvider, registerHotRestartListener, renderer;
13
+ import 'browser_detection.dart' ;
13
14
import 'display.dart' ;
14
15
import 'dom.dart' ;
15
16
import 'mouse/context_menu.dart' ;
@@ -20,9 +21,11 @@ import 'platform_views/message_handler.dart';
20
21
import 'pointer_binding.dart' ;
21
22
import 'semantics.dart' ;
22
23
import 'services.dart' ;
24
+ import 'text_editing/text_editing.dart' ;
23
25
import 'util.dart' ;
24
26
import 'view_embedder/dom_manager.dart' ;
25
27
import 'view_embedder/embedding_strategy/embedding_strategy.dart' ;
28
+ import 'view_embedder/style_manager.dart' ;
26
29
27
30
typedef _HandleMessageCallBack = Future <bool > Function ();
28
31
@@ -61,6 +64,7 @@ base class EngineFlutterView implements ui.FlutterView {
61
64
// hot restart.
62
65
embeddingStrategy.attachViewRoot (dom.rootElement);
63
66
pointerBinding = PointerBinding (this );
67
+ _resizeSubscription = onResize.listen (_didResize);
64
68
registerHotRestartListener (dispose);
65
69
}
66
70
@@ -78,6 +82,8 @@ base class EngineFlutterView implements ui.FlutterView {
78
82
/// Abstracts all the DOM manipulations required to embed a Flutter view in a user-supplied `hostElement` .
79
83
final EmbeddingStrategy embeddingStrategy;
80
84
85
+ late final StreamSubscription <ui.Size ?> _resizeSubscription;
86
+
81
87
final ViewConfiguration _viewConfiguration = const ViewConfiguration ();
82
88
83
89
/// Whether this [EngineFlutterView] has been disposed or not.
@@ -91,6 +97,7 @@ base class EngineFlutterView implements ui.FlutterView {
91
97
return ;
92
98
}
93
99
isDisposed = true ;
100
+ _resizeSubscription.cancel ();
94
101
dimensionsProvider.close ();
95
102
pointerBinding.dispose ();
96
103
dom.rootElement.remove ();
@@ -136,41 +143,32 @@ base class EngineFlutterView implements ui.FlutterView {
136
143
137
144
@override
138
145
ui.Size get physicalSize {
139
- if (_physicalSize == null ) {
140
- computePhysicalSize ();
141
- }
142
- assert (_physicalSize != null );
143
- return _physicalSize! ;
146
+ return _physicalSize ?? = _computePhysicalSize ();
144
147
}
145
148
146
149
/// Lazily populated and cleared at the end of the frame.
147
150
ui.Size ? _physicalSize;
148
151
149
152
ui.Size ? debugPhysicalSizeOverride;
150
153
151
- /// Computes the physical size of the screen from [domWindow] .
154
+ /// Computes the physical size of the view .
152
155
///
153
156
/// This function is expensive. It triggers browser layout if there are
154
157
/// pending DOM writes.
155
- void computePhysicalSize () {
156
- bool override = false ;
158
+ ui. Size _computePhysicalSize () {
159
+ ui. Size ? physicalSizeOverride ;
157
160
158
161
assert (() {
159
- if (debugPhysicalSizeOverride != null ) {
160
- _physicalSize = debugPhysicalSizeOverride;
161
- override = true ;
162
- }
162
+ physicalSizeOverride = debugPhysicalSizeOverride;
163
163
return true ;
164
164
}());
165
165
166
- if (! override) {
167
- _physicalSize = dimensionsProvider.computePhysicalSize ();
168
- }
166
+ return physicalSizeOverride ?? dimensionsProvider.computePhysicalSize ();
169
167
}
170
168
171
169
/// Forces the view to recompute its physical size. Useful for tests.
172
170
void debugForceResize () {
173
- computePhysicalSize ();
171
+ _physicalSize = _computePhysicalSize ();
174
172
}
175
173
176
174
@override
@@ -202,6 +200,69 @@ base class EngineFlutterView implements ui.FlutterView {
202
200
final DimensionsProvider dimensionsProvider;
203
201
204
202
Stream <ui.Size ?> get onResize => dimensionsProvider.onResize;
203
+
204
+ /// Called immediately after the view has been resized.
205
+ ///
206
+ /// When there is a text editing going on in mobile devices, do not change
207
+ /// the physicalSize, change the [window.viewInsets] . See:
208
+ /// https://api.flutter.dev/flutter/dart-ui/FlutterView/viewInsets.html
209
+ /// https://api.flutter.dev/flutter/dart-ui/FlutterView/physicalSize.html
210
+ ///
211
+ /// Note: always check for rotations for a mobile device. Update the physical
212
+ /// size if the change is caused by a rotation.
213
+ void _didResize (ui.Size ? newSize) {
214
+ StyleManager .scaleSemanticsHost (dom.semanticsHost, devicePixelRatio);
215
+ final ui.Size newPhysicalSize = _computePhysicalSize ();
216
+ final bool isEditingOnMobile =
217
+ isMobile && ! _isRotation (newPhysicalSize) && textEditing.isEditing;
218
+ if (isEditingOnMobile) {
219
+ _computeOnScreenKeyboardInsets (true );
220
+ } else {
221
+ _physicalSize = newPhysicalSize;
222
+ // When physical size changes this value has to be recalculated.
223
+ _computeOnScreenKeyboardInsets (false );
224
+ }
225
+ platformDispatcher.invokeOnMetricsChanged ();
226
+ }
227
+
228
+ /// Uses the previous physical size and current innerHeight/innerWidth
229
+ /// values to decide if a device is rotating.
230
+ ///
231
+ /// During a rotation the height and width values will (almost) swap place.
232
+ /// Values can slightly differ due to space occupied by the browser header.
233
+ /// For example the following values are collected for Pixel 3 rotation:
234
+ ///
235
+ /// height: 658 width: 393
236
+ /// new height: 313 new width: 738
237
+ ///
238
+ /// The following values are from a changed caused by virtual keyboard.
239
+ ///
240
+ /// height: 658 width: 393
241
+ /// height: 368 width: 393
242
+ bool _isRotation (ui.Size newPhysicalSize) {
243
+ // This method compares the new dimensions with the previous ones.
244
+ // Return false if the previous dimensions are not set.
245
+ if (_physicalSize != null ) {
246
+ // First confirm both height and width are effected.
247
+ if (_physicalSize! .height != newPhysicalSize.height && _physicalSize! .width != newPhysicalSize.width) {
248
+ // If prior to rotation height is bigger than width it should be the
249
+ // opposite after the rotation and vice versa.
250
+ if ((_physicalSize! .height > _physicalSize! .width && newPhysicalSize.height < newPhysicalSize.width) ||
251
+ (_physicalSize! .width > _physicalSize! .height && newPhysicalSize.width < newPhysicalSize.height)) {
252
+ // Rotation detected
253
+ return true ;
254
+ }
255
+ }
256
+ }
257
+ return false ;
258
+ }
259
+
260
+ void _computeOnScreenKeyboardInsets (bool isEditingOnMobile) {
261
+ _viewInsets = dimensionsProvider.computeKeyboardInsets (
262
+ _physicalSize! .height,
263
+ isEditingOnMobile,
264
+ );
265
+ }
205
266
}
206
267
207
268
final class _EngineFlutterViewImpl extends EngineFlutterView {
@@ -543,46 +604,6 @@ final class EngineFlutterWindow extends EngineFlutterView implements ui.Singleto
543
604
display.debugOverrideDevicePixelRatio (value);
544
605
}
545
606
546
- void computeOnScreenKeyboardInsets (bool isEditingOnMobile) {
547
- _viewInsets = dimensionsProvider.computeKeyboardInsets (
548
- _physicalSize! .height,
549
- isEditingOnMobile,
550
- );
551
- }
552
-
553
- /// Uses the previous physical size and current innerHeight/innerWidth
554
- /// values to decide if a device is rotating.
555
- ///
556
- /// During a rotation the height and width values will (almost) swap place.
557
- /// Values can slightly differ due to space occupied by the browser header.
558
- /// For example the following values are collected for Pixel 3 rotation:
559
- ///
560
- /// height: 658 width: 393
561
- /// new height: 313 new width: 738
562
- ///
563
- /// The following values are from a changed caused by virtual keyboard.
564
- ///
565
- /// height: 658 width: 393
566
- /// height: 368 width: 393
567
- bool isRotation () {
568
- // This method compares the new dimensions with the previous ones.
569
- // Return false if the previous dimensions are not set.
570
- if (_physicalSize != null ) {
571
- final ui.Size current = dimensionsProvider.computePhysicalSize ();
572
- // First confirm both height and width are effected.
573
- if (_physicalSize! .height != current.height && _physicalSize! .width != current.width) {
574
- // If prior to rotation height is bigger than width it should be the
575
- // opposite after the rotation and vice versa.
576
- if ((_physicalSize! .height > _physicalSize! .width && current.height < current.width) ||
577
- (_physicalSize! .width > _physicalSize! .height && current.width < current.height)) {
578
- // Rotation detected
579
- return true ;
580
- }
581
- }
582
- }
583
- return false ;
584
- }
585
-
586
607
// TODO(mdebbar): Deprecate this and remove it.
587
608
// https://github.com/flutter/flutter/issues/127395
588
609
ui.Size ? get webOnlyDebugPhysicalSizeOverride {
0 commit comments