Unverified Commit d0ea9ed2 authored by Kate Lovett's avatar Kate Lovett Committed by GitHub

SliverOffstage (#45128)

parent 1160c8fd
......@@ -1965,7 +1965,7 @@ class RenderSliverOpacity extends RenderSliver with RenderObjectWithChildMixin<R
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(DoubleProperty('opacity', opacity));
properties.add(FlagProperty('alwaysIncludeSemantics', value: alwaysIncludeSemantics, ifTrue: 'alwaysIncludeSemantics',));
properties.add(FlagProperty('alwaysIncludeSemantics', value: alwaysIncludeSemantics, ifTrue: 'alwaysIncludeSemantics'));
}
}
......@@ -2079,6 +2079,118 @@ class RenderSliverIgnorePointer extends RenderSliver with RenderObjectWithChildM
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(DiagnosticsProperty<bool>('ignoring', ignoring));
properties.add(DiagnosticsProperty<bool>('ignoringSemantics', _effectiveIgnoringSemantics, description: ignoringSemantics == null ? 'implicitly $_effectiveIgnoringSemantics' : null,),);
properties.add(DiagnosticsProperty<bool>('ignoringSemantics', _effectiveIgnoringSemantics, description: ignoringSemantics == null ? 'implicitly $_effectiveIgnoringSemantics' : null));
}
}
/// Lays the sliver child out as if it was in the tree, but without painting
/// anything, without making the sliver child available for hit testing, and
/// without taking any room in the parent.
class RenderSliverOffstage extends RenderSliver with RenderObjectWithChildMixin<RenderSliver> {
/// Creates an offstage render object.
RenderSliverOffstage({
bool offstage = true,
RenderSliver sliver,
}) : assert(offstage != null),
_offstage = offstage {
child = sliver;
}
/// Whether the sliver child is hidden from the rest of the tree.
///
/// If true, the sliver child is laid out as if it was in the tree, but
/// without painting anything, without making the sliver child available for
/// hit testing, and without taking any room in the parent.
///
/// If false, the sliver child is included in the tree as normal.
bool get offstage => _offstage;
bool _offstage;
set offstage(bool value) {
assert(value != null);
if (value == _offstage)
return;
_offstage = value;
markNeedsLayoutForSizedByParentChange();
}
@override
void setupParentData(RenderObject child) {
if (child.parentData is! SliverPhysicalParentData)
child.parentData = SliverPhysicalParentData();
}
@override
void performLayout() {
assert(child != null);
child.layout(constraints, parentUsesSize: true);
geometry = child.geometry;
}
@override
bool hitTest(SliverHitTestResult result, {double mainAxisPosition, double crossAxisPosition}) {
return !offstage && super.hitTest(
result,
mainAxisPosition: mainAxisPosition,
crossAxisPosition: crossAxisPosition,
);
}
@override
bool hitTestChildren(SliverHitTestResult result, {double mainAxisPosition, double crossAxisPosition}) {
return !offstage
&& child != null
&& child.geometry.hitTestExtent > 0
&& child.hitTest(
result,
mainAxisPosition: mainAxisPosition,
crossAxisPosition: crossAxisPosition,
);
}
@override
double childMainAxisPosition(RenderSliver child) {
assert(child != null);
assert(child == this.child);
return 0.0;
}
@override
void paint(PaintingContext context, Offset offset) {
if (offstage)
return;
super.paint(context, offset);
}
@override
void applyPaintTransform(RenderObject child, Matrix4 transform) {
assert(child != null);
final SliverPhysicalParentData childParentData = child.parentData;
childParentData.applyPaintTransform(transform);
}
@override
void visitChildrenForSemantics(RenderObjectVisitor visitor) {
if (offstage)
return;
super.visitChildrenForSemantics(visitor);
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(DiagnosticsProperty<bool>('offstage', offstage));
}
@override
List<DiagnosticsNode> debugDescribeChildren() {
if (child == null)
return <DiagnosticsNode>[];
return <DiagnosticsNode>[
child.toDiagnosticsNode(
name: 'child',
style: offstage ? DiagnosticsTreeStyle.offstage : DiagnosticsTreeStyle.sparse,
),
];
}
}
......@@ -1712,8 +1712,7 @@ class SliverOpacity extends SingleChildRenderObjectWidget {
}
@override
void updateRenderObject(BuildContext context,
RenderSliverOpacity renderObject) {
void updateRenderObject(BuildContext context, RenderSliverOpacity renderObject) {
renderObject
..opacity = opacity
..alwaysIncludeSemantics = alwaysIncludeSemantics;
......@@ -1787,6 +1786,66 @@ class SliverIgnorePointer extends SingleChildRenderObjectWidget {
}
}
/// A sliver that lays its sliver child out as if it was in the tree, but
/// without painting anything, without making the sliver child available for hit
/// testing, and without taking any room in the parent.
///
/// Animations continue to run in offstage sliver children, and therefore use
/// battery and CPU time, regardless of whether the animations end up being
/// visible.
///
/// To hide a sliver widget from view while it is
/// not needed, prefer removing the widget from the tree entirely rather than
/// keeping it alive in an [Offstage] subtree.
class SliverOffstage extends SingleChildRenderObjectWidget {
/// Creates a sliver that visually hides its sliver child.
const SliverOffstage({
Key key,
this.offstage = true,
Widget sliver,
}) : assert(offstage != null),
super(key: key, child: sliver);
/// Whether the sliver child is hidden from the rest of the tree.
///
/// If true, the sliver child is laid out as if it was in the tree, but
/// without painting anything, without making the child available for hit
/// testing, and without taking any room in the parent.
///
/// If false, the sliver child is included in the tree as normal.
final bool offstage;
@override
RenderSliverOffstage createRenderObject(BuildContext context) => RenderSliverOffstage(offstage: offstage);
@override
void updateRenderObject(BuildContext context, RenderSliverOffstage renderObject) {
renderObject.offstage = offstage;
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(DiagnosticsProperty<bool>('offstage', offstage));
}
@override
_SliverOffstageElement createElement() => _SliverOffstageElement(this);
}
class _SliverOffstageElement extends SingleChildRenderObjectElement {
_SliverOffstageElement(SliverOffstage widget) : super(widget);
@override
SliverOffstage get widget => super.widget;
@override
void debugVisitOnstageChildren(ElementVisitor visitor) {
if (!widget.offstage)
super.debugVisitOnstageChildren(visitor);
}
}
/// Mark a child as needing to stay alive even when it's in a lazy list that
/// would otherwise remove it.
///
......
......@@ -440,6 +440,38 @@ void main() {
);
}
group('SliverOffstage - ', () {
testWidgets('offstage true', (WidgetTester tester) async {
final SemanticsTester semantics = SemanticsTester(tester);
await tester.pumpWidget(_boilerPlate(
const SliverOffstage(
offstage: true,
sliver: SliverToBoxAdapter(
child: Text('a'),
)
)
));
expect(semantics.nodesWith(label: 'a'), hasLength(0));
expect(find.byType(Text), findsNothing);
});
testWidgets('offstage false', (WidgetTester tester) async {
final SemanticsTester semantics = SemanticsTester(tester);
await tester.pumpWidget(_boilerPlate(
const SliverOffstage(
offstage: false,
sliver: SliverToBoxAdapter(
child: Text('a'),
)
)
));
expect(semantics.nodesWith(label: 'a'), hasLength(1));
expect(find.byType(Text), findsOneWidget);
});
});
group('SliverOpacity - ', () {
testWidgets('painting & semantics', (WidgetTester tester) async {
final SemanticsTester semantics = SemanticsTester(tester);
......
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