mirror of
https://github.com/flutter/flutter
synced 2024-10-13 19:52:53 +00:00
LinearGradient and RadialGradient RTL (#12204)
This commit is contained in:
parent
4f6e350b6e
commit
daedbc84a2
|
@ -25,7 +25,11 @@ abstract class Gradient {
|
|||
const Gradient();
|
||||
|
||||
/// 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.
|
||||
|
@ -91,21 +95,37 @@ class LinearGradient extends Gradient {
|
|||
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
|
||||
/// of the paint box at (0.0,0.0) and the bottom right at (1.0,1.0).
|
||||
/// The offset at which stop 0.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 (0.0,0.5) is half way down the
|
||||
/// 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.
|
||||
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.
|
||||
///
|
||||
|
@ -144,16 +164,20 @@ class LinearGradient extends Gradient {
|
|||
final TileMode tileMode;
|
||||
|
||||
@override
|
||||
Shader createShader(Rect rect) {
|
||||
Shader createShader(Rect rect, { TextDirection textDirection }) {
|
||||
return new ui.Gradient.linear(
|
||||
begin.withinRect(rect),
|
||||
end.withinRect(rect),
|
||||
begin.resolve(textDirection).withinRect(rect),
|
||||
end.resolve(textDirection).withinRect(rect),
|
||||
colors, stops, tileMode,
|
||||
);
|
||||
}
|
||||
|
||||
/// Returns a new [LinearGradient] with its properties scaled by the given
|
||||
/// factor.
|
||||
/// Returns a new [LinearGradient] with its properties (in particular the
|
||||
/// 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) {
|
||||
return new LinearGradient(
|
||||
begin: begin,
|
||||
|
@ -168,7 +192,7 @@ class LinearGradient extends Gradient {
|
|||
///
|
||||
/// 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.
|
||||
/// [tileMode] and with the same [colors] but transparent (using [scale]).
|
||||
///
|
||||
/// If neither gradient is null, they must have the same number of [colors].
|
||||
static LinearGradient lerp(LinearGradient a, LinearGradient b, double t) {
|
||||
|
@ -178,11 +202,7 @@ class LinearGradient extends Gradient {
|
|||
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.colors.length == b.colors.length, 'Cannot interpolate between two gradients with a different number of colors.');
|
||||
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 += 1)
|
||||
|
@ -195,8 +215,8 @@ class LinearGradient extends Gradient {
|
|||
interpolatedStops = a.stops ?? b.stops;
|
||||
}
|
||||
return new LinearGradient(
|
||||
begin: FractionalOffset.lerp(a.begin, b.begin, t),
|
||||
end: FractionalOffset.lerp(a.end, b.end, t),
|
||||
begin: FractionalOffsetGeometry.lerp(a.begin, b.begin, t),
|
||||
end: FractionalOffsetGeometry.lerp(a.end, b.end, t),
|
||||
colors: interpolatedColors,
|
||||
stops: interpolatedStops,
|
||||
tileMode: t < 0.5 ? a.tileMode : b.tileMode,
|
||||
|
@ -240,7 +260,7 @@ class LinearGradient extends Gradient {
|
|||
|
||||
@override
|
||||
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
|
||||
/// 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
|
||||
/// of the paint box.
|
||||
|
@ -368,11 +398,11 @@ class RadialGradient extends Gradient {
|
|||
final TileMode tileMode;
|
||||
|
||||
@override
|
||||
Shader createShader(Rect rect) {
|
||||
Shader createShader(Rect rect, { TextDirection textDirection }) {
|
||||
return new ui.Gradient.radial(
|
||||
center.withinRect(rect),
|
||||
center.resolve(textDirection).withinRect(rect),
|
||||
radius * rect.shortestSide,
|
||||
colors, stops, tileMode
|
||||
colors, stops, tileMode,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -413,6 +443,6 @@ class RadialGradient extends Gradient {
|
|||
|
||||
@override
|
||||
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', () {
|
||||
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…
Reference in a new issue