mirror of
https://github.com/flutter/flutter
synced 2024-10-13 11:42:54 +00:00
Revert "Add CompositedTransformFollower.{followerAnchor, leaderAnchor} for custom anchoring (#64930)" (#65871)
This reverts commit 2fbb529d2b
.
This commit is contained in:
parent
7948a7863b
commit
8eadbb3137
|
@ -3,6 +3,7 @@
|
|||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:collection';
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
@ -2027,14 +2028,6 @@ class LayerLink {
|
|||
LeaderLayer? get leader => _leader;
|
||||
LeaderLayer? _leader;
|
||||
|
||||
/// The total size of [leader]'s contents.
|
||||
///
|
||||
/// Generally this should be set by the [RenderObject] that paints on the
|
||||
/// registered [leader] layer (for instance a [RenderLeaderLayer] that shares
|
||||
/// this link with its followers). This size may be outdated before and during
|
||||
/// layout.
|
||||
Size? leaderSize;
|
||||
|
||||
@override
|
||||
String toString() => '${describeIdentity(this)}(${ _leader != null ? "<linked>" : "<dangling>" })';
|
||||
}
|
||||
|
@ -2273,91 +2266,59 @@ class FollowerLayer extends ContainerLayer {
|
|||
/// treated as the child of the second, and so forth. The first layer in the
|
||||
/// list won't have [applyTransform] called on it. The first layer may be
|
||||
/// null.
|
||||
static Matrix4 _collectTransformForLayerChain(List<ContainerLayer?> layers) {
|
||||
Matrix4 _collectTransformForLayerChain(List<ContainerLayer?> layers) {
|
||||
// Initialize our result matrix.
|
||||
final Matrix4 result = Matrix4.identity();
|
||||
// Apply each layer to the matrix in turn, starting from the last layer,
|
||||
// and providing the previous layer as the child.
|
||||
for (int index = layers.length - 1; index > 0; index -= 1)
|
||||
layers[index]?.applyTransform(layers[index - 1], result);
|
||||
layers[index]!.applyTransform(layers[index - 1], result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Find the common ancestor of two layers [a] and [b] by searching towards
|
||||
/// the root of the tree, and append each ancestor of [a] or [b] visited along
|
||||
/// the path to [ancestorsA] and [ancestorsB] respectively.
|
||||
///
|
||||
/// Returns null if [a] [b] do not share a common ancestor, in which case the
|
||||
/// results in [ancestorsA] and [ancestorsB] are undefined.
|
||||
static Layer? _pathsToCommonAncestor(
|
||||
Layer? a, Layer? b,
|
||||
List<ContainerLayer?> ancestorsA, List<ContainerLayer?> ancestorsB,
|
||||
) {
|
||||
// No common ancestor found.
|
||||
if (a == null || b == null)
|
||||
return null;
|
||||
|
||||
if (identical(a, b))
|
||||
return a;
|
||||
|
||||
if (a.depth < b.depth) {
|
||||
ancestorsB.add(b.parent);
|
||||
return _pathsToCommonAncestor(a, b.parent, ancestorsA, ancestorsB);
|
||||
} else if (a.depth > b.depth){
|
||||
ancestorsA.add(a.parent);
|
||||
return _pathsToCommonAncestor(a.parent, b, ancestorsA, ancestorsB);
|
||||
}
|
||||
|
||||
ancestorsA.add(a.parent);
|
||||
ancestorsB.add(b.parent);
|
||||
return _pathsToCommonAncestor(a.parent, b.parent, ancestorsA, ancestorsB);
|
||||
}
|
||||
|
||||
/// Populate [_lastTransform] given the current state of the tree.
|
||||
void _establishTransform() {
|
||||
assert(link != null);
|
||||
_lastTransform = null;
|
||||
final LeaderLayer? leader = link.leader;
|
||||
// Check to see if we are linked.
|
||||
if (leader == null)
|
||||
if (link.leader == null)
|
||||
return;
|
||||
// If we're linked, check the link is valid.
|
||||
assert(
|
||||
leader.owner == owner,
|
||||
'Linked LeaderLayer anchor is not in the same layer tree as the FollowerLayer.',
|
||||
);
|
||||
assert(
|
||||
leader._lastOffset != null,
|
||||
'LeaderLayer anchor must come before FollowerLayer in paint order, but the reverse was true.',
|
||||
);
|
||||
|
||||
// Stores [leader, ..., commonAncestor] after calling _pathsToCommonAncestor.
|
||||
final List<ContainerLayer?> forwardLayers = <ContainerLayer>[leader];
|
||||
// Stores [this (follower), ..., commonAncestor] after calling
|
||||
// _pathsToCommonAncestor.
|
||||
final List<ContainerLayer?> inverseLayers = <ContainerLayer>[this];
|
||||
|
||||
final Layer? ancestor = _pathsToCommonAncestor(
|
||||
leader, this,
|
||||
forwardLayers, inverseLayers,
|
||||
);
|
||||
assert(ancestor != null);
|
||||
|
||||
assert(link.leader!.owner == owner, 'Linked LeaderLayer anchor is not in the same layer tree as the FollowerLayer.');
|
||||
assert(link.leader!._lastOffset != null, 'LeaderLayer anchor must come before FollowerLayer in paint order, but the reverse was true.');
|
||||
// Collect all our ancestors into a Set so we can recognize them.
|
||||
final Set<Layer> ancestors = HashSet<Layer>();
|
||||
Layer? ancestor = parent;
|
||||
while (ancestor != null) {
|
||||
ancestors.add(ancestor);
|
||||
ancestor = ancestor.parent;
|
||||
}
|
||||
// Collect all the layers from a hypothetical child (null) of the target
|
||||
// layer up to the common ancestor layer.
|
||||
ContainerLayer? layer = link.leader;
|
||||
final List<ContainerLayer?> forwardLayers = <ContainerLayer?>[null, layer];
|
||||
do {
|
||||
layer = layer!.parent;
|
||||
forwardLayers.add(layer);
|
||||
} while (!ancestors.contains(layer)); // ignore: iterable_contains_unrelated_type
|
||||
ancestor = layer;
|
||||
// Collect all the layers from this layer up to the common ancestor layer.
|
||||
layer = this;
|
||||
final List<ContainerLayer> inverseLayers = <ContainerLayer>[layer];
|
||||
do {
|
||||
layer = layer!.parent;
|
||||
inverseLayers.add(layer!);
|
||||
} while (layer != ancestor);
|
||||
// Establish the forward and backward matrices given these lists of layers.
|
||||
final Matrix4 forwardTransform = _collectTransformForLayerChain(forwardLayers);
|
||||
// Further transforms the coordinate system to a hypothetical child (null)
|
||||
// of the leader layer, to account for the leader's additional paint offset
|
||||
// and layer offset (LeaderLayer._lastOffset).
|
||||
leader.applyTransform(null, forwardTransform);
|
||||
forwardTransform.translate(linkedOffset!.dx, linkedOffset!.dy);
|
||||
|
||||
final Matrix4 inverseTransform = _collectTransformForLayerChain(inverseLayers);
|
||||
|
||||
if (inverseTransform.invert() == 0.0) {
|
||||
// We are in a degenerate transform, so there's not much we can do.
|
||||
return;
|
||||
}
|
||||
// Combine the matrices and store the result.
|
||||
inverseTransform.multiply(forwardTransform);
|
||||
inverseTransform.translate(linkedOffset!.dx, linkedOffset!.dy);
|
||||
_lastTransform = inverseTransform;
|
||||
_inverseDirty = true;
|
||||
}
|
||||
|
|
|
@ -4826,37 +4826,28 @@ class RenderLeaderLayer extends RenderProxyBox {
|
|||
required LayerLink link,
|
||||
RenderBox? child,
|
||||
}) : assert(link != null),
|
||||
_link = link,
|
||||
super(child);
|
||||
super(child) {
|
||||
this.link = link;
|
||||
}
|
||||
|
||||
/// The link object that connects this [RenderLeaderLayer] with one or more
|
||||
/// [RenderFollowerLayer]s.
|
||||
///
|
||||
/// This property must not be null. The object must not be associated with
|
||||
/// another [RenderLeaderLayer] that is also being painted.
|
||||
LayerLink get link => _link;
|
||||
LayerLink _link;
|
||||
LayerLink get link => _link!;
|
||||
LayerLink? _link;
|
||||
set link(LayerLink value) {
|
||||
assert(value != null);
|
||||
if (_link == value)
|
||||
return;
|
||||
_link.leaderSize = null;
|
||||
_link = value;
|
||||
if (hasSize) {
|
||||
_link.leaderSize = size;
|
||||
}
|
||||
markNeedsPaint();
|
||||
}
|
||||
|
||||
@override
|
||||
bool get alwaysNeedsCompositing => true;
|
||||
|
||||
@override
|
||||
void performLayout() {
|
||||
super.performLayout();
|
||||
link.leaderSize = size;
|
||||
}
|
||||
|
||||
@override
|
||||
void paint(PaintingContext context, Offset offset) {
|
||||
if (layer == null) {
|
||||
|
@ -4899,8 +4890,6 @@ class RenderFollowerLayer extends RenderProxyBox {
|
|||
required LayerLink link,
|
||||
bool showWhenUnlinked = true,
|
||||
Offset offset = Offset.zero,
|
||||
Alignment leaderAnchor = Alignment.topLeft,
|
||||
Alignment followerAnchor = Alignment.topLeft,
|
||||
RenderBox? child,
|
||||
}) : assert(link != null),
|
||||
assert(showWhenUnlinked != null),
|
||||
|
@ -4908,8 +4897,6 @@ class RenderFollowerLayer extends RenderProxyBox {
|
|||
_link = link,
|
||||
_showWhenUnlinked = showWhenUnlinked,
|
||||
_offset = offset,
|
||||
_leaderAnchor = leaderAnchor,
|
||||
_followerAnchor = followerAnchor,
|
||||
super(child);
|
||||
|
||||
/// The link object that connects this [RenderFollowerLayer] with a
|
||||
|
@ -4955,46 +4942,6 @@ class RenderFollowerLayer extends RenderProxyBox {
|
|||
markNeedsPaint();
|
||||
}
|
||||
|
||||
/// The anchor point on the linked [RenderLeaderLayer] that [followerAnchor]
|
||||
/// will line up with.
|
||||
///
|
||||
/// {@template flutter.rendering.followerLayer.anchor}
|
||||
/// For example, when [leaderAnchor] and [followerAnchor] are both
|
||||
/// [Alignment.topLeft], this [RenderFollowerLayer] will be top left aligned
|
||||
/// with the linked [RenderLeaderLayer]. When [leaderAnchor] is
|
||||
/// [Alignment.bottomLeft] and [followerAnchor] is [Alignment.topLeft], this
|
||||
/// [RenderFollowerLayer] will be left aligned with the linked
|
||||
/// [RenderLeaderLayer], and its top edge will line up with the
|
||||
/// [RenderLeaderLayer]'s bottom edge.
|
||||
/// {@endtemplate}
|
||||
///
|
||||
/// Defaults to [Alignment.topLeft].
|
||||
Alignment get leaderAnchor => _leaderAnchor;
|
||||
Alignment _leaderAnchor;
|
||||
set leaderAnchor(Alignment value) {
|
||||
assert(value != null);
|
||||
if (_leaderAnchor == value)
|
||||
return;
|
||||
_leaderAnchor = value;
|
||||
markNeedsPaint();
|
||||
}
|
||||
|
||||
/// The anchor point on this [RenderFollowerLayer] that will line up with
|
||||
/// [followerAnchor] on the linked [RenderLeaderLayer].
|
||||
///
|
||||
/// {@macro flutter.rendering.followerLayer.anchor}
|
||||
///
|
||||
/// Defaults to [Alignment.topLeft].
|
||||
Alignment get followerAnchor => _followerAnchor;
|
||||
Alignment _followerAnchor;
|
||||
set followerAnchor(Alignment value) {
|
||||
assert(value != null);
|
||||
if (_followerAnchor == value)
|
||||
return;
|
||||
_followerAnchor = value;
|
||||
markNeedsPaint();
|
||||
}
|
||||
|
||||
@override
|
||||
void detach() {
|
||||
layer = null;
|
||||
|
@ -5043,29 +4990,19 @@ class RenderFollowerLayer extends RenderProxyBox {
|
|||
|
||||
@override
|
||||
void paint(PaintingContext context, Offset offset) {
|
||||
final Size? leaderSize = link.leaderSize;
|
||||
assert(
|
||||
link.leaderSize != null || (link.leader == null || leaderAnchor == Alignment.topLeft),
|
||||
'$link: layer is linked to ${link.leader} but a valid leaderSize is not set. '
|
||||
'leaderSize is required when leaderAnchor is not Alignment.topLeft'
|
||||
'(current value is $leaderAnchor).',
|
||||
);
|
||||
final Offset effectiveLinkedOffset = leaderSize == null
|
||||
? this.offset
|
||||
: leaderAnchor.alongSize(leaderSize) - followerAnchor.alongSize(size) + this.offset;
|
||||
assert(showWhenUnlinked != null);
|
||||
if (layer == null) {
|
||||
layer = FollowerLayer(
|
||||
link: link,
|
||||
showWhenUnlinked: showWhenUnlinked,
|
||||
linkedOffset: effectiveLinkedOffset,
|
||||
linkedOffset: this.offset,
|
||||
unlinkedOffset: offset,
|
||||
);
|
||||
} else {
|
||||
layer
|
||||
?..link = link
|
||||
layer!
|
||||
..link = link
|
||||
..showWhenUnlinked = showWhenUnlinked
|
||||
..linkedOffset = effectiveLinkedOffset
|
||||
..linkedOffset = this.offset
|
||||
..unlinkedOffset = offset;
|
||||
}
|
||||
context.pushLayer(
|
||||
|
|
|
@ -1327,11 +1327,9 @@ class CompositedTransformTarget extends SingleChildRenderObjectWidget {
|
|||
///
|
||||
/// When this widget is composited during the compositing phase (which comes
|
||||
/// after the paint phase, as described in [WidgetsBinding.drawFrame]), it
|
||||
/// applies a transformation that brings [targetAnchor] of the linked
|
||||
/// [CompositedTransformTarget] and [followerAnchor] of this widget together.
|
||||
/// The two anchor points will have the same global coordinates, unless [offset]
|
||||
/// is not [Offset.zero], in which case [followerAnchor] will be offset by
|
||||
/// [offset] in the linked [CompositedTransformTarget]'s coordinate space.
|
||||
/// applies a transformation that causes it to provide its child with a
|
||||
/// coordinate space that matches that of the linked [CompositedTransformTarget]
|
||||
/// widget, offset by [offset].
|
||||
///
|
||||
/// The [LayerLink] object used as the [link] must be the same object as that
|
||||
/// provided to the matching [CompositedTransformTarget].
|
||||
|
@ -1363,14 +1361,10 @@ class CompositedTransformFollower extends SingleChildRenderObjectWidget {
|
|||
required this.link,
|
||||
this.showWhenUnlinked = true,
|
||||
this.offset = Offset.zero,
|
||||
this.targetAnchor = Alignment.topLeft,
|
||||
this.followerAnchor = Alignment.topLeft,
|
||||
Widget? child,
|
||||
}) : assert(link != null),
|
||||
assert(showWhenUnlinked != null),
|
||||
assert(offset != null),
|
||||
assert(targetAnchor != null),
|
||||
assert(followerAnchor != null),
|
||||
super(key: key, child: child);
|
||||
|
||||
/// The link object that connects this [CompositedTransformFollower] with a
|
||||
|
@ -1390,33 +1384,8 @@ class CompositedTransformFollower extends SingleChildRenderObjectWidget {
|
|||
/// hidden.
|
||||
final bool showWhenUnlinked;
|
||||
|
||||
/// The anchor point on the linked [CompositedTransformTarget] that
|
||||
/// [followerAnchor] will line up with.
|
||||
///
|
||||
/// {@template flutter.widgets.followerLayer.anchor}
|
||||
/// For example, when [targetAnchor] and [followerAnchor] are both
|
||||
/// [Alignment.topLeft], this widget will be top left aligned with the linked
|
||||
/// [CompositedTransformTarget]. When [targetAnchor] is
|
||||
/// [Alignment.bottomLeft] and [followerAnchor] is [Alignment.topLeft], this
|
||||
/// widget will be left aligned with the linked [CompositedTransformTarget],
|
||||
/// and its top edge will line up with the [CompositedTransformTarget]'s
|
||||
/// bottom edge.
|
||||
/// {@endtemplate}
|
||||
///
|
||||
/// Defaults to [Alignment.topLeft].
|
||||
final Alignment targetAnchor;
|
||||
|
||||
/// The anchor point on this widget that will line up with [followerAnchor] on
|
||||
/// the linked [CompositedTransformTarget].
|
||||
///
|
||||
/// {@macro flutter.widgets.followerLayer.anchor}
|
||||
///
|
||||
/// Defaults to [Alignment.topLeft].
|
||||
final Alignment followerAnchor;
|
||||
|
||||
/// The additional offset to apply to the [targetAnchor] of the linked
|
||||
/// [CompositedTransformTarget] to obtain this widget's [followerAnchor]
|
||||
/// position.
|
||||
/// The offset to apply to the origin of the linked
|
||||
/// [CompositedTransformTarget] to obtain this widget's origin.
|
||||
final Offset offset;
|
||||
|
||||
@override
|
||||
|
@ -1425,8 +1394,6 @@ class CompositedTransformFollower extends SingleChildRenderObjectWidget {
|
|||
link: link,
|
||||
showWhenUnlinked: showWhenUnlinked,
|
||||
offset: offset,
|
||||
leaderAnchor: targetAnchor,
|
||||
followerAnchor: followerAnchor,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1435,9 +1402,7 @@ class CompositedTransformFollower extends SingleChildRenderObjectWidget {
|
|||
renderObject
|
||||
..link = link
|
||||
..showWhenUnlinked = showWhenUnlinked
|
||||
..offset = offset
|
||||
..leaderAnchor = targetAnchor
|
||||
..followerAnchor = followerAnchor;
|
||||
..offset = offset;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,12 +9,11 @@ import 'package:flutter/rendering.dart';
|
|||
import 'package:flutter/widgets.dart';
|
||||
|
||||
void main() {
|
||||
final LayerLink link = LayerLink();
|
||||
group('Composited transforms - only offsets', () {
|
||||
testWidgets('Composited transforms - only offsets', (WidgetTester tester) async {
|
||||
final LayerLink link = LayerLink();
|
||||
final GlobalKey key = GlobalKey();
|
||||
|
||||
Widget build({ @required Alignment targetAlignment, @required Alignment followerAlignment }) {
|
||||
return Directionality(
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
|
@ -31,41 +30,23 @@ void main() {
|
|||
top: 343.0,
|
||||
child: CompositedTransformFollower(
|
||||
link: link,
|
||||
targetAnchor: targetAlignment,
|
||||
followerAnchor: followerAlignment,
|
||||
child: Container(key: key, height: 20.0, width: 20.0),
|
||||
child: Container(key: key, height: 10.0, width: 10.0),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
testWidgets('topLeft', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(build(targetAlignment: Alignment.topLeft, followerAlignment: Alignment.topLeft));
|
||||
final RenderBox box = key.currentContext.findRenderObject() as RenderBox;
|
||||
expect(box.localToGlobal(Offset.zero), const Offset(123.0, 456.0));
|
||||
});
|
||||
|
||||
testWidgets('center', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(build(targetAlignment: Alignment.center, followerAlignment: Alignment.center));
|
||||
final RenderBox box = key.currentContext.findRenderObject() as RenderBox;
|
||||
expect(box.localToGlobal(Offset.zero), const Offset(118.0, 451.0));
|
||||
});
|
||||
|
||||
testWidgets('bottomRight - topRight', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(build(targetAlignment: Alignment.bottomRight, followerAlignment: Alignment.topRight));
|
||||
final RenderBox box = key.currentContext.findRenderObject() as RenderBox;
|
||||
expect(box.localToGlobal(Offset.zero), const Offset(113.0, 466.0));
|
||||
});
|
||||
),
|
||||
);
|
||||
final RenderBox box = key.currentContext.findRenderObject() as RenderBox;
|
||||
expect(box.localToGlobal(Offset.zero), const Offset(123.0, 456.0));
|
||||
});
|
||||
|
||||
group('Composited transforms - with rotations', () {
|
||||
testWidgets('Composited transforms - with rotations', (WidgetTester tester) async {
|
||||
final LayerLink link = LayerLink();
|
||||
final GlobalKey key1 = GlobalKey();
|
||||
final GlobalKey key2 = GlobalKey();
|
||||
|
||||
Widget build({ @required Alignment targetAlignment, @required Alignment followerAlignment }) {
|
||||
return Directionality(
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
|
@ -76,7 +57,7 @@ void main() {
|
|||
angle: 1.0, // radians
|
||||
child: CompositedTransformTarget(
|
||||
link: link,
|
||||
child: Container(key: key1, width: 80.0, height: 10.0),
|
||||
child: Container(key: key1, height: 10.0, width: 10.0),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -87,50 +68,28 @@ void main() {
|
|||
angle: -0.3, // radians
|
||||
child: CompositedTransformFollower(
|
||||
link: link,
|
||||
targetAnchor: targetAlignment,
|
||||
followerAnchor: followerAlignment,
|
||||
child: Container(key: key2, width: 40.0, height: 20.0),
|
||||
child: Container(key: key2, height: 10.0, width: 10.0),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
testWidgets('topLeft', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(build(targetAlignment: Alignment.topLeft, followerAlignment: Alignment.topLeft));
|
||||
final RenderBox box1 = key1.currentContext.findRenderObject() as RenderBox;
|
||||
final RenderBox box2 = key2.currentContext.findRenderObject() as RenderBox;
|
||||
final Offset position1 = box1.localToGlobal(Offset.zero);
|
||||
final Offset position2 = box2.localToGlobal(Offset.zero);
|
||||
expect(position1, offsetMoreOrLessEquals(position2));
|
||||
});
|
||||
|
||||
testWidgets('center', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(build(targetAlignment: Alignment.center, followerAlignment: Alignment.center));
|
||||
final RenderBox box1 = key1.currentContext.findRenderObject() as RenderBox;
|
||||
final RenderBox box2 = key2.currentContext.findRenderObject() as RenderBox;
|
||||
final Offset position1 = box1.localToGlobal(const Offset(40, 5));
|
||||
final Offset position2 = box2.localToGlobal(const Offset(20, 10));
|
||||
expect(position1, offsetMoreOrLessEquals(position2));
|
||||
});
|
||||
|
||||
testWidgets('bottomRight - topRight', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(build(targetAlignment: Alignment.bottomRight, followerAlignment: Alignment.topRight));
|
||||
final RenderBox box1 = key1.currentContext.findRenderObject() as RenderBox;
|
||||
final RenderBox box2 = key2.currentContext.findRenderObject() as RenderBox;
|
||||
final Offset position1 = box1.localToGlobal(const Offset(80, 10));
|
||||
final Offset position2 = box2.localToGlobal(const Offset(40, 0));
|
||||
expect(position1, offsetMoreOrLessEquals(position2));
|
||||
});
|
||||
),
|
||||
);
|
||||
final RenderBox box1 = key1.currentContext.findRenderObject() as RenderBox;
|
||||
final RenderBox box2 = key2.currentContext.findRenderObject() as RenderBox;
|
||||
final Offset position1 = box1.localToGlobal(Offset.zero);
|
||||
final Offset position2 = box2.localToGlobal(Offset.zero);
|
||||
expect(position1.dx, moreOrLessEquals(position2.dx));
|
||||
expect(position1.dy, moreOrLessEquals(position2.dy));
|
||||
});
|
||||
|
||||
group('Composited transforms - nested', () {
|
||||
testWidgets('Composited transforms - nested', (WidgetTester tester) async {
|
||||
final LayerLink link = LayerLink();
|
||||
final GlobalKey key1 = GlobalKey();
|
||||
final GlobalKey key2 = GlobalKey();
|
||||
|
||||
Widget build({ @required Alignment targetAlignment, @required Alignment followerAlignment }) {
|
||||
return Directionality(
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
|
@ -141,7 +100,7 @@ void main() {
|
|||
angle: 1.0, // radians
|
||||
child: CompositedTransformTarget(
|
||||
link: link,
|
||||
child: Container(key: key1, width: 80.0, height: 10.0),
|
||||
child: Container(key: key1, height: 10.0, width: 10.0),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -160,9 +119,7 @@ void main() {
|
|||
padding: const EdgeInsets.all(20.0),
|
||||
child: CompositedTransformFollower(
|
||||
link: link,
|
||||
targetAnchor: targetAlignment,
|
||||
followerAnchor: followerAlignment,
|
||||
child: Container(key: key2, width: 40.0, height: 20.0),
|
||||
child: Container(key: key2, height: 10.0, width: 10.0),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -172,45 +129,24 @@ void main() {
|
|||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
testWidgets('topLeft', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(build(targetAlignment: Alignment.topLeft, followerAlignment: Alignment.topLeft));
|
||||
final RenderBox box1 = key1.currentContext.findRenderObject() as RenderBox;
|
||||
final RenderBox box2 = key2.currentContext.findRenderObject() as RenderBox;
|
||||
final Offset position1 = box1.localToGlobal(Offset.zero);
|
||||
final Offset position2 = box2.localToGlobal(Offset.zero);
|
||||
expect(position1, offsetMoreOrLessEquals(position2));
|
||||
});
|
||||
|
||||
testWidgets('center', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(build(targetAlignment: Alignment.center, followerAlignment: Alignment.center));
|
||||
final RenderBox box1 = key1.currentContext.findRenderObject() as RenderBox;
|
||||
final RenderBox box2 = key2.currentContext.findRenderObject() as RenderBox;
|
||||
final Offset position1 = box1.localToGlobal(Alignment.center.alongSize(const Size(80, 10)));
|
||||
final Offset position2 = box2.localToGlobal(Alignment.center.alongSize(const Size(40, 20)));
|
||||
expect(position1, offsetMoreOrLessEquals(position2));
|
||||
});
|
||||
|
||||
testWidgets('bottomRight - topRight', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(build(targetAlignment: Alignment.bottomRight, followerAlignment: Alignment.topRight));
|
||||
final RenderBox box1 = key1.currentContext.findRenderObject() as RenderBox;
|
||||
final RenderBox box2 = key2.currentContext.findRenderObject() as RenderBox;
|
||||
final Offset position1 = box1.localToGlobal(Alignment.bottomRight.alongSize(const Size(80, 10)));
|
||||
final Offset position2 = box2.localToGlobal(Alignment.topRight.alongSize(const Size(40, 20)));
|
||||
expect(position1, offsetMoreOrLessEquals(position2));
|
||||
});
|
||||
),
|
||||
);
|
||||
final RenderBox box1 = key1.currentContext.findRenderObject() as RenderBox;
|
||||
final RenderBox box2 = key2.currentContext.findRenderObject() as RenderBox;
|
||||
final Offset position1 = box1.localToGlobal(Offset.zero);
|
||||
final Offset position2 = box2.localToGlobal(Offset.zero);
|
||||
expect(position1.dx, moreOrLessEquals(position2.dx));
|
||||
expect(position1.dy, moreOrLessEquals(position2.dy));
|
||||
});
|
||||
|
||||
group('Composited transforms - hit testing', () {
|
||||
testWidgets('Composited transforms - hit testing', (WidgetTester tester) async {
|
||||
final LayerLink link = LayerLink();
|
||||
final GlobalKey key1 = GlobalKey();
|
||||
final GlobalKey key2 = GlobalKey();
|
||||
final GlobalKey key3 = GlobalKey();
|
||||
|
||||
bool tapped = false;
|
||||
|
||||
Widget build({ @required Alignment targetAlignment, @required Alignment followerAlignment }) {
|
||||
return Directionality(
|
||||
bool _tapped = false;
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
|
@ -227,34 +163,18 @@ void main() {
|
|||
child: GestureDetector(
|
||||
key: key2,
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTap: () { tapped = true; },
|
||||
child: Container(key: key3, height: 2.0, width: 2.0),
|
||||
onTap: () { _tapped = true; },
|
||||
child: Container(key: key3, height: 10.0, width: 10.0),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
const List<Alignment> alignments = <Alignment>[
|
||||
Alignment.topLeft, Alignment.topRight,
|
||||
Alignment.center,
|
||||
Alignment.bottomLeft, Alignment.bottomRight,
|
||||
];
|
||||
|
||||
setUp(() { tapped = false; });
|
||||
|
||||
for (final Alignment targetAlignment in alignments) {
|
||||
for (final Alignment followerAlignment in alignments) {
|
||||
testWidgets('$targetAlignment - $followerAlignment', (WidgetTester tester) async{
|
||||
await tester.pumpWidget(build(targetAlignment: targetAlignment, followerAlignment: followerAlignment));
|
||||
final RenderBox box2 = key2.currentContext.findRenderObject() as RenderBox;
|
||||
expect(box2.size, const Size(2.0, 2.0));
|
||||
expect(tapped, isFalse);
|
||||
await tester.tap(find.byKey(key3));
|
||||
expect(tapped, isTrue);
|
||||
});
|
||||
}
|
||||
}
|
||||
),
|
||||
);
|
||||
final RenderBox box2 = key2.currentContext.findRenderObject() as RenderBox;
|
||||
expect(box2.size, const Size(10.0, 10.0));
|
||||
expect(_tapped, isFalse);
|
||||
await tester.tap(find.byKey(key1));
|
||||
expect(_tapped, isTrue);
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue