SliverOffstage (#45128)
This commit is contained in:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user