mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
RoundedRectangleBorder (#12591)
This commit is contained in:
parent
d8380201bd
commit
d920fdd11a
@ -35,6 +35,7 @@ export 'src/painting/geometry.dart';
|
||||
export 'src/painting/gradient.dart';
|
||||
export 'src/painting/images.dart';
|
||||
export 'src/painting/matrix_utils.dart';
|
||||
export 'src/painting/rounded_rectangle_border.dart';
|
||||
export 'src/painting/text_painter.dart';
|
||||
export 'src/painting/text_span.dart';
|
||||
export 'src/painting/text_style.dart';
|
||||
|
@ -10,16 +10,29 @@ import 'borders.dart';
|
||||
import 'edge_insets.dart';
|
||||
|
||||
/// The shape to use when rendering a [Border] or [BoxDecoration].
|
||||
///
|
||||
/// Consider using [ShapeBorder] subclasses directly (with [ShapeDecoration]),
|
||||
/// instead of using [BoxShape] and [Border], if the shapes will need to be
|
||||
/// interpolated or animated. The [Border] class cannot interpolate between
|
||||
/// different shapes.
|
||||
enum BoxShape {
|
||||
/// An axis-aligned, 2D rectangle. May have rounded corners (described by a
|
||||
/// [BorderRadius]). The edges of the rectangle will match the edges of the box
|
||||
/// into which the [Border] or [BoxDecoration] is painted.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [RoundedRectangleBorder], the equivalent [ShapeBorder].
|
||||
rectangle,
|
||||
|
||||
/// A circle centered in the middle of the box into which the [Border] or
|
||||
/// [BoxDecoration] is painted. The diameter of the circle is the shortest
|
||||
/// dimension of the box, either the width or the height, such that the circle
|
||||
/// touches the edges of the box.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [CircleBorder], the equivalent [ShapeBorder].
|
||||
circle,
|
||||
}
|
||||
|
||||
|
@ -140,7 +140,14 @@ class BoxDecoration extends Decoration {
|
||||
/// The shape to fill the background [color], [gradient], and [image] into and
|
||||
/// to cast as the [boxShadow].
|
||||
///
|
||||
/// If this is [BoxShape.rectangle] then [borderRadius] is ignored.
|
||||
/// If this is [BoxShape.circle] then [borderRadius] is ignored.
|
||||
///
|
||||
/// The [shape] cannot be interpolated; animating between two [BoxDecoration]s
|
||||
/// with different [shape]s will result in a discontinuity in the rendering.
|
||||
/// To interpolate between two shapes, consider using [ShapeDecoration] and
|
||||
/// different [ShapeBorder]s; in particular, [CircleBorder] instead of
|
||||
/// [BoxShape.circle] and [RoundedRectangleBorder] instead of
|
||||
/// [BoxShape.rectangle].
|
||||
final BoxShape shape;
|
||||
|
||||
@override
|
||||
|
298
packages/flutter/lib/src/painting/rounded_rectangle_border.dart
Normal file
298
packages/flutter/lib/src/painting/rounded_rectangle_border.dart
Normal file
@ -0,0 +1,298 @@
|
||||
// Copyright 2017 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 'dart:ui' as ui show lerpDouble;
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import 'basic_types.dart';
|
||||
import 'border_radius.dart';
|
||||
import 'borders.dart';
|
||||
import 'circle_border.dart';
|
||||
import 'edge_insets.dart';
|
||||
|
||||
/// A rectangular border with rounded corners.
|
||||
///
|
||||
/// Typically used with [ShapeDecoration] to draw a box with a rounded
|
||||
/// rectangle.
|
||||
///
|
||||
/// This shape can interpolate to and from [CircleBorder].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [BorderSide], which is used to describe each side of the box.
|
||||
/// * [Border], which, when used with [BoxDecoration], can also
|
||||
/// describe a rounded rectangle.
|
||||
class RoundedRectangleBorder extends ShapeBorder {
|
||||
/// Creates a rounded rectangle border.
|
||||
///
|
||||
/// The arguments must not be null.
|
||||
RoundedRectangleBorder({
|
||||
this.side: BorderSide.none,
|
||||
this.borderRadius: BorderRadius.zero,
|
||||
}) : assert(side != null),
|
||||
assert(borderRadius != null);
|
||||
|
||||
/// The style of this border.
|
||||
final BorderSide side;
|
||||
|
||||
/// The radii for each corner.
|
||||
final BorderRadius borderRadius;
|
||||
|
||||
@override
|
||||
EdgeInsetsGeometry get dimensions {
|
||||
return new EdgeInsets.all(side.width);
|
||||
}
|
||||
|
||||
@override
|
||||
ShapeBorder scale(double t) {
|
||||
return new RoundedRectangleBorder(
|
||||
side: side.scale(t),
|
||||
borderRadius: borderRadius * t,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
ShapeBorder lerpFrom(ShapeBorder a, double t) {
|
||||
if (a is RoundedRectangleBorder) {
|
||||
return new RoundedRectangleBorder(
|
||||
side: BorderSide.lerp(a.side, side, t),
|
||||
borderRadius: BorderRadius.lerp(a.borderRadius, borderRadius, t),
|
||||
);
|
||||
}
|
||||
if (a is CircleBorder) {
|
||||
return new _RoundedRectangleToCircleBorder(
|
||||
side: BorderSide.lerp(a.side, side, t),
|
||||
borderRadius: borderRadius,
|
||||
circleness: 1.0 - t,
|
||||
);
|
||||
}
|
||||
return super.lerpFrom(a, t);
|
||||
}
|
||||
|
||||
@override
|
||||
ShapeBorder lerpTo(ShapeBorder b, double t) {
|
||||
if (b is RoundedRectangleBorder) {
|
||||
return new RoundedRectangleBorder(
|
||||
side: BorderSide.lerp(side, b.side, t),
|
||||
borderRadius: BorderRadius.lerp(borderRadius, b.borderRadius, t),
|
||||
);
|
||||
}
|
||||
if (b is CircleBorder) {
|
||||
return new _RoundedRectangleToCircleBorder(
|
||||
side: BorderSide.lerp(side, b.side, t),
|
||||
borderRadius: borderRadius,
|
||||
circleness: t,
|
||||
);
|
||||
}
|
||||
return super.lerpTo(b, t);
|
||||
}
|
||||
|
||||
@override
|
||||
Path getInnerPath(Rect rect, { TextDirection textDirection }) {
|
||||
return new Path()
|
||||
..addRRect(borderRadius.toRRect(rect).deflate(side.width));
|
||||
}
|
||||
|
||||
@override
|
||||
Path getOuterPath(Rect rect, { TextDirection textDirection }) {
|
||||
return new Path()
|
||||
..addRRect(borderRadius.toRRect(rect));
|
||||
}
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Rect rect, { TextDirection textDirection }) {
|
||||
switch (side.style) {
|
||||
case BorderStyle.none:
|
||||
break;
|
||||
case BorderStyle.solid:
|
||||
final double width = side.width;
|
||||
if (width == 0.0) {
|
||||
canvas.drawRRect(borderRadius.toRRect(rect), side.toPaint());
|
||||
} else {
|
||||
final RRect outer = borderRadius.toRRect(rect);
|
||||
final RRect inner = outer.deflate(width);
|
||||
final Paint paint = new Paint()
|
||||
..color = side.color;
|
||||
canvas.drawDRRect(outer, inner, paint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(dynamic other) {
|
||||
if (runtimeType != other.runtimeType)
|
||||
return false;
|
||||
final RoundedRectangleBorder typedOther = other;
|
||||
return side == typedOther.side
|
||||
&& borderRadius == typedOther.borderRadius;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => hashValues(side, borderRadius);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return '$runtimeType($side, $borderRadius)';
|
||||
}
|
||||
}
|
||||
|
||||
class _RoundedRectangleToCircleBorder extends ShapeBorder {
|
||||
_RoundedRectangleToCircleBorder({
|
||||
this.side: BorderSide.none,
|
||||
this.borderRadius: BorderRadius.zero,
|
||||
@required this.circleness,
|
||||
}) : assert(side != null),
|
||||
assert(borderRadius != null),
|
||||
assert(circleness != null);
|
||||
|
||||
final BorderSide side;
|
||||
|
||||
final BorderRadius borderRadius;
|
||||
|
||||
final double circleness;
|
||||
|
||||
@override
|
||||
EdgeInsetsGeometry get dimensions {
|
||||
return new EdgeInsets.all(side.width);
|
||||
}
|
||||
|
||||
@override
|
||||
ShapeBorder scale(double t) {
|
||||
return new _RoundedRectangleToCircleBorder(
|
||||
side: side.scale(t),
|
||||
borderRadius: borderRadius * t,
|
||||
circleness: t,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
ShapeBorder lerpFrom(ShapeBorder a, double t) {
|
||||
if (a is RoundedRectangleBorder) {
|
||||
return new _RoundedRectangleToCircleBorder(
|
||||
side: BorderSide.lerp(a.side, side, t),
|
||||
borderRadius: BorderRadius.lerp(a.borderRadius, borderRadius, t),
|
||||
circleness: circleness * t,
|
||||
);
|
||||
}
|
||||
if (a is CircleBorder) {
|
||||
return new _RoundedRectangleToCircleBorder(
|
||||
side: BorderSide.lerp(a.side, side, t),
|
||||
borderRadius: borderRadius,
|
||||
circleness: circleness + (1.0 - circleness) * (1.0 - t),
|
||||
);
|
||||
}
|
||||
if (a is _RoundedRectangleToCircleBorder) {
|
||||
return new _RoundedRectangleToCircleBorder(
|
||||
side: BorderSide.lerp(a.side, side, t),
|
||||
borderRadius: BorderRadius.lerp(a.borderRadius, borderRadius, t),
|
||||
circleness: ui.lerpDouble(a.circleness, circleness, t),
|
||||
);
|
||||
}
|
||||
return super.lerpFrom(a, t);
|
||||
}
|
||||
|
||||
@override
|
||||
ShapeBorder lerpTo(ShapeBorder b, double t) {
|
||||
if (b is RoundedRectangleBorder) {
|
||||
return new _RoundedRectangleToCircleBorder(
|
||||
side: BorderSide.lerp(side, b.side, t),
|
||||
borderRadius: BorderRadius.lerp(borderRadius, b.borderRadius, t),
|
||||
circleness: circleness * (1.0 - t),
|
||||
);
|
||||
}
|
||||
if (b is CircleBorder) {
|
||||
return new _RoundedRectangleToCircleBorder(
|
||||
side: BorderSide.lerp(side, b.side, t),
|
||||
borderRadius: borderRadius,
|
||||
circleness: circleness + (1.0 - circleness) * t,
|
||||
);
|
||||
}
|
||||
if (b is _RoundedRectangleToCircleBorder) {
|
||||
return new _RoundedRectangleToCircleBorder(
|
||||
side: BorderSide.lerp(side, b.side, t),
|
||||
borderRadius: BorderRadius.lerp(borderRadius, b.borderRadius, t),
|
||||
circleness: ui.lerpDouble(circleness, b.circleness, t),
|
||||
);
|
||||
}
|
||||
return super.lerpTo(b, t);
|
||||
}
|
||||
|
||||
Rect _adjustRect(Rect rect) {
|
||||
if (circleness == 0.0 || rect.width == rect.height)
|
||||
return rect;
|
||||
if (rect.width < rect.height) {
|
||||
final double delta = circleness * (rect.height - rect.width) / 2.0;
|
||||
return new Rect.fromLTRB(
|
||||
rect.left,
|
||||
rect.top + delta,
|
||||
rect.right,
|
||||
rect.bottom - delta,
|
||||
);
|
||||
} else {
|
||||
final double delta = circleness * (rect.width - rect.height) / 2.0;
|
||||
return new Rect.fromLTRB(
|
||||
rect.left + delta,
|
||||
rect.top,
|
||||
rect.right - delta,
|
||||
rect.bottom,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
BorderRadius _adjustBorderRadius(Rect rect) {
|
||||
if (circleness == 0.0)
|
||||
return borderRadius;
|
||||
return BorderRadius.lerp(borderRadius, new BorderRadius.circular(rect.shortestSide / 2.0), circleness);
|
||||
}
|
||||
|
||||
@override
|
||||
Path getInnerPath(Rect rect, { TextDirection textDirection }) {
|
||||
return new Path()
|
||||
..addRRect(_adjustBorderRadius(rect).toRRect(_adjustRect(rect)).deflate(side.width));
|
||||
}
|
||||
|
||||
@override
|
||||
Path getOuterPath(Rect rect, { TextDirection textDirection }) {
|
||||
return new Path()
|
||||
..addRRect(_adjustBorderRadius(rect).toRRect(_adjustRect(rect)));
|
||||
}
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Rect rect, { TextDirection textDirection }) {
|
||||
switch (side.style) {
|
||||
case BorderStyle.none:
|
||||
break;
|
||||
case BorderStyle.solid:
|
||||
final double width = side.width;
|
||||
if (width == 0.0) {
|
||||
canvas.drawRRect(_adjustBorderRadius(rect).toRRect(_adjustRect(rect)), side.toPaint());
|
||||
} else {
|
||||
final RRect outer = _adjustBorderRadius(rect).toRRect(_adjustRect(rect));
|
||||
final RRect inner = outer.deflate(width);
|
||||
final Paint paint = new Paint()
|
||||
..color = side.color;
|
||||
canvas.drawDRRect(outer, inner, paint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(dynamic other) {
|
||||
if (runtimeType != other.runtimeType)
|
||||
return false;
|
||||
final _RoundedRectangleToCircleBorder typedOther = other;
|
||||
return side == typedOther.side
|
||||
&& borderRadius == typedOther.borderRadius
|
||||
&& circleness == typedOther.circleness;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => hashValues(side, borderRadius, circleness);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'RoundedRectangleBorder($side, $borderRadius, ${(circleness * 100).toStringAsFixed(1)}% of the way to being a CircleBorder)';
|
||||
}
|
||||
}
|
@ -7,6 +7,54 @@ import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import '../rendering/mock_canvas.dart';
|
||||
|
||||
final Matcher isUnitCircle = isPathThat(
|
||||
includes: <Offset>[
|
||||
const Offset(-0.6035617555492896, 0.2230970398703236),
|
||||
const Offset(-0.7738478165627277, 0.5640447581420576),
|
||||
const Offset(-0.46090034164788385, -0.692017006684612),
|
||||
const Offset(-0.2138540316101296, -0.09997005339529785),
|
||||
const Offset(-0.46919827227410416, 0.29581721423767027),
|
||||
const Offset(-0.43628713652733153, 0.5065324817995975),
|
||||
const Offset(0.0, 0.0),
|
||||
const Offset(0.49296904381712725, -0.5922438805080081),
|
||||
const Offset(0.2901141594861445, -0.3181478162967859),
|
||||
const Offset(0.45229946324502146, 0.4324593232323706),
|
||||
const Offset(0.11827752132593572, 0.806442226027837),
|
||||
const Offset(0.8854165569581154, -0.08604230149167624),
|
||||
],
|
||||
excludes: <Offset>[
|
||||
const Offset(-100.0, -100.0),
|
||||
const Offset(-100.0, 100.0),
|
||||
const Offset(-1.1104403014186688, -1.1234939207590569),
|
||||
const Offset(-1.1852827482514838, -0.5029551986333607),
|
||||
const Offset(-1.0253256532179804, -0.02034402043932526),
|
||||
const Offset(-1.4488532714237397, 0.4948740308904742),
|
||||
const Offset(-1.03142206223176, 0.81070400258819),
|
||||
const Offset(-1.006747917852356, 1.3712062218039343),
|
||||
const Offset(-0.5241429900291878, -1.2852518410112541),
|
||||
const Offset(-0.8879593765104428, -0.9999680025850874),
|
||||
const Offset(-0.9120835110799488, -0.4361605900585557),
|
||||
const Offset(-0.8184877240407303, 1.1202520775469589),
|
||||
const Offset(-0.15746058420492282, -1.1905035795387513),
|
||||
const Offset(-0.11519948876183506, 1.3848147258237393),
|
||||
const Offset(0.0035741796943844495, -1.3383908620447724),
|
||||
const Offset(0.34408827443814394, 1.4514436242950461),
|
||||
const Offset(0.709487222145941, -1.3468012918181573),
|
||||
const Offset(0.6287522653614315, -0.8315879623940617),
|
||||
const Offset(0.9716071801865485, 0.24311969613525442),
|
||||
const Offset(0.7632982576031955, 0.8329765574976169),
|
||||
const Offset(0.9923766847309081, 1.0592617071813715),
|
||||
const Offset(1.2696730082820435, -1.0353385446957046),
|
||||
const Offset(1.4266154921521208, -0.8382633931857755),
|
||||
const Offset(1.298035226938996, -0.11544603567954526),
|
||||
const Offset(1.4143230992455558, 0.10842501221141165),
|
||||
const Offset(1.465352952354424, 0.6999947490821032),
|
||||
const Offset(1.0462985816010146, 1.3874230508561505),
|
||||
const Offset(100.0, -100.0),
|
||||
const Offset(100.0, 100.0),
|
||||
],
|
||||
);
|
||||
|
||||
void main() {
|
||||
test('CircleBorder', () {
|
||||
final CircleBorder c10 = const CircleBorder(const BorderSide(width: 10.0));
|
||||
@ -18,53 +66,6 @@ void main() {
|
||||
expect(ShapeBorder.lerp(c10, c20, 0.0), c10);
|
||||
expect(ShapeBorder.lerp(c10, c20, 0.5), c15);
|
||||
expect(ShapeBorder.lerp(c10, c20, 1.0), c20);
|
||||
final Matcher isUnitCircle = isPathThat(
|
||||
includes: <Offset>[
|
||||
const Offset(-0.6035617555492896, 0.2230970398703236),
|
||||
const Offset(-0.7738478165627277, 0.5640447581420576),
|
||||
const Offset(-0.46090034164788385, -0.692017006684612),
|
||||
const Offset(-0.2138540316101296, -0.09997005339529785),
|
||||
const Offset(-0.46919827227410416, 0.29581721423767027),
|
||||
const Offset(-0.43628713652733153, 0.5065324817995975),
|
||||
const Offset(0.0, 0.0),
|
||||
const Offset(0.49296904381712725, -0.5922438805080081),
|
||||
const Offset(0.2901141594861445, -0.3181478162967859),
|
||||
const Offset(0.45229946324502146, 0.4324593232323706),
|
||||
const Offset(0.11827752132593572, 0.806442226027837),
|
||||
const Offset(0.8854165569581154, -0.08604230149167624),
|
||||
],
|
||||
excludes: <Offset>[
|
||||
const Offset(-100.0, -100.0),
|
||||
const Offset(-100.0, 100.0),
|
||||
const Offset(-1.1104403014186688, -1.1234939207590569),
|
||||
const Offset(-1.1852827482514838, -0.5029551986333607),
|
||||
const Offset(-1.0253256532179804, -0.02034402043932526),
|
||||
const Offset(-1.4488532714237397, 0.4948740308904742),
|
||||
const Offset(-1.03142206223176, 0.81070400258819),
|
||||
const Offset(-1.006747917852356, 1.3712062218039343),
|
||||
const Offset(-0.5241429900291878, -1.2852518410112541),
|
||||
const Offset(-0.8879593765104428, -0.9999680025850874),
|
||||
const Offset(-0.9120835110799488, -0.4361605900585557),
|
||||
const Offset(-0.8184877240407303, 1.1202520775469589),
|
||||
const Offset(-0.15746058420492282, -1.1905035795387513),
|
||||
const Offset(-0.11519948876183506, 1.3848147258237393),
|
||||
const Offset(0.0035741796943844495, -1.3383908620447724),
|
||||
const Offset(0.34408827443814394, 1.4514436242950461),
|
||||
const Offset(0.709487222145941, -1.3468012918181573),
|
||||
const Offset(0.6287522653614315, -0.8315879623940617),
|
||||
const Offset(0.9716071801865485, 0.24311969613525442),
|
||||
const Offset(0.7632982576031955, 0.8329765574976169),
|
||||
const Offset(0.9923766847309081, 1.0592617071813715),
|
||||
const Offset(1.2696730082820435, -1.0353385446957046),
|
||||
const Offset(1.4266154921521208, -0.8382633931857755),
|
||||
const Offset(1.298035226938996, -0.11544603567954526),
|
||||
const Offset(1.4143230992455558, 0.10842501221141165),
|
||||
const Offset(1.465352952354424, 0.6999947490821032),
|
||||
const Offset(1.0462985816010146, 1.3874230508561505),
|
||||
const Offset(100.0, -100.0),
|
||||
const Offset(100.0, 100.0),
|
||||
],
|
||||
);
|
||||
expect(c10.getInnerPath(new Rect.fromCircle(center: Offset.zero, radius: 1.0).inflate(10.0)), isUnitCircle);
|
||||
expect(c10.getOuterPath(new Rect.fromCircle(center: Offset.zero, radius: 1.0)), isUnitCircle);
|
||||
expect(
|
||||
|
@ -0,0 +1,89 @@
|
||||
// Copyright 2017 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/painting.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import '../rendering/mock_canvas.dart';
|
||||
import 'circle_border_test.dart';
|
||||
|
||||
void main() {
|
||||
test('RoundedRectangleBorder', () {
|
||||
final RoundedRectangleBorder c10 = new RoundedRectangleBorder(side: const BorderSide(width: 10.0), borderRadius: new BorderRadius.circular(100.0));
|
||||
final RoundedRectangleBorder c15 = new RoundedRectangleBorder(side: const BorderSide(width: 15.0), borderRadius: new BorderRadius.circular(150.0));
|
||||
final RoundedRectangleBorder c20 = new RoundedRectangleBorder(side: const BorderSide(width: 20.0), borderRadius: new BorderRadius.circular(200.0));
|
||||
expect(c10.dimensions, const EdgeInsets.all(10.0));
|
||||
expect(c10.scale(2.0), c20);
|
||||
expect(c20.scale(0.5), c10);
|
||||
expect(ShapeBorder.lerp(c10, c20, 0.0), c10);
|
||||
expect(ShapeBorder.lerp(c10, c20, 0.5), c15);
|
||||
expect(ShapeBorder.lerp(c10, c20, 1.0), c20);
|
||||
|
||||
final RoundedRectangleBorder c1 = new RoundedRectangleBorder(side: const BorderSide(width: 1.0), borderRadius: new BorderRadius.circular(1.0));
|
||||
final RoundedRectangleBorder c2 = new RoundedRectangleBorder(side: const BorderSide(width: 1.0), borderRadius: new BorderRadius.circular(2.0));
|
||||
expect(c2.getInnerPath(new Rect.fromCircle(center: Offset.zero, radius: 2.0)), isUnitCircle);
|
||||
expect(c1.getOuterPath(new Rect.fromCircle(center: Offset.zero, radius: 1.0)), isUnitCircle);
|
||||
final Rect rect = new Rect.fromLTRB(10.0, 20.0, 80.0, 190.0);
|
||||
expect(
|
||||
(Canvas canvas) => c10.paint(canvas, rect),
|
||||
paints
|
||||
..drrect(
|
||||
outer: new RRect.fromRectAndRadius(rect, const Radius.circular(100.0)),
|
||||
inner: new RRect.fromRectAndRadius(rect.deflate(10.0), const Radius.circular(90.0)),
|
||||
strokeWidth: 0.0,
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
test('RoundedRectangleBorder and CircleBorder', () {
|
||||
final RoundedRectangleBorder r = new RoundedRectangleBorder(side: BorderSide.none, borderRadius: new BorderRadius.circular(10.0));
|
||||
final CircleBorder c = const CircleBorder(BorderSide.none);
|
||||
final Rect rect = new Rect.fromLTWH(0.0, 0.0, 100.0, 20.0); // center is x=40..60 y=10
|
||||
final Matcher looksLikeR = isPathThat(
|
||||
includes: const <Offset>[ const Offset(30.0, 10.0), const Offset(50.0, 10.0), ],
|
||||
excludes: const <Offset>[ const Offset(1.0, 1.0), const Offset(99.0, 19.0), ],
|
||||
);
|
||||
final Matcher looksLikeC = isPathThat(
|
||||
includes: const <Offset>[ const Offset(50.0, 10.0), ],
|
||||
excludes: const <Offset>[ const Offset(1.0, 1.0), const Offset(30.0, 10.0), const Offset(99.0, 19.0), ],
|
||||
);
|
||||
expect(r.getOuterPath(rect), looksLikeR);
|
||||
expect(c.getOuterPath(rect), looksLikeC);
|
||||
expect(ShapeBorder.lerp(r, c, 0.1).getOuterPath(rect), looksLikeR);
|
||||
expect(ShapeBorder.lerp(r, c, 0.9).getOuterPath(rect), looksLikeC);
|
||||
expect(ShapeBorder.lerp(ShapeBorder.lerp(r, c, 0.9), r, 0.1).getOuterPath(rect), looksLikeC);
|
||||
expect(ShapeBorder.lerp(ShapeBorder.lerp(r, c, 0.9), r, 0.9).getOuterPath(rect), looksLikeR);
|
||||
expect(ShapeBorder.lerp(ShapeBorder.lerp(r, c, 0.1), c, 0.1).getOuterPath(rect), looksLikeR);
|
||||
expect(ShapeBorder.lerp(ShapeBorder.lerp(r, c, 0.1), c, 0.9).getOuterPath(rect), looksLikeC);
|
||||
expect(ShapeBorder.lerp(ShapeBorder.lerp(r, c, 0.1), ShapeBorder.lerp(r, c, 0.9), 0.1).getOuterPath(rect), looksLikeR);
|
||||
expect(ShapeBorder.lerp(ShapeBorder.lerp(r, c, 0.1), ShapeBorder.lerp(r, c, 0.9), 0.9).getOuterPath(rect), looksLikeC);
|
||||
expect(ShapeBorder.lerp(r, ShapeBorder.lerp(r, c, 0.9), 0.1).getOuterPath(rect), looksLikeR);
|
||||
expect(ShapeBorder.lerp(r, ShapeBorder.lerp(r, c, 0.9), 0.9).getOuterPath(rect), looksLikeC);
|
||||
expect(ShapeBorder.lerp(c, ShapeBorder.lerp(r, c, 0.1), 0.1).getOuterPath(rect), looksLikeC);
|
||||
expect(ShapeBorder.lerp(c, ShapeBorder.lerp(r, c, 0.1), 0.9).getOuterPath(rect), looksLikeR);
|
||||
|
||||
expect(ShapeBorder.lerp(r, c, 0.1).toString(),
|
||||
'RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.circular(10.0), 10.0% of the way to being a CircleBorder)');
|
||||
expect(ShapeBorder.lerp(r, c, 0.2).toString(),
|
||||
'RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.circular(10.0), 20.0% of the way to being a CircleBorder)');
|
||||
expect(ShapeBorder.lerp(ShapeBorder.lerp(r, c, 0.1), ShapeBorder.lerp(r, c, 0.9), 0.9).toString(),
|
||||
'RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.circular(10.0), 82.0% of the way to being a CircleBorder)');
|
||||
|
||||
expect(ShapeBorder.lerp(c, r, 0.9).toString(),
|
||||
'RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.circular(10.0), 10.0% of the way to being a CircleBorder)');
|
||||
expect(ShapeBorder.lerp(c, r, 0.8).toString(),
|
||||
'RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.circular(10.0), 20.0% of the way to being a CircleBorder)');
|
||||
expect(ShapeBorder.lerp(ShapeBorder.lerp(r, c, 0.9), ShapeBorder.lerp(r, c, 0.1), 0.1).toString(),
|
||||
'RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.circular(10.0), 82.0% of the way to being a CircleBorder)');
|
||||
|
||||
expect(ShapeBorder.lerp(r, c, 0.1), ShapeBorder.lerp(r, c, 0.1));
|
||||
expect(ShapeBorder.lerp(r, c, 0.1).hashCode, ShapeBorder.lerp(r, c, 0.1).hashCode);
|
||||
|
||||
final ShapeBorder direct50 = ShapeBorder.lerp(r, c, 0.5);
|
||||
final ShapeBorder indirect50 = ShapeBorder.lerp(ShapeBorder.lerp(c, r, 0.1), ShapeBorder.lerp(c, r, 0.9), 0.5);
|
||||
expect(direct50, indirect50);
|
||||
expect(direct50.hashCode, indirect50.hashCode);
|
||||
expect(direct50.toString(), indirect50.toString());
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue
Block a user