Added clipping opt-out for Stack. (#5326)
Added a flag that instructs Stack how to deal with overflowing children: they can either be clipped or not.
This commit is contained in:
parent
9c15407ba9
commit
fd119f4f59
@ -199,6 +199,15 @@ class StackParentData extends ContainerBoxParentDataMixin<RenderBox> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether overflowing children should be clipped, or their overflows be
|
||||
/// visible.
|
||||
enum Overflow {
|
||||
/// Children's overflows will be visible.
|
||||
visible,
|
||||
/// Children's overflows will be clipped.
|
||||
clip
|
||||
}
|
||||
|
||||
/// Implements the stack layout algorithm
|
||||
///
|
||||
/// In a stack layout, the children are positioned on top of each other in the
|
||||
@ -244,8 +253,11 @@ class RenderStack extends RenderBox
|
||||
/// top left corners.
|
||||
RenderStack({
|
||||
List<RenderBox> children,
|
||||
FractionalOffset alignment: FractionalOffset.topLeft
|
||||
}) : _alignment = alignment {
|
||||
FractionalOffset alignment: FractionalOffset.topLeft,
|
||||
Overflow overflow: Overflow.clip
|
||||
}) : _alignment = alignment,
|
||||
_overflow = overflow {
|
||||
assert(overflow != null);
|
||||
addAll(children);
|
||||
}
|
||||
|
||||
@ -257,6 +269,20 @@ class RenderStack extends RenderBox
|
||||
child.parentData = new StackParentData();
|
||||
}
|
||||
|
||||
/// Whether overflowing children should be clipped. See [Overflow].
|
||||
///
|
||||
/// Some children in a stack might overflow its box. When this flag is set to
|
||||
/// [Overflow.clipped], children cannot paint outside of the stack's box.
|
||||
Overflow get overflow => _overflow;
|
||||
Overflow _overflow;
|
||||
set overflow (Overflow value) {
|
||||
assert(value != null);
|
||||
if (_overflow != value) {
|
||||
_overflow = value;
|
||||
markNeedsPaint();
|
||||
}
|
||||
}
|
||||
|
||||
/// How to align the non-positioned children in the stack.
|
||||
///
|
||||
/// The non-positioned children are placed relative to each other such that
|
||||
@ -409,7 +435,7 @@ class RenderStack extends RenderBox
|
||||
|
||||
@override
|
||||
void paint(PaintingContext context, Offset offset) {
|
||||
if (_hasVisualOverflow) {
|
||||
if (_overflow == Overflow.clip && _hasVisualOverflow) {
|
||||
context.pushClipRect(needsCompositing, offset, Point.origin & size, paintStack);
|
||||
} else {
|
||||
paintStack(context, offset);
|
||||
|
@ -1394,6 +1394,7 @@ class Stack extends MultiChildRenderObjectWidget {
|
||||
Stack({
|
||||
Key key,
|
||||
this.alignment: FractionalOffset.topLeft,
|
||||
this.overflow: Overflow.clip,
|
||||
List<Widget> children: _emptyWidgetList
|
||||
}) : super(key: key, children: children);
|
||||
|
||||
@ -1405,12 +1406,25 @@ class Stack extends MultiChildRenderObjectWidget {
|
||||
/// each non-positioned child will be located at the same global coordinate.
|
||||
final FractionalOffset alignment;
|
||||
|
||||
/// Whether overflowing children should be clipped. See [Overflow].
|
||||
///
|
||||
/// Some children in a stack might overflow its box. When this flag is set to
|
||||
/// [Overflow.clipped], children cannot paint outside of the stack's box.
|
||||
final Overflow overflow;
|
||||
|
||||
@override
|
||||
RenderStack createRenderObject(BuildContext context) => new RenderStack(alignment: alignment);
|
||||
RenderStack createRenderObject(BuildContext context) {
|
||||
return new RenderStack(
|
||||
alignment: alignment,
|
||||
overflow: overflow
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void updateRenderObject(BuildContext context, RenderStack renderObject) {
|
||||
renderObject.alignment = alignment;
|
||||
renderObject
|
||||
..alignment = alignment
|
||||
..overflow = overflow;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,15 @@ import 'package:flutter/widgets.dart';
|
||||
|
||||
import '../rendering/rendering_tester.dart';
|
||||
|
||||
class TestPaintingContext implements PaintingContext {
|
||||
final List<Invocation> invocations = <Invocation>[];
|
||||
|
||||
@override
|
||||
void noSuchMethod(Invocation invocation) {
|
||||
invocations.add(invocation);
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
testWidgets('Can construct an empty Stack', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(new Stack());
|
||||
@ -253,4 +262,58 @@ void main() {
|
||||
expect(renderBox.size.height, equals(12.0));
|
||||
});
|
||||
|
||||
testWidgets('Stack clip test', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
new Center(
|
||||
child: new Stack(
|
||||
children: <Widget>[
|
||||
new Container(
|
||||
width: 100.0,
|
||||
height: 100.0
|
||||
),
|
||||
new Positioned(
|
||||
top: 0.0,
|
||||
left: 0.0,
|
||||
child: new Container(
|
||||
width: 200.0,
|
||||
height: 200.0
|
||||
)
|
||||
)
|
||||
]
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
RenderBox box = tester.renderObject(find.byType(Stack));
|
||||
TestPaintingContext context = new TestPaintingContext();
|
||||
box.paint(context, Offset.zero);
|
||||
expect(context.invocations.first.memberName, equals(#pushClipRect));
|
||||
|
||||
await tester.pumpWidget(
|
||||
new Center(
|
||||
child: new Stack(
|
||||
overflow: Overflow.visible,
|
||||
children: <Widget>[
|
||||
new Container(
|
||||
width: 100.0,
|
||||
height: 100.0
|
||||
),
|
||||
new Positioned(
|
||||
top: 0.0,
|
||||
left: 0.0,
|
||||
child: new Container(
|
||||
width: 200.0,
|
||||
height: 200.0
|
||||
)
|
||||
)
|
||||
]
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
box = tester.renderObject(find.byType(Stack));
|
||||
context = new TestPaintingContext();
|
||||
box.paint(context, Offset.zero);
|
||||
expect(context.invocations.first.memberName, equals(#paintChild));
|
||||
});
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user