Unverified Commit c4cdbf86 authored by Hans Muller's avatar Hans Muller Committed by GitHub

Transform Widget alignment is AlignmentGeometry (#12870)



* a => an
parent 16c363ac
......@@ -1618,13 +1618,15 @@ class RenderTransform extends RenderProxyBox {
RenderTransform({
@required Matrix4 transform,
Offset origin,
Alignment alignment,
AlignmentGeometry alignment,
TextDirection textDirection,
this.transformHitTests: true,
RenderBox child
}) : assert(transform != null),
super(child) {
this.transform = transform;
this.alignment = alignment;
this.textDirection = textDirection;
this.origin = origin;
}
......@@ -1646,16 +1648,35 @@ class RenderTransform extends RenderProxyBox {
///
/// This is equivalent to setting an origin based on the size of the box.
/// If it is specified at the same time as an offset, both are applied.
Alignment get alignment => _alignment;
Alignment _alignment;
set alignment(Alignment value) {
assert(value == null || (value.x != null && value.y != null));
///
/// An [AlignmentDirectional.start] value is the same as an [Alignment]
/// whose [Alignment.x] value is `-1.0` if [textDirection] is
/// [TextDirection.ltr], and `1.0` if [textDirection] is [TextDirection.rtl].
/// Similarly [AlignmentDirectional.end] is the same as an [Alignment]
/// whose [Alignment.x] value is `1.0` if [textDirection] is
/// [TextDirection.ltr], and `-1.0` if [textDirection] is [TextDirection.rtl].
AlignmentGeometry get alignment => _alignment;
AlignmentGeometry _alignment;
set alignment(AlignmentGeometry value) {
if (_alignment == value)
return;
_alignment = value;
markNeedsPaint();
}
/// The text direction with which to resolve [alignment].
///
/// This may be changed to null, but only after [alignment] has been changed
/// to a value that does not depend on the direction.
TextDirection get textDirection => _textDirection;
TextDirection _textDirection;
set textDirection(TextDirection value) {
if (_textDirection == value)
return;
_textDirection = value;
markNeedsPaint();
}
/// When set to true, hit tests are performed based on the position of the
/// child as it is painted. When set to false, hit tests are performed
/// ignoring the transformation.
......@@ -1713,18 +1734,19 @@ class RenderTransform extends RenderProxyBox {
}
Matrix4 get _effectiveTransform {
if (_origin == null && _alignment == null)
final Alignment resolvedAlignment = alignment?.resolve(textDirection);
if (_origin == null && resolvedAlignment == null)
return _transform;
final Matrix4 result = new Matrix4.identity();
if (_origin != null)
result.translate(_origin.dx, _origin.dy);
Offset translation;
if (_alignment != null) {
translation = _alignment.alongSize(size);
if (resolvedAlignment != null) {
translation = resolvedAlignment.alongSize(size);
result.translate(translation.dx, translation.dy);
}
result.multiply(_transform);
if (_alignment != null)
if (resolvedAlignment != null)
result.translate(-translation.dx, -translation.dy);
if (_origin != null)
result.translate(-_origin.dx, -_origin.dy);
......@@ -1770,6 +1792,7 @@ class RenderTransform extends RenderProxyBox {
description.add(new TransformProperty('transform matrix', _transform));
description.add(new DiagnosticsProperty<Offset>('origin', origin));
description.add(new DiagnosticsProperty<Alignment>('alignment', alignment));
description.add(new EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null));
description.add(new DiagnosticsProperty<bool>('transformHitTests', transformHitTests));
}
}
......@@ -1822,7 +1845,7 @@ class RenderFittedBox extends RenderProxyBox {
/// parent's bounds. An alignment of (1.0, 0.5) aligns the child to the middle
/// of the right edge of its parent's bounds.
///
/// If this is set to a [AlignmentDirectional] object, then
/// If this is set to an [AlignmentDirectional] object, then
/// [textDirection] must not be null.
AlignmentGeometry get alignment => _alignment;
AlignmentGeometry _alignment;
......@@ -1951,7 +1974,7 @@ class RenderFittedBox extends RenderProxyBox {
/// Applies a translation transformation before painting its child.
///
/// The translation is expressed as a [Offset] scaled to the child's size. For
/// The translation is expressed as an [Offset] scaled to the child's size. For
/// example, an [Offset] with a `dx` of 0.25 will result in a horizontal
/// translation of one quarter the width of the child.
///
......
......@@ -794,10 +794,17 @@ class Transform extends SingleChildRenderObjectWidget {
/// The alignment of the origin, relative to the size of the box.
///
/// This is equivalent to setting an origin based on the size of the box.
/// If it is specified at the same time as an offset, both are applied.
final Alignment alignment;
/// If it is specified at the same time as the [origin], both are applied.
///
/// An [AlignmentDirectional.start] value is the same as an [Alignment]
/// whose [Alignment.x] value is `-1.0` if [textDirection] is
/// [TextDirection.ltr], and `1.0` if [textDirection] is [TextDirection.rtl].
/// Similarly [AlignmentDirectional.end] is the same as an [Alignment]
/// whose [Alignment.x] value is `1.0` if [textDirection] is
/// [TextDirection.ltr], and `-1.0` if [textDirection] is [TextDirection.rtl].
final AlignmentGeometry alignment;
/// Whether to apply the translation when performing hit tests.
/// Whether to apply the transformation when performing hit tests.
final bool transformHitTests;
@override
......@@ -806,6 +813,7 @@ class Transform extends SingleChildRenderObjectWidget {
transform: transform,
origin: origin,
alignment: alignment,
textDirection: Directionality.of(context),
transformHitTests: transformHitTests
);
}
......@@ -816,6 +824,7 @@ class Transform extends SingleChildRenderObjectWidget {
..transform = transform
..origin = origin
..alignment = alignment
..textDirection = Directionality.of(context)
..transformHitTests = transformHitTests;
}
}
......@@ -1195,7 +1204,7 @@ class Padding extends SingleChildRenderObjectWidget {
/// * [Center], which is the same as [Align] but with the [alignment] always
/// set to [Alignment.center].
/// * [FractionallySizedBox], which sizes its child based on a fraction of its own
/// size and positions the child according to a [Alignment] value.
/// size and positions the child according to an [Alignment] value.
class Align extends SingleChildRenderObjectWidget {
/// Creates an alignment widget.
///
......@@ -1291,9 +1300,9 @@ class Center extends Align {
///
/// * [SingleChildLayoutDelegate], which controls the layout of the child.
/// * [Align], which sizes itself based on its child's size and positions
/// the child according to a [Alignment] value.
/// the child according to an [Alignment] value.
/// * [FractionallySizedBox], which sizes its child based on a fraction of its own
/// size and positions the child according to a [Alignment] value.
/// size and positions the child according to an [Alignment] value.
/// * [CustomMultiChildLayout], which uses a delegate to position multiple
/// children.
class CustomSingleChildLayout extends SingleChildRenderObjectWidget {
......@@ -1568,7 +1577,7 @@ class ConstrainedBox extends SingleChildRenderObjectWidget {
/// See also:
///
/// * [Align] (which sizes itself based on its child's size and positions
/// the child according to a [Alignment] value)
/// the child according to an [Alignment] value)
/// * [OverflowBox]
class FractionallySizedBox extends SingleChildRenderObjectWidget {
/// Creates a widget that sizes its child to a fraction of the total available space.
......@@ -2269,7 +2278,7 @@ class ListBody extends MultiChildRenderObjectWidget {
/// See also:
///
/// * [Align], which sizes itself based on its child's size and positions
/// the child according to a [Alignment] value.
/// the child according to an [Alignment] value.
/// * [CustomSingleChildLayout], which uses a delegate to control the layout of
/// a single child.
/// * [CustomMultiChildLayout], which uses a delegate to position multiple
......@@ -4023,7 +4032,7 @@ class RawImage extends LeafRenderObjectWidget {
/// How to align the image within its bounds.
///
/// The alignment aligns the given position in the image to the given position
/// in the layout bounds. For example, a [Alignment] alignment of (-1.0,
/// in the layout bounds. For example, an [Alignment] alignment of (-1.0,
/// -1.0) aligns the image to the top-left corner of its layout bounds, while a
/// [Alignment] alignment of (1.0, 1.0) aligns the bottom right of the
/// image with the bottom right corner of its layout bounds. Similarly, an
......
......@@ -106,6 +106,77 @@ void main() {
expect(didReceiveTap, isTrue);
});
testWidgets('Transform AlignmentDirectional alignment', (WidgetTester tester) async {
bool didReceiveTap = false;
Widget buildFrame(TextDirection textDirection, AlignmentGeometry alignment) {
return new Directionality(
textDirection: textDirection,
child: new Stack(
children: <Widget>[
new Positioned(
top: 100.0,
left: 100.0,
child: new Container(
width: 100.0,
height: 100.0,
color: const Color(0xFF0000FF),
),
),
new Positioned(
top: 100.0,
left: 100.0,
child: new Container(
width: 100.0,
height: 100.0,
child: new Transform(
transform: new Matrix4.diagonal3Values(0.5, 0.5, 1.0),
alignment: alignment,
child: new GestureDetector(
onTap: () {
didReceiveTap = true;
},
child: new Container(
color: const Color(0xFF00FFFF),
),
),
),
),
),
],
),
);
}
await tester.pumpWidget(buildFrame(TextDirection.ltr, AlignmentDirectional.centerEnd));
didReceiveTap = false;
await tester.tapAt(const Offset(110.0, 110.0));
expect(didReceiveTap, isFalse);
await tester.tapAt(const Offset(190.0, 150.0));
expect(didReceiveTap, isTrue);
await tester.pumpWidget(buildFrame(TextDirection.rtl, AlignmentDirectional.centerStart));
didReceiveTap = false;
await tester.tapAt(const Offset(110.0, 110.0));
expect(didReceiveTap, isFalse);
await tester.tapAt(const Offset(190.0, 150.0));
expect(didReceiveTap, isTrue);
await tester.pumpWidget(buildFrame(TextDirection.ltr, AlignmentDirectional.centerStart));
didReceiveTap = false;
await tester.tapAt(const Offset(190.0, 150.0));
expect(didReceiveTap, isFalse);
await tester.tapAt(const Offset(110.0, 150.0));
expect(didReceiveTap, isTrue);
await tester.pumpWidget(buildFrame(TextDirection.rtl, AlignmentDirectional.centerEnd));
didReceiveTap = false;
await tester.tapAt(const Offset(190.0, 150.0));
expect(didReceiveTap, isFalse);
await tester.tapAt(const Offset(110.0, 150.0));
expect(didReceiveTap, isTrue);
});
testWidgets('Transform offset + alignment', (WidgetTester tester) async {
bool didReceiveTap = false;
await tester.pumpWidget(
......
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