Material should unconditionally repaint on LayoutChangedNotification (#8107)
When a ListView scrolls, it generates a LayoutChangedNotification, which was causing Material to repaint unconditionally. That's not necessary if there are no ink effects that need to be moved. This patch skips the repaint in that case. Fixes #7937
This commit is contained in:
parent
39f7d58b74
commit
c40b92b910
@ -216,7 +216,8 @@ class _MaterialState extends State<Material> with TickerProviderStateMixin {
|
||||
}
|
||||
contents = new NotificationListener<LayoutChangedNotification>(
|
||||
onNotification: (LayoutChangedNotification notification) {
|
||||
_inkFeatureRenderer.currentContext.findRenderObject().markNeedsPaint();
|
||||
_RenderInkFeatures renderer = _inkFeatureRenderer.currentContext.findRenderObject();
|
||||
renderer._didChangeLayout();
|
||||
return true;
|
||||
},
|
||||
child: new _InkFeatures(
|
||||
@ -292,6 +293,11 @@ class _RenderInkFeatures extends RenderProxyBox implements MaterialInkController
|
||||
markNeedsPaint();
|
||||
}
|
||||
|
||||
void _didChangeLayout() {
|
||||
if (_inkFeatures.isNotEmpty)
|
||||
markNeedsPaint();
|
||||
}
|
||||
|
||||
@override
|
||||
bool hitTestSelf(Point position) => true;
|
||||
|
||||
|
@ -13,12 +13,86 @@ class NotifyMaterial extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class PaintRecorder extends CustomPainter {
|
||||
PaintRecorder(this.log);
|
||||
|
||||
List<Size> log;
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
log.add(size);
|
||||
final Paint paint = new Paint()..color = const Color(0xFF0000FF);
|
||||
canvas.drawRect(Point.origin & size, paint);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(PaintRecorder oldDelegate) => false;
|
||||
}
|
||||
|
||||
void main() {
|
||||
testWidgets('LayoutChangedNotificaion test', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
new Material(
|
||||
child: new NotifyMaterial()
|
||||
)
|
||||
child: new NotifyMaterial(),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('ListView scroll does not repaint', (WidgetTester tester) async {
|
||||
List<Size> log = <Size>[];
|
||||
|
||||
await tester.pumpWidget(
|
||||
new Column(
|
||||
children: <Widget>[
|
||||
new SizedBox(
|
||||
width: 150.0,
|
||||
height: 150.0,
|
||||
child: new CustomPaint(
|
||||
painter: new PaintRecorder(log),
|
||||
),
|
||||
),
|
||||
new Expanded(
|
||||
child: new Material(
|
||||
child: new Column(
|
||||
children: <Widget>[
|
||||
new Expanded(
|
||||
child: new ListView(
|
||||
children: <Widget>[
|
||||
new Container(
|
||||
height: 2000.0,
|
||||
decoration: const BoxDecoration(
|
||||
backgroundColor: const Color(0xFF00FF00),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
new SizedBox(
|
||||
width: 100.0,
|
||||
height: 100.0,
|
||||
child: new CustomPaint(
|
||||
painter: new PaintRecorder(log),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
// We paint twice because we have two CustomPaint widgets in the tree above
|
||||
// to test repainting both inside and outside the Material widget.
|
||||
expect(log, equals(<Size>[
|
||||
const Size(150.0, 150.0),
|
||||
const Size(100.0, 100.0),
|
||||
]));
|
||||
log.clear();
|
||||
|
||||
await tester.scroll(find.byType(ListView), const Offset(0.0, -300.0));
|
||||
await tester.pump();
|
||||
|
||||
expect(log, isEmpty);
|
||||
});
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user