Expose Gradient.radial (#17826)
* Expose Gradient.radial * cleanup doc * update tests, null check * add asset images
This commit is contained in:
parent
61a4ab386a
commit
587a1b7708
@ -440,12 +440,23 @@ class LinearGradient extends Gradient {
|
||||
/// abstracts out the arguments to the [new ui.Gradient.radial] constructor from
|
||||
/// the `dart:ui` library.
|
||||
///
|
||||
/// A gradient has a [center] and a [radius]. The [center] point corresponds to
|
||||
/// 0.0, and the ring at [radius] from the center corresponds to 1.0. These
|
||||
/// lengths are expressed in fractions, so that the same gradient can be reused
|
||||
/// with varying sized boxes without changing the parameters. (This contrasts
|
||||
/// with [new ui.Gradient.radial], whose arguments are expressed in logical
|
||||
/// pixels.)
|
||||
/// A normal radial gradient has a [center] and a [radius]. The [center] point
|
||||
/// corresponds to 0.0, and the ring at [radius] from the center corresponds
|
||||
/// to 1.0. These lengths are expressed in fractions, so that the same gradient
|
||||
/// can be reused with varying sized boxes without changing the parameters.
|
||||
/// (This contrasts with [new ui.Gradient.radial], whose arguments are expressed
|
||||
/// in logical pixels.)
|
||||
///
|
||||
/// It is also possible to create a two-point (or focal pointed) radial gradient
|
||||
/// (which is sometimes referred to as a two point conic gradient, but is not the
|
||||
/// same as a CSS conic gradient which corresponds to a [SweepGradient]). A [focal]
|
||||
/// point and [focalRadius] can be specified similarly to [center] and [radius],
|
||||
/// which will make the rendered gradient appear to be pointed or directed in the
|
||||
/// direction of the [focal] point. This is only important if [focal] and [center]
|
||||
/// are not equal or [focalRadius] > 0.0 (as this case is visually identical to a
|
||||
/// normal radial gradient). One important case to avoid is having [focal] and
|
||||
/// [center] both resolve to [Offset.zero] when [focalRadius] > 0.0. In such a case,
|
||||
/// a valid shader cannot be created by the framework.
|
||||
///
|
||||
/// The [colors] are described by a list of [Color] objects. There must be at
|
||||
/// least two colors. The [stops] list, if specified, must have the same length
|
||||
@ -502,9 +513,12 @@ class RadialGradient extends Gradient {
|
||||
@required List<Color> colors,
|
||||
List<double> stops,
|
||||
this.tileMode: TileMode.clamp,
|
||||
this.focal,
|
||||
this.focalRadius: 0.0
|
||||
}) : assert(center != null),
|
||||
assert(radius != null),
|
||||
assert(tileMode != null),
|
||||
assert(focalRadius != null),
|
||||
super(colors: colors, stops: stops);
|
||||
|
||||
/// The center of the gradient, as an offset into the (-1.0, -1.0) x (1.0, 1.0)
|
||||
@ -539,14 +553,43 @@ class RadialGradient extends Gradient {
|
||||
/// 
|
||||
/// 
|
||||
/// 
|
||||
///
|
||||
/// 
|
||||
/// 
|
||||
/// 
|
||||
final TileMode tileMode;
|
||||
|
||||
/// The focal point of the gradient. If specified, the gradient will appear
|
||||
/// to be focused along the vector from [center] to focal.
|
||||
///
|
||||
/// See [center] for a description of how the coordinates are mapped.
|
||||
///
|
||||
/// If this value is specified and [focalRadius] > 0.0, care should be taken
|
||||
/// to ensure that either this value or [center] will not both resolve to
|
||||
/// [Offset.zero], which would fail to create a valid gradient.
|
||||
final AlignmentGeometry focal;
|
||||
|
||||
/// The radius of the focal point of gradient, as a fraction of the shortest
|
||||
/// side of the paint box.
|
||||
///
|
||||
/// For example, if a radial gradient is painted on a box that is
|
||||
/// 100.0 pixels wide and 200.0 pixels tall, then a radius of 1.0
|
||||
/// will place the 1.0 stop at 100.0 pixels from the [focus].
|
||||
///
|
||||
/// If this value is specified and is greater than 0.0, either [focal] or
|
||||
/// [center] must not resolve to [Offset.zero], which would fail to create
|
||||
/// a valid gradient.
|
||||
final double focalRadius;
|
||||
|
||||
@override
|
||||
Shader createShader(Rect rect, { TextDirection textDirection }) {
|
||||
return new ui.Gradient.radial(
|
||||
center.resolve(textDirection).withinRect(rect),
|
||||
radius * rect.shortestSide,
|
||||
colors, _impliedStops(), tileMode,
|
||||
null, // transform
|
||||
focal == null ? null : focal.resolve(textDirection).withinRect(rect),
|
||||
focalRadius * rect.shortestSide,
|
||||
);
|
||||
}
|
||||
|
||||
@ -562,6 +605,8 @@ class RadialGradient extends Gradient {
|
||||
colors: colors.map<Color>((Color color) => Color.lerp(null, color, factor)).toList(),
|
||||
stops: stops,
|
||||
tileMode: tileMode,
|
||||
focal: focal,
|
||||
focalRadius: focalRadius
|
||||
);
|
||||
}
|
||||
|
||||
@ -613,6 +658,8 @@ class RadialGradient extends Gradient {
|
||||
colors: interpolated.colors,
|
||||
stops: interpolated.stops,
|
||||
tileMode: t < 0.5 ? a.tileMode : b.tileMode, // TODO(ianh): interpolate tile mode
|
||||
focal: AlignmentGeometry.lerp(a.focal, b.focal, t),
|
||||
focalRadius: math.max(0.0, ui.lerpDouble(a.focalRadius, b.focalRadius, t)),
|
||||
);
|
||||
}
|
||||
|
||||
@ -627,7 +674,9 @@ class RadialGradient extends Gradient {
|
||||
radius != typedOther.radius ||
|
||||
tileMode != typedOther.tileMode ||
|
||||
colors?.length != typedOther.colors?.length ||
|
||||
stops?.length != typedOther.stops?.length)
|
||||
stops?.length != typedOther.stops?.length ||
|
||||
focal != typedOther.focal ||
|
||||
focalRadius != typedOther.focalRadius)
|
||||
return false;
|
||||
if (colors != null) {
|
||||
assert(typedOther.colors != null);
|
||||
@ -649,11 +698,11 @@ class RadialGradient extends Gradient {
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => hashValues(center, radius, tileMode, hashList(colors), hashList(stops));
|
||||
int get hashCode => hashValues(center, radius, tileMode, hashList(colors), hashList(stops), focal, focalRadius);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return '$runtimeType($center, $radius, $colors, $stops, $tileMode)';
|
||||
return '$runtimeType($center, $radius, $colors, $stops, $tileMode, $focal, $focalRadius)';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -165,48 +165,10 @@ void main() {
|
||||
},
|
||||
throwsAssertionError,
|
||||
);
|
||||
expect(
|
||||
() {
|
||||
return const RadialGradient(
|
||||
center: AlignmentDirectional.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: AlignmentDirectional.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: Alignment.topLeft,
|
||||
colors: const <Color>[ const Color(0xFFFFFFFF), const Color(0xFFFFFFFF) ]
|
||||
).createShader(new Rect.fromLTWH(0.0, 0.0, 100.0, 100.0));
|
||||
},
|
||||
returnsNormally,
|
||||
);
|
||||
});
|
||||
|
||||
test('SweepGradient with AlignmentDirectional', () {
|
||||
expect(
|
||||
() {
|
||||
return const SweepGradient(
|
||||
center: AlignmentDirectional.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 SweepGradient(
|
||||
return const RadialGradient(
|
||||
center: AlignmentDirectional.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);
|
||||
@ -215,7 +177,7 @@ void main() {
|
||||
);
|
||||
expect(
|
||||
() {
|
||||
return const SweepGradient(
|
||||
return const RadialGradient(
|
||||
center: AlignmentDirectional.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);
|
||||
@ -224,7 +186,7 @@ void main() {
|
||||
);
|
||||
expect(
|
||||
() {
|
||||
return const SweepGradient(
|
||||
return const RadialGradient(
|
||||
center: Alignment.topLeft,
|
||||
colors: const <Color>[ const Color(0xFFFFFFFF), const Color(0xFFFFFFFF) ]
|
||||
).createShader(new Rect.fromLTWH(0.0, 0.0, 100.0, 100.0));
|
||||
@ -289,6 +251,9 @@ void main() {
|
||||
);
|
||||
|
||||
final RadialGradient actual = RadialGradient.lerp(testGradient1, testGradient2, 0.5);
|
||||
|
||||
expect(actual.focal, isNull);
|
||||
|
||||
expect(actual, const RadialGradient(
|
||||
center: const Alignment(0.0, -1.0),
|
||||
radius: 15.0,
|
||||
@ -303,6 +268,61 @@ void main() {
|
||||
));
|
||||
});
|
||||
|
||||
test('RadialGradient lerp test with focal', () {
|
||||
const RadialGradient testGradient1 = const RadialGradient(
|
||||
center: Alignment.topLeft,
|
||||
focal: Alignment.centerLeft,
|
||||
radius: 20.0,
|
||||
focalRadius: 10.0,
|
||||
colors: const <Color>[
|
||||
const Color(0x33333333),
|
||||
const Color(0x66666666),
|
||||
],
|
||||
);
|
||||
const RadialGradient testGradient2 = const RadialGradient(
|
||||
center: Alignment.topRight,
|
||||
focal: Alignment.centerRight,
|
||||
radius: 10.0,
|
||||
focalRadius: 5.0,
|
||||
colors: const <Color>[
|
||||
const Color(0x44444444),
|
||||
const Color(0x88888888),
|
||||
],
|
||||
);
|
||||
const RadialGradient testGradient3 = const RadialGradient(
|
||||
center: Alignment.topRight,
|
||||
radius: 10.0,
|
||||
colors: const <Color>[
|
||||
const Color(0x44444444),
|
||||
const Color(0x88888888),
|
||||
],
|
||||
);
|
||||
|
||||
final RadialGradient actual = RadialGradient.lerp(testGradient1, testGradient2, 0.5);
|
||||
expect(actual, const RadialGradient(
|
||||
center: const Alignment(0.0, -1.0),
|
||||
focal: const Alignment(0.0, 0.0),
|
||||
radius: 15.0,
|
||||
focalRadius: 7.5,
|
||||
colors: const <Color>[
|
||||
const Color(0x3B3B3B3B),
|
||||
const Color(0x77777777),
|
||||
],
|
||||
));
|
||||
|
||||
final RadialGradient actual2 = RadialGradient.lerp(testGradient1, testGradient3, 0.5);
|
||||
expect(actual2, const RadialGradient(
|
||||
center: const Alignment(0.0, -1.0),
|
||||
focal: const Alignment(-0.5, 0.0),
|
||||
radius: 15.0,
|
||||
focalRadius: 5.0,
|
||||
colors: const <Color>[
|
||||
const Color(0x3B3B3B3B),
|
||||
const Color(0x77777777),
|
||||
],
|
||||
));
|
||||
});
|
||||
|
||||
test('SweepGradient lerp test', () {
|
||||
const SweepGradient testGradient1 = const SweepGradient(
|
||||
center: Alignment.topLeft,
|
||||
|
Loading…
x
Reference in New Issue
Block a user