mirror of
https://github.com/flutter/flutter
synced 2024-10-14 04:02:56 +00:00
More useful error messages when you use Stack without a textDirection. (#59360)
This commit is contained in:
parent
b3c237ce54
commit
f7f019aa94
|
@ -3262,8 +3262,21 @@ class Stack extends MultiChildRenderObjectWidget {
|
|||
/// [Overflow.clip], children cannot paint outside of the stack's box.
|
||||
final Overflow overflow;
|
||||
|
||||
bool _debugCheckHasDirectionality(BuildContext context) {
|
||||
if (alignment is AlignmentDirectional && textDirection == null) {
|
||||
assert(debugCheckHasDirectionality(
|
||||
context,
|
||||
why: 'to resolve the \'alignment\' argument',
|
||||
hint: alignment == AlignmentDirectional.topStart ? 'The default value for \'alignment\' is AlignmentDirectional.topStart, which requires a text direction.' : null,
|
||||
alternative: 'Instead of providing a Directionality widget, another solution would be passing a non-directional \'alignment\', or an explicit \'textDirection\', to the $runtimeType.'),
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
RenderStack createRenderObject(BuildContext context) {
|
||||
assert(_debugCheckHasDirectionality(context));
|
||||
return RenderStack(
|
||||
alignment: alignment,
|
||||
textDirection: textDirection ?? Directionality.of(context),
|
||||
|
@ -3274,6 +3287,7 @@ class Stack extends MultiChildRenderObjectWidget {
|
|||
|
||||
@override
|
||||
void updateRenderObject(BuildContext context, RenderStack renderObject) {
|
||||
assert(_debugCheckHasDirectionality(context));
|
||||
renderObject
|
||||
..alignment = alignment
|
||||
..textDirection = textDirection ?? Directionality.of(context)
|
||||
|
@ -3322,6 +3336,7 @@ class IndexedStack extends Stack {
|
|||
|
||||
@override
|
||||
RenderIndexedStack createRenderObject(BuildContext context) {
|
||||
assert(_debugCheckHasDirectionality(context));
|
||||
return RenderIndexedStack(
|
||||
index: index,
|
||||
alignment: alignment,
|
||||
|
@ -3331,6 +3346,7 @@ class IndexedStack extends Stack {
|
|||
|
||||
@override
|
||||
void updateRenderObject(BuildContext context, RenderIndexedStack renderObject) {
|
||||
assert(_debugCheckHasDirectionality(context));
|
||||
renderObject
|
||||
..index = index
|
||||
..alignment = alignment
|
||||
|
|
|
@ -242,13 +242,33 @@ bool debugCheckHasMediaQuery(BuildContext context) {
|
|||
/// assert(debugCheckHasDirectionality(context));
|
||||
/// ```
|
||||
///
|
||||
/// To improve the error messages you can add some extra color using the
|
||||
/// named arguments.
|
||||
///
|
||||
/// * why: explain why the direction is needed, for example "to resolve
|
||||
/// the 'alignment' argument". Should be an adverb phrase describing why.
|
||||
/// * hint: explain why this might be happening, for example "The default
|
||||
/// value of the 'aligment' argument of the $runtimeType widget is an
|
||||
/// AlignmentDirectional value.". Should be a fully punctuated sentence.
|
||||
/// * alternative: provide additional advice specific to the situation,
|
||||
/// especially an alternative to providing a Directionality ancestor.
|
||||
/// For example, "Alternatively, consider specifying the 'textDirection'
|
||||
/// argument.". Should be a funny punctuated sentence.
|
||||
///
|
||||
/// Each one can be null, in which case it is skipped (this is the default).
|
||||
/// If they are non-null, they are included in the order above, interspersed
|
||||
/// with the more generic advice regarding [Directionality].
|
||||
///
|
||||
/// Does nothing if asserts are disabled. Always returns true.
|
||||
bool debugCheckHasDirectionality(BuildContext context) {
|
||||
bool debugCheckHasDirectionality(BuildContext context, { String why, String hint, String alternative }) {
|
||||
assert(() {
|
||||
if (context.widget is! Directionality && context.findAncestorWidgetOfExactType<Directionality>() == null) {
|
||||
why = why == null ? '' : ' $why';
|
||||
throw FlutterError.fromParts(<DiagnosticsNode>[
|
||||
ErrorSummary('No Directionality widget found.'),
|
||||
ErrorDescription('${context.widget.runtimeType} widgets require a Directionality widget ancestor.\n'),
|
||||
ErrorDescription('${context.widget.runtimeType} widgets require a Directionality widget ancestor$why.\n'),
|
||||
if (hint != null)
|
||||
ErrorHint(hint),
|
||||
context.describeWidget('The specific widget that could not find a Directionality ancestor was'),
|
||||
context.describeOwnershipChain('The ownership chain for the affected widget is'),
|
||||
ErrorHint(
|
||||
|
@ -259,6 +279,8 @@ bool debugCheckHasDirectionality(BuildContext context) {
|
|||
'values, and to resolve EdgeInsetsDirectional, '
|
||||
'AlignmentDirectional, and other *Directional objects.'
|
||||
),
|
||||
if (alternative != null)
|
||||
ErrorHint(alternative),
|
||||
]);
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -749,4 +749,25 @@ void main() {
|
|||
expect(tester.getRect(find.byType(SizedBox).at(7)), const Rect.fromLTWH(0.0, 0.0, 100.0, 100.0));
|
||||
expect(tester.getRect(find.byType(SizedBox).at(8)), const Rect.fromLTWH(0.0, 500.0, 100.0, 100.0));
|
||||
});
|
||||
|
||||
testWidgets('Stack error messages', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
Stack(),
|
||||
);
|
||||
expect(
|
||||
tester.takeException().toString(),
|
||||
'No Directionality widget found.\n'
|
||||
'Stack widgets require a Directionality widget ancestor to resolve the \'alignment\' argument.\n'
|
||||
'The default value for \'alignment\' is AlignmentDirectional.topStart, which requires a text direction.\n'
|
||||
'The specific widget that could not find a Directionality ancestor was:\n'
|
||||
' Stack\n'
|
||||
'The ownership chain for the affected widget is: "Stack ← [root]"\n'
|
||||
'Typically, the Directionality widget is introduced by the MaterialApp or WidgetsApp widget at the '
|
||||
'top of your application widget tree. It determines the ambient reading direction and is used, for '
|
||||
'example, to determine how to lay out text, how to interpret "start" and "end" values, and to resolve '
|
||||
'EdgeInsetsDirectional, AlignmentDirectional, and other *Directional objects.\n'
|
||||
'Instead of providing a Directionality widget, another solution would be passing a non-directional '
|
||||
'\'alignment\', or an explicit \'textDirection\', to the Stack.'
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue