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>(
|
contents = new NotificationListener<LayoutChangedNotification>(
|
||||||
onNotification: (LayoutChangedNotification notification) {
|
onNotification: (LayoutChangedNotification notification) {
|
||||||
_inkFeatureRenderer.currentContext.findRenderObject().markNeedsPaint();
|
_RenderInkFeatures renderer = _inkFeatureRenderer.currentContext.findRenderObject();
|
||||||
|
renderer._didChangeLayout();
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
child: new _InkFeatures(
|
child: new _InkFeatures(
|
||||||
@ -292,6 +293,11 @@ class _RenderInkFeatures extends RenderProxyBox implements MaterialInkController
|
|||||||
markNeedsPaint();
|
markNeedsPaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _didChangeLayout() {
|
||||||
|
if (_inkFeatures.isNotEmpty)
|
||||||
|
markNeedsPaint();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool hitTestSelf(Point position) => true;
|
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() {
|
void main() {
|
||||||
testWidgets('LayoutChangedNotificaion test', (WidgetTester tester) async {
|
testWidgets('LayoutChangedNotificaion test', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
new Material(
|
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