LinearGradient and RadialGradient RTL (#12204)
This commit is contained in:
parent
4f6e350b6e
commit
daedbc84a2
@ -25,7 +25,11 @@ abstract class Gradient {
|
|||||||
const Gradient();
|
const Gradient();
|
||||||
|
|
||||||
/// Creates a [Shader] for this gradient to fill the given rect.
|
/// Creates a [Shader] for this gradient to fill the given rect.
|
||||||
Shader createShader(Rect rect);
|
///
|
||||||
|
/// If the gradient's configuration is text-direction-dependent, for example
|
||||||
|
/// it uses [FractionalOffsetDirection] objects instead of [FractionalOffset]
|
||||||
|
/// objects, then the `textDirection` argument must not be null.
|
||||||
|
Shader createShader(Rect rect, { TextDirection textDirection });
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A 2D linear gradient.
|
/// A 2D linear gradient.
|
||||||
@ -91,21 +95,37 @@ class LinearGradient extends Gradient {
|
|||||||
assert(colors != null),
|
assert(colors != null),
|
||||||
assert(tileMode != null);
|
assert(tileMode != null);
|
||||||
|
|
||||||
/// The offset from coordinate (0.0,0.0) at which stop 0.0 of the
|
/// The offset at which stop 0.0 of the gradient is placed.
|
||||||
/// gradient is placed, in a coordinate space that maps the top left
|
///
|
||||||
/// of the paint box at (0.0,0.0) and the bottom right at (1.0,1.0).
|
/// If this is a [FractionalOffset], then it is expressed as a vector from
|
||||||
|
/// coordinate (0.0,0.0), in a coordinate space that maps the top left of the
|
||||||
|
/// paint box at (0.0,0.0) and the bottom right at (1.0,1.0).
|
||||||
///
|
///
|
||||||
/// For example, a begin offset of (0.0,0.5) is half way down the
|
/// For example, a begin offset of (0.0,0.5) is half way down the
|
||||||
/// left side of the box.
|
/// left side of the box.
|
||||||
final FractionalOffset begin;
|
|
||||||
|
|
||||||
/// The offset from coordinate (0.0,0.0) at which stop 1.0 of the
|
|
||||||
/// gradient is placed, in a coordinate space that maps the top left
|
|
||||||
/// of the paint box at (0.0,0.0) and the bottom right at (1.0,1.0).
|
|
||||||
///
|
///
|
||||||
/// For example, an end offset of (1.0,0.5) is half way down the
|
/// It can also be a [FractionalOffsetDirectional], in which case it is
|
||||||
|
/// expressed as a vector from the top start corner, where the start is the
|
||||||
|
/// left in left-to-right contexts and the right in right-to-left contexts. If
|
||||||
|
/// a text-direction-dependent value is provided here, then the [createShader]
|
||||||
|
/// method will need to be given a [TextDirection].
|
||||||
|
final FractionalOffsetGeometry begin;
|
||||||
|
|
||||||
|
/// The offset at which stop 1.0 of the gradient is placed.
|
||||||
|
///
|
||||||
|
/// If this is a [FractionalOffset], then it is expressed as a vector from
|
||||||
|
/// coordinate (0.0,0.0), in a coordinate space that maps the top left of the
|
||||||
|
/// paint box at (0.0,0.0) and the bottom right at (1.0,1.0).
|
||||||
|
///
|
||||||
|
/// For example, a begin offset of (1.0,0.5) is half way down the
|
||||||
/// right side of the box.
|
/// right side of the box.
|
||||||
final FractionalOffset end;
|
///
|
||||||
|
/// It can also be a [FractionalOffsetDirectional], in which case it is
|
||||||
|
/// expressed as a vector from the top start corner, where the start is the
|
||||||
|
/// left in left-to-right contexts and the right in right-to-left contexts. If
|
||||||
|
/// a text-direction-dependent value is provided here, then the [createShader]
|
||||||
|
/// method will need to be given a [TextDirection].
|
||||||
|
final FractionalOffsetGeometry end;
|
||||||
|
|
||||||
/// The colors the gradient should obtain at each of the stops.
|
/// The colors the gradient should obtain at each of the stops.
|
||||||
///
|
///
|
||||||
@ -144,16 +164,20 @@ class LinearGradient extends Gradient {
|
|||||||
final TileMode tileMode;
|
final TileMode tileMode;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Shader createShader(Rect rect) {
|
Shader createShader(Rect rect, { TextDirection textDirection }) {
|
||||||
return new ui.Gradient.linear(
|
return new ui.Gradient.linear(
|
||||||
begin.withinRect(rect),
|
begin.resolve(textDirection).withinRect(rect),
|
||||||
end.withinRect(rect),
|
end.resolve(textDirection).withinRect(rect),
|
||||||
colors, stops, tileMode,
|
colors, stops, tileMode,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a new [LinearGradient] with its properties scaled by the given
|
/// Returns a new [LinearGradient] with its properties (in particular the
|
||||||
/// factor.
|
/// colors) scaled by the given factor.
|
||||||
|
///
|
||||||
|
/// If the factor is 1.0 or greater, then the gradient is returned unmodified.
|
||||||
|
/// If the factor is 0.0 or less, then the gradient is fully transparent.
|
||||||
|
/// Values in between scale the opacity of the colors.
|
||||||
LinearGradient scale(double factor) {
|
LinearGradient scale(double factor) {
|
||||||
return new LinearGradient(
|
return new LinearGradient(
|
||||||
begin: begin,
|
begin: begin,
|
||||||
@ -168,7 +192,7 @@ class LinearGradient extends Gradient {
|
|||||||
///
|
///
|
||||||
/// If either gradient is null, this function linearly interpolates from a
|
/// If either gradient is null, this function linearly interpolates from a
|
||||||
/// a gradient that matches the other gradient in [begin], [end], [stops] and
|
/// a gradient that matches the other gradient in [begin], [end], [stops] and
|
||||||
/// [tileMode] and with the same [colors] but transparent.
|
/// [tileMode] and with the same [colors] but transparent (using [scale]).
|
||||||
///
|
///
|
||||||
/// If neither gradient is null, they must have the same number of [colors].
|
/// If neither gradient is null, they must have the same number of [colors].
|
||||||
static LinearGradient lerp(LinearGradient a, LinearGradient b, double t) {
|
static LinearGradient lerp(LinearGradient a, LinearGradient b, double t) {
|
||||||
@ -178,11 +202,7 @@ class LinearGradient extends Gradient {
|
|||||||
return b.scale(t);
|
return b.scale(t);
|
||||||
if (b == null)
|
if (b == null)
|
||||||
return a.scale(1.0 - t);
|
return a.scale(1.0 - t);
|
||||||
// Interpolation is only possible when the lengths of colors and stops are
|
assert(a.colors.length == b.colors.length, 'Cannot interpolate between two gradients with a different number of colors.');
|
||||||
// the same or stops is null for one.
|
|
||||||
// TODO(xster): lerp unsimilar LinearGradients in the future by scaling
|
|
||||||
// lists of LinearGradients.
|
|
||||||
assert(a.colors.length == b.colors.length);
|
|
||||||
assert(a.stops == null || b.stops == null || a.stops.length == b.stops.length);
|
assert(a.stops == null || b.stops == null || a.stops.length == b.stops.length);
|
||||||
final List<Color> interpolatedColors = <Color>[];
|
final List<Color> interpolatedColors = <Color>[];
|
||||||
for (int i = 0; i < a.colors.length; i += 1)
|
for (int i = 0; i < a.colors.length; i += 1)
|
||||||
@ -195,8 +215,8 @@ class LinearGradient extends Gradient {
|
|||||||
interpolatedStops = a.stops ?? b.stops;
|
interpolatedStops = a.stops ?? b.stops;
|
||||||
}
|
}
|
||||||
return new LinearGradient(
|
return new LinearGradient(
|
||||||
begin: FractionalOffset.lerp(a.begin, b.begin, t),
|
begin: FractionalOffsetGeometry.lerp(a.begin, b.begin, t),
|
||||||
end: FractionalOffset.lerp(a.end, b.end, t),
|
end: FractionalOffsetGeometry.lerp(a.end, b.end, t),
|
||||||
colors: interpolatedColors,
|
colors: interpolatedColors,
|
||||||
stops: interpolatedStops,
|
stops: interpolatedStops,
|
||||||
tileMode: t < 0.5 ? a.tileMode : b.tileMode,
|
tileMode: t < 0.5 ? a.tileMode : b.tileMode,
|
||||||
@ -240,7 +260,7 @@ class LinearGradient extends Gradient {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'LinearGradient($begin, $end, $colors, $stops, $tileMode)';
|
return '$runtimeType($begin, $end, $colors, $stops, $tileMode)';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,7 +339,17 @@ class RadialGradient extends Gradient {
|
|||||||
///
|
///
|
||||||
/// For example, an offset of (0.5,0.5) will place the radial
|
/// For example, an offset of (0.5,0.5) will place the radial
|
||||||
/// gradient in the center of the box.
|
/// gradient in the center of the box.
|
||||||
final FractionalOffset center;
|
///
|
||||||
|
/// If this is a [FractionalOffset], then it is expressed as a vector from
|
||||||
|
/// coordinate (0.0,0.0), in a coordinate space that maps the top left of the
|
||||||
|
/// paint box at (0.0,0.0) and the bottom right at (1.0,1.0).
|
||||||
|
///
|
||||||
|
/// It can also be a [FractionalOffsetDirectional], in which case it is
|
||||||
|
/// expressed as a vector from the top start corner, where the start is the
|
||||||
|
/// left in left-to-right contexts and the right in right-to-left contexts. If
|
||||||
|
/// a text-direction-dependent value is provided here, then the [createShader]
|
||||||
|
/// method will need to be given a [TextDirection].
|
||||||
|
final FractionalOffsetGeometry center;
|
||||||
|
|
||||||
/// The radius of the gradient, as a fraction of the shortest side
|
/// The radius of the gradient, as a fraction of the shortest side
|
||||||
/// of the paint box.
|
/// of the paint box.
|
||||||
@ -368,11 +398,11 @@ class RadialGradient extends Gradient {
|
|||||||
final TileMode tileMode;
|
final TileMode tileMode;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Shader createShader(Rect rect) {
|
Shader createShader(Rect rect, { TextDirection textDirection }) {
|
||||||
return new ui.Gradient.radial(
|
return new ui.Gradient.radial(
|
||||||
center.withinRect(rect),
|
center.resolve(textDirection).withinRect(rect),
|
||||||
radius * rect.shortestSide,
|
radius * rect.shortestSide,
|
||||||
colors, stops, tileMode
|
colors, stops, tileMode,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -413,6 +443,6 @@ class RadialGradient extends Gradient {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'RadialGradient($center, $radius, $colors, $stops, $tileMode)';
|
return '$runtimeType($center, $radius, $colors, $stops, $tileMode)';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,74 +112,4 @@ void main() {
|
|||||||
test('BoxShadow toString test', () {
|
test('BoxShadow toString test', () {
|
||||||
expect(const BoxShadow(blurRadius: 4.0).toString(), equals('BoxShadow(Color(0xff000000), Offset(0.0, 0.0), 4.0, 0.0)'));
|
expect(const BoxShadow(blurRadius: 4.0).toString(), equals('BoxShadow(Color(0xff000000), Offset(0.0, 0.0), 4.0, 0.0)'));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('LinearGradient scale test', () {
|
|
||||||
final LinearGradient testGradient = const LinearGradient(
|
|
||||||
begin: FractionalOffset.bottomRight,
|
|
||||||
end: const FractionalOffset(0.7, 1.0),
|
|
||||||
colors: const <Color>[
|
|
||||||
const Color(0x00FFFFFF),
|
|
||||||
const Color(0x11777777),
|
|
||||||
const Color(0x44444444),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
final LinearGradient actual = LinearGradient.lerp(null, testGradient, 0.25);
|
|
||||||
|
|
||||||
expect(actual, const LinearGradient(
|
|
||||||
begin: FractionalOffset.bottomRight,
|
|
||||||
end: const FractionalOffset(0.7, 1.0),
|
|
||||||
colors: const <Color>[
|
|
||||||
const Color(0x00FFFFFF),
|
|
||||||
const Color(0x04777777),
|
|
||||||
const Color(0x11444444),
|
|
||||||
],
|
|
||||||
));
|
|
||||||
});
|
|
||||||
|
|
||||||
test('LinearGradient lerp test', () {
|
|
||||||
final LinearGradient testGradient1 = const LinearGradient(
|
|
||||||
begin: FractionalOffset.topLeft,
|
|
||||||
end: FractionalOffset.bottomLeft,
|
|
||||||
colors: const <Color>[
|
|
||||||
const Color(0x33333333),
|
|
||||||
const Color(0x66666666),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
final LinearGradient testGradient2 = const LinearGradient(
|
|
||||||
begin: FractionalOffset.topRight,
|
|
||||||
end: FractionalOffset.topLeft,
|
|
||||||
colors: const <Color>[
|
|
||||||
const Color(0x44444444),
|
|
||||||
const Color(0x88888888),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
final LinearGradient actual =
|
|
||||||
LinearGradient.lerp(testGradient1, testGradient2, 0.5);
|
|
||||||
|
|
||||||
expect(actual, const LinearGradient(
|
|
||||||
begin: const FractionalOffset(0.5, 0.0),
|
|
||||||
end: const FractionalOffset(0.0, 0.5),
|
|
||||||
colors: const <Color>[
|
|
||||||
const Color(0x3B3B3B3B),
|
|
||||||
const Color(0x77777777),
|
|
||||||
],
|
|
||||||
));
|
|
||||||
});
|
|
||||||
|
|
||||||
test('LinearGradient toString', () {
|
|
||||||
expect(
|
|
||||||
const LinearGradient(
|
|
||||||
begin: FractionalOffset.topLeft,
|
|
||||||
end: FractionalOffset.bottomLeft,
|
|
||||||
colors: const <Color>[
|
|
||||||
const Color(0x33333333),
|
|
||||||
const Color(0x66666666),
|
|
||||||
],
|
|
||||||
).toString(),
|
|
||||||
equals(
|
|
||||||
'LinearGradient(FractionalOffset.topLeft, FractionalOffset.bottomLeft, [Color(0x33333333), Color(0x66666666)], null, TileMode.clamp)',
|
|
||||||
),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
155
packages/flutter/test/painting/gradient_test.dart
Normal file
155
packages/flutter/test/painting/gradient_test.dart
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:flutter/painting.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
test('LinearGradient scale test', () {
|
||||||
|
final LinearGradient testGradient = const LinearGradient(
|
||||||
|
begin: FractionalOffset.bottomRight,
|
||||||
|
end: const FractionalOffset(0.7, 1.0),
|
||||||
|
colors: const <Color>[
|
||||||
|
const Color(0x00FFFFFF),
|
||||||
|
const Color(0x11777777),
|
||||||
|
const Color(0x44444444),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
final LinearGradient actual = LinearGradient.lerp(null, testGradient, 0.25);
|
||||||
|
|
||||||
|
expect(actual, const LinearGradient(
|
||||||
|
begin: FractionalOffset.bottomRight,
|
||||||
|
end: const FractionalOffset(0.7, 1.0),
|
||||||
|
colors: const <Color>[
|
||||||
|
const Color(0x00FFFFFF),
|
||||||
|
const Color(0x04777777),
|
||||||
|
const Color(0x11444444),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('LinearGradient lerp test', () {
|
||||||
|
final LinearGradient testGradient1 = const LinearGradient(
|
||||||
|
begin: FractionalOffset.topLeft,
|
||||||
|
end: FractionalOffset.bottomLeft,
|
||||||
|
colors: const <Color>[
|
||||||
|
const Color(0x33333333),
|
||||||
|
const Color(0x66666666),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
final LinearGradient testGradient2 = const LinearGradient(
|
||||||
|
begin: FractionalOffset.topRight,
|
||||||
|
end: FractionalOffset.topLeft,
|
||||||
|
colors: const <Color>[
|
||||||
|
const Color(0x44444444),
|
||||||
|
const Color(0x88888888),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
final LinearGradient actual = LinearGradient.lerp(testGradient1, testGradient2, 0.5);
|
||||||
|
|
||||||
|
expect(actual, const LinearGradient(
|
||||||
|
begin: const FractionalOffset(0.5, 0.0),
|
||||||
|
end: const FractionalOffset(0.0, 0.5),
|
||||||
|
colors: const <Color>[
|
||||||
|
const Color(0x3B3B3B3B),
|
||||||
|
const Color(0x77777777),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('LinearGradient toString', () {
|
||||||
|
expect(
|
||||||
|
const LinearGradient(
|
||||||
|
begin: FractionalOffset.topLeft,
|
||||||
|
end: FractionalOffset.bottomLeft,
|
||||||
|
colors: const <Color>[
|
||||||
|
const Color(0x33333333),
|
||||||
|
const Color(0x66666666),
|
||||||
|
],
|
||||||
|
).toString(),
|
||||||
|
equals(
|
||||||
|
'LinearGradient(FractionalOffset.topLeft, FractionalOffset.bottomLeft, [Color(0x33333333), Color(0x66666666)], null, TileMode.clamp)',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('LinearGradient with FractionalOffsetDirectional', () {
|
||||||
|
expect(
|
||||||
|
() {
|
||||||
|
return const LinearGradient(
|
||||||
|
begin: FractionalOffsetDirectional.topStart,
|
||||||
|
colors: const <Color>[ const Color(0xFFFFFFFF), const Color(0xFFFFFFFF) ]
|
||||||
|
).createShader(new Rect.fromLTWH(0.0, 0.0, 100.0, 100.0));
|
||||||
|
},
|
||||||
|
throwsAssertionError,
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
() {
|
||||||
|
return const LinearGradient(
|
||||||
|
begin: FractionalOffsetDirectional.topStart,
|
||||||
|
colors: const <Color>[ const Color(0xFFFFFFFF), const Color(0xFFFFFFFF) ]
|
||||||
|
).createShader(new Rect.fromLTWH(0.0, 0.0, 100.0, 100.0), textDirection: TextDirection.rtl);
|
||||||
|
},
|
||||||
|
returnsNormally,
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
() {
|
||||||
|
return const LinearGradient(
|
||||||
|
begin: FractionalOffsetDirectional.topStart,
|
||||||
|
colors: const <Color>[ const Color(0xFFFFFFFF), const Color(0xFFFFFFFF) ]
|
||||||
|
).createShader(new Rect.fromLTWH(0.0, 0.0, 100.0, 100.0), textDirection: TextDirection.ltr);
|
||||||
|
},
|
||||||
|
returnsNormally,
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
() {
|
||||||
|
return const LinearGradient(
|
||||||
|
begin: FractionalOffset.topLeft,
|
||||||
|
colors: const <Color>[ const Color(0xFFFFFFFF), const Color(0xFFFFFFFF) ]
|
||||||
|
).createShader(new Rect.fromLTWH(0.0, 0.0, 100.0, 100.0));
|
||||||
|
},
|
||||||
|
returnsNormally,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('RadialGradient with FractionalOffsetDirectional', () {
|
||||||
|
expect(
|
||||||
|
() {
|
||||||
|
return const RadialGradient(
|
||||||
|
center: FractionalOffsetDirectional.topStart,
|
||||||
|
colors: const <Color>[ const Color(0xFFFFFFFF), const Color(0xFFFFFFFF) ]
|
||||||
|
).createShader(new Rect.fromLTWH(0.0, 0.0, 100.0, 100.0));
|
||||||
|
},
|
||||||
|
throwsAssertionError,
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
() {
|
||||||
|
return const RadialGradient(
|
||||||
|
center: FractionalOffsetDirectional.topStart,
|
||||||
|
colors: const <Color>[ const Color(0xFFFFFFFF), const Color(0xFFFFFFFF) ]
|
||||||
|
).createShader(new Rect.fromLTWH(0.0, 0.0, 100.0, 100.0), textDirection: TextDirection.rtl);
|
||||||
|
},
|
||||||
|
returnsNormally,
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
() {
|
||||||
|
return const RadialGradient(
|
||||||
|
center: FractionalOffsetDirectional.topStart,
|
||||||
|
colors: const <Color>[ const Color(0xFFFFFFFF), const Color(0xFFFFFFFF) ]
|
||||||
|
).createShader(new Rect.fromLTWH(0.0, 0.0, 100.0, 100.0), textDirection: TextDirection.ltr);
|
||||||
|
},
|
||||||
|
returnsNormally,
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
() {
|
||||||
|
return const RadialGradient(
|
||||||
|
center: FractionalOffset.topLeft,
|
||||||
|
colors: const <Color>[ const Color(0xFFFFFFFF), const Color(0xFFFFFFFF) ]
|
||||||
|
).createShader(new Rect.fromLTWH(0.0, 0.0, 100.0, 100.0));
|
||||||
|
},
|
||||||
|
returnsNormally,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user