mirror of
https://github.com/flutter/flutter.git
synced 2026-02-14 14:50:22 +08:00
LayoutBuilder + GlobalKey + setState assert (#6068)
This silences an assertion that fired when reparenting a widget with a global key inside a LayoutBuilder callback when that callback also happened to call setState (directly or indirectly) on that widget. Normally such setStates are considered ok since we know we haven't cleaned that subtree yet, but we were not correctly handling the case where the list needed resorting in that situation.
This commit is contained in:
parent
fa52b456ec
commit
78c74116a9
@ -1495,6 +1495,8 @@ class BuildOwner {
|
||||
/// widget tree.
|
||||
void markNeedsToResortDirtyElements() {
|
||||
assert(() {
|
||||
if (debugPrintScheduleBuildForStacks)
|
||||
debugPrintStack(label: 'markNeedsToResortDirtyElements() called; _dirtyElementsNeedsResorting was $_dirtyElementsNeedsResorting (now true); dirty list is: $_dirtyElements');
|
||||
if (_dirtyElementsNeedsResorting == null) {
|
||||
throw new FlutterError(
|
||||
'markNeedsToResortDirtyElements() called inappropriately.\n'
|
||||
@ -1633,6 +1635,7 @@ class BuildOwner {
|
||||
_debugCurrentBuildTarget = context;
|
||||
return true;
|
||||
});
|
||||
_dirtyElementsNeedsResorting = false;
|
||||
try {
|
||||
callback();
|
||||
} finally {
|
||||
|
||||
@ -0,0 +1,59 @@
|
||||
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart' hide TypeMatcher;
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
class Wrapper extends StatelessWidget {
|
||||
Wrapper({
|
||||
Key key,
|
||||
this.child,
|
||||
}) : super(key: key);
|
||||
|
||||
final Widget child;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => child;
|
||||
}
|
||||
|
||||
class StatefulWrapper extends StatefulWidget {
|
||||
StatefulWrapper({
|
||||
Key key,
|
||||
this.child,
|
||||
}) : super(key: key);
|
||||
|
||||
final Widget child;
|
||||
|
||||
@override
|
||||
StatefulWrapperState createState() => new StatefulWrapperState();
|
||||
}
|
||||
|
||||
class StatefulWrapperState extends State<StatefulWrapper> {
|
||||
|
||||
void trigger() {
|
||||
setState(() { /* for test purposes */ });
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => config.child;
|
||||
}
|
||||
|
||||
void main() {
|
||||
testWidgets('Moving global key inside a LayoutBuilder', (WidgetTester tester) async {
|
||||
GlobalKey<StatefulWrapperState> key = new GlobalKey<StatefulWrapperState>();
|
||||
await tester.pumpWidget(
|
||||
new LayoutBuilder(builder: (BuildContext context, BoxConstraints constraints) {
|
||||
return new Wrapper(
|
||||
child: new StatefulWrapper(key: key, child: new Container(height: 100.0)),
|
||||
);
|
||||
}),
|
||||
);
|
||||
await tester.pumpWidget(
|
||||
new LayoutBuilder(builder: (BuildContext context, BoxConstraints constraints) {
|
||||
key.currentState.trigger();
|
||||
return new StatefulWrapper(key: key, child: new Container(height: 100.0));
|
||||
}),
|
||||
);
|
||||
});
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user