Restore FractionalOffset operators (#12368)

These now act the way they used to act if both operands are
FractionalOffsets.  Once you mix in some other AlignmentGeometry
objects, everything gets converted to the AlignmentGeometry coordinate
system.
This commit is contained in:
Adam Barth 2017-10-02 21:48:24 -07:00 committed by GitHub
parent 7bfa3c5676
commit 31b6ac049c
3 changed files with 85 additions and 7 deletions

View File

@ -540,7 +540,7 @@ class AlignmentDirectional extends AlignmentGeometry {
if (start == 1.0 && y == 1.0)
return 'AlignmentDirectional.bottomEnd';
return 'AlignmentDirectional(${start.toStringAsFixed(1)}, '
'${y.toStringAsFixed(1)})';
'${y.toStringAsFixed(1)})';
}
@override

View File

@ -21,6 +21,31 @@ import 'basic_types.dart';
/// The [FractionalOffset] class specifies offsets in terms of a distance from
/// the top left, regardless of the [TextDirection].
///
/// ## Design discussion
///
/// [FractionalOffset] and [Alignment] are two different representations of the
/// same information: the location within a rectangle relative to the size of
/// the rectangle. The difference between the two classes is in the coordinate
/// system they use to represent the location.
///
/// [FractionalOffset] uses a coordinate system with an origin in the top-left
/// corner of the rectangle whereas [Alignment] uses a coordinate system with an
/// origin in the center of the rectangle.
///
/// Historically, [FractionalOffset] predates [Alignment]. When we attempted to
/// make a version of [FractionalOffset] that adapted to the [TextDirection], we
/// ran into difficulty because placing the origin in the top-left corner
/// introduced a left-to-right bias that was hard to remove.
///
/// By placing the origin in the center, [Alignment] and [AlignmentDirectional]
/// are able to use the same origin, which means we can use a linear function to
/// resolve an [AlignmentDirectional] into an [Alignment] in both
/// [TextDirection.rtl] and [TextDirection.ltr].
///
/// [Alignment] is better for most purposes than [FractionalOffset] and should
/// be used instead of [FractionalOffset]. We continue to implement
/// [FractionalOffset] to support code that predates [Alignment].
///
/// See also:
///
/// * [Alignment], which uses a coordinate system based on the center of the
@ -108,6 +133,47 @@ class FractionalOffset extends Alignment {
/// The bottom right corner.
static const FractionalOffset bottomRight = const FractionalOffset(1.0, 1.0);
@override
Alignment operator -(Alignment other) {
if (other is! FractionalOffset)
return super - other;
final FractionalOffset typedOther = other;
return new FractionalOffset(dx - typedOther.dx, dy - typedOther.dy);
}
@override
Alignment operator +(Alignment other) {
if (other is! FractionalOffset)
return super + other;
final FractionalOffset typedOther = other;
return new FractionalOffset(dx + typedOther.dx, dy + typedOther.dy);
}
@override
FractionalOffset operator -() {
return new FractionalOffset(-dx, -dy);
}
@override
FractionalOffset operator *(double other) {
return new FractionalOffset(dx * other, dy * other);
}
@override
FractionalOffset operator /(double other) {
return new FractionalOffset(dx / other, dy / other);
}
@override
FractionalOffset operator ~/(double other) {
return new FractionalOffset((dx ~/ other).toDouble(), (dy ~/ other).toDouble());
}
@override
FractionalOffset operator %(double other) {
return new FractionalOffset(dx % other, dy % other);
}
/// Linearly interpolate between two [FractionalOffset]s.
///
/// If either is null, this function interpolates from [FractionalOffset.center].
@ -120,4 +186,10 @@ class FractionalOffset extends Alignment {
return new FractionalOffset(ui.lerpDouble(a.dx, 0.5, t), ui.lerpDouble(a.dy, 0.5, t));
return new FractionalOffset(ui.lerpDouble(a.dx, b.dx, t), ui.lerpDouble(a.dy, b.dy, t));
}
@override
String toString() {
return 'FractionalOffset(${dx.toStringAsFixed(1)}, '
'${dy.toStringAsFixed(1)})';
}
}

View File

@ -7,14 +7,20 @@ import 'package:flutter_test/flutter_test.dart';
void main() {
test('FractionalOffset control test', () {
const FractionalOffset offset = const FractionalOffset(0.5, 0.25);
const FractionalOffset a = const FractionalOffset(0.5, 0.25);
const FractionalOffset b = const FractionalOffset(1.25, 0.75);
expect(offset, hasOneLineDescription);
expect(offset.hashCode, equals(const FractionalOffset(0.5, 0.25).hashCode));
expect(a, hasOneLineDescription);
expect(a.hashCode, equals(const FractionalOffset(0.5, 0.25).hashCode));
expect(a.toString(), equals('FractionalOffset(0.5, 0.3)'));
expect(offset / 2.0, const Alignment(0.0, -0.25));
expect(offset ~/ 2.0, Alignment.center);
expect(offset % 5.0, const Alignment(0.0, 4.5));
expect(-a, const FractionalOffset(-0.5, -0.25));
expect(a - b, const FractionalOffset(-0.75, -0.5));
expect(a + b, const FractionalOffset(1.75, 1.0));
expect(a * 2.0, const FractionalOffset(1.0, 0.5));
expect(a / 2.0, const FractionalOffset(0.25, 0.125));
expect(a ~/ 2.0, const FractionalOffset(0.0, 0.0));
expect(a % 5.0, const FractionalOffset(0.5, 0.25));
});
test('FractionalOffset.lerp()', () {