Commit 3a0ce961 authored by xster's avatar xster Committed by GitHub

lerp LinearGradient (#9628)

* Implement

* Don’t scale the fractional offsets since it’s easier to use

* review notes

* fix nit
parent 66ed8de7
......@@ -637,7 +637,10 @@ class LinearGradient extends Gradient {
this.colors,
this.stops,
this.tileMode: TileMode.clamp
});
}) : assert(begin != null),
assert(end != null),
assert(colors != null),
assert(tileMode != null);
/// The offset from coordinate (0.0,0.0) at which stop 0.0 of the
/// gradient is placed, in a coordinate space that maps the top left
......@@ -679,6 +682,54 @@ class LinearGradient extends Gradient {
);
}
/// Returns a new [LinearGradient] with its properties scaled by the given factor.
LinearGradient scale(double factor) {
return new LinearGradient(
begin: begin,
end: end,
colors: colors.map<Color>((Color color) => Color.lerp(null, color, factor)).toList(),
stops: stops,
tileMode: tileMode,
);
}
/// Linearly interpolate between two [LinearGradient]s.
///
/// If either gradient is null, this function linearly interpolates from a
/// a gradient that matches the other gradient in begin, end, stops and
/// tileMode and with the same colors but transparent.
static LinearGradient lerp(LinearGradient a, LinearGradient b, double t) {
if (a == null && b == null)
return null;
if (a == null)
return b.scale(t);
if (b == null)
return a.scale(1.0 - t);
// Interpolation is only possible when the lengths of colors and stops are
// 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);
final List<Color> interpolatedColors = <Color>[];
for (int i = 0; i < a.colors.length; i++)
interpolatedColors.add(Color.lerp(a.colors[i], b.colors[i], t));
List<double> interpolatedStops;
if (a.stops != null && b.stops != null) {
for (int i = 0; i < a.stops.length; i++)
interpolatedStops.add(ui.lerpDouble(a.stops[i], b.stops[i], t));
} else {
interpolatedStops = a.stops ?? b.stops;
}
return new LinearGradient(
begin: FractionalOffset.lerp(a.begin, b.begin, t),
end: FractionalOffset.lerp(a.end, b.end, t),
colors: interpolatedColors,
stops: interpolatedStops,
tileMode: t < 0.5 ? a.tileMode : b.tileMode,
);
}
@override
bool operator ==(dynamic other) {
if (identical(this, other))
......
......@@ -6,7 +6,7 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/painting.dart';
void main() {
test("BorderSide control test", () {
test('BorderSide control test', () {
final BorderSide side1 = const BorderSide();
final BorderSide side2 = side1.copyWith(
color: const Color(0xFF00FFFF),
......@@ -39,7 +39,7 @@ void main() {
expect(interpolated.color, equals(side2.color.withOpacity(0.2)));
});
test("Border control test", () {
test('Border control test', () {
final Border border1 = new Border.all(width: 4.0);
final Border border2 = Border.lerp(null, border1, 0.25);
final Border border3 = Border.lerp(border1, null, 0.25);
......@@ -54,7 +54,7 @@ void main() {
expect(border4.left.width, equals(2.0));
});
test("BoxShadow control test", () {
test('BoxShadow control test', () {
final BoxShadow shadow1 = const BoxShadow(blurRadius: 4.0);
final BoxShadow shadow2 = BoxShadow.lerp(null, shadow1, 0.25);
final BoxShadow shadow3 = BoxShadow.lerp(shadow1, null, 0.25);
......@@ -76,4 +76,58 @@ void main() {
<BoxShadow>[shadow2], <BoxShadow>[shadow3, shadow1], 0.5);
expect(shadowList, equals(<BoxShadow>[shadow4, shadow1.scale(0.5)]));
});
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),
],
));
});
}
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