Unverified Commit fdf87edd authored by xubaolin's avatar xubaolin Committed by GitHub

InkDecoration do not paint if it's part of the tree doesn't get painted (#61216)

parent 753b8489
......@@ -8,6 +8,7 @@ import 'dart:math' as math;
import 'dart:ui' show lerpDouble, hashValues;
import 'package:flutter/foundation.dart';
import 'package:vector_math/vector_math_64.dart' show Matrix4;
import 'box.dart';
import 'object.dart';
......@@ -707,6 +708,22 @@ class RenderIndexedStack extends RenderStack {
context.paintChild(child, childParentData.offset + offset);
}
@override
void applyPaintTransform(RenderObject child, Matrix4 transform) {
if (firstChild == null || index == null)
return;
final RenderBox childAtIndex = _childAtIndex();
if (child != childAtIndex)
// It is possible that the offstage widgets want to paint themselves.
// For example, the Material widget tries to paint all
// InkFeatures under its subtree as long as they are not disposed. In
// such case, we give it a zero transform to prevent them from painting.
// https://github.com/flutter/flutter/issues/59963
transform.setZero();
else
super.applyPaintTransform(child, transform);
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
......
......@@ -341,11 +341,19 @@ void main() {
testWidgets('Dropdown button control test', (WidgetTester tester) async {
String value = 'one';
StateSetter setState;
void didChangeValue(String newValue) {
value = newValue;
setState(() {
value = newValue;
});
}
Widget build() => buildFrame(value: value, onChanged: didChangeValue);
Widget build() {
return StatefulBuilder(builder: (BuildContext context, StateSetter setter) {
setState = setter;
return buildFrame(value: value, onChanged: didChangeValue);
},);
}
await tester.pumpWidget(build());
......@@ -380,27 +388,33 @@ void main() {
testWidgets('Dropdown button with no app', (WidgetTester tester) async {
String value = 'one';
StateSetter setState;
void didChangeValue(String newValue) {
value = newValue;
setState(() {
value = newValue;
});
}
Widget build() {
return Directionality(
textDirection: TextDirection.ltr,
child: Navigator(
initialRoute: '/',
onGenerateRoute: (RouteSettings settings) {
return MaterialPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return Material(
child: buildFrame(value: 'one', onChanged: didChangeValue),
);
},
);
},
),
);
return StatefulBuilder(builder: (BuildContext context, StateSetter setter) {
setState = setter;
return Directionality(
textDirection: TextDirection.ltr,
child: Navigator(
initialRoute: '/',
onGenerateRoute: (RouteSettings settings) {
return MaterialPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return Material(
child: buildFrame(value: value, onChanged: didChangeValue),
);
},
);
},
),
);
},);
}
await tester.pumpWidget(build());
......@@ -2486,15 +2500,22 @@ void main() {
testWidgets('DropdownButton onTap callback is called when defined', (WidgetTester tester) async {
int dropdownButtonTapCounter = 0;
String value = 'one';
StateSetter setState;
void onChanged(String newValue) { value = newValue; }
void onChanged(String newValue) {
setState(() {
value = newValue;
});
}
void onTap() { dropdownButtonTapCounter += 1; }
Widget build() => buildFrame(
value: value,
onChanged: onChanged,
onTap: onTap,
);
Widget build() {
return StatefulBuilder(builder: (BuildContext context, StateSetter setter) {
setState = setter;
return buildFrame(value: value, onChanged: onChanged, onTap: onTap,);
},);
}
await tester.pumpWidget(build());
expect(dropdownButtonTapCounter, 0);
......@@ -2530,8 +2551,15 @@ void main() {
testWidgets('DropdownMenuItem onTap callback is called when defined', (WidgetTester tester) async {
String value = 'one';
int currentIndex = -1;
StateSetter setState;
void onChanged(String newValue) {
setState(() {
currentIndex = -1;
value = newValue;
});
}
final List<int> menuItemTapCounters = <int>[0, 0, 0, 0];
void onChanged(String newValue) { value = newValue; }
final List<VoidCallback> onTapCallbacks = <VoidCallback>[
() { menuItemTapCounters[0] += 1; },
......@@ -2540,28 +2568,32 @@ void main() {
() { menuItemTapCounters[3] += 1; },
];
int currentIndex = -1;
await tester.pumpWidget(
TestApp(
textDirection: TextDirection.ltr,
child: Material(
child: RepaintBoundary(
child: DropdownButton<String>(
value: value,
onChanged: onChanged,
items: menuItems.map<DropdownMenuItem<String>>((String item) {
currentIndex += 1;
return DropdownMenuItem<String>(
value: item,
onTap: onTapCallbacks[currentIndex],
child: Text(item),
);
}).toList(),
Widget build() {
return StatefulBuilder(builder: (BuildContext context, StateSetter setter) {
setState = setter;
return TestApp(
textDirection: TextDirection.ltr,
child: Material(
child: RepaintBoundary(
child: DropdownButton<String>(
value: value,
onChanged: onChanged,
items: menuItems.map<DropdownMenuItem<String>>((String item) {
currentIndex += 1;
return DropdownMenuItem<String>(
value: item,
onTap: onTapCallbacks[currentIndex],
child: Text(item),
);
}).toList(),
),
),
),
),
),
);
);
});
}
await tester.pumpWidget(build());
// Tap dropdown button.
await tester.tap(find.text('one'));
......
......@@ -434,4 +434,36 @@ void main() {
throw 'Expected: paint.color.alpha == 0, found: ${paint.color.alpha}';
}));
});
testWidgets('Does the Ink widget render anything if it have ancestor IndexedStack', (WidgetTester tester) async {
// Regressing test for https://github.com/flutter/flutter/issues/59963
int index = 0;
Widget build() => Directionality(
textDirection: TextDirection.ltr,
child: Material(
child: IndexedStack(
index: index,
children: <Widget>[
Ink(width: 100, height: 100, decoration: const BoxDecoration(color: Colors.black)),
Ink(width: 50, height: 50, decoration: const BoxDecoration(color: Colors.red)),
],
),
),
);
await tester.pumpWidget(build());
final RenderBox box = Material.of(tester.element(find.byType(IndexedStack))) as RenderBox;
expect(box, paints..rect(rect: const Rect.fromLTRB(0.0, 0.0, 100.0, 100.0), color: Color(Colors.black.value)));
// update index, child do not at index should not be painted by have a zero
// transform.
index = 1;
await tester.pumpWidget(build());
expect(box, paints..transform(
matrix4: equals(<dynamic>[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]),
));
});
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment