mirror of
https://github.com/flutter/flutter
synced 2024-10-13 11:42:54 +00:00
BoxDecoration.borderRadius and RoundedRectangleBorder.borderRadius RTL (#12603)
This commit is contained in:
parent
f6135107bc
commit
0790891600
|
@ -117,8 +117,9 @@ abstract class BorderRadiusGeometry {
|
|||
|
||||
/// Linearly interpolate between two [BorderRadiusGeometry] objects.
|
||||
///
|
||||
/// If either is null, this function interpolates from [BorderRadius.zero], and
|
||||
/// the result is an object of the same type as the non-null argument.
|
||||
/// If either is null, this function interpolates from [BorderRadius.zero],
|
||||
/// and the result is an object of the same type as the non-null argument. (If
|
||||
/// both are null, this returns null.)
|
||||
///
|
||||
/// If [lerp] is applied to two objects of the same type ([BorderRadius] or
|
||||
/// [BorderRadiusDirectional]), an object of that type will be returned (though
|
||||
|
@ -126,6 +127,8 @@ abstract class BorderRadiusGeometry {
|
|||
/// representing a combination of both is returned. That object can be turned
|
||||
/// into a concrete [BorderRadius] using [resolve].
|
||||
static BorderRadiusGeometry lerp(BorderRadiusGeometry a, BorderRadiusGeometry b, double t) {
|
||||
if (a == null && b == null)
|
||||
return null;
|
||||
a ??= BorderRadius.zero;
|
||||
b ??= BorderRadius.zero;
|
||||
return a.add((b.subtract(a)) * t);
|
||||
|
|
|
@ -123,7 +123,7 @@ class BoxDecoration extends Decoration {
|
|||
///
|
||||
/// Applies only to boxes with rectangular shapes; ignored if [shape] is not
|
||||
/// [BoxShape.rectangle].
|
||||
final BorderRadius borderRadius;
|
||||
final BorderRadiusGeometry borderRadius;
|
||||
|
||||
/// A list of shadows cast by this box behind the box.
|
||||
///
|
||||
|
@ -159,7 +159,7 @@ class BoxDecoration extends Decoration {
|
|||
color: Color.lerp(null, color, factor),
|
||||
image: image, // TODO(ianh): fade the image from transparent
|
||||
border: BoxBorder.lerp(null, border, factor),
|
||||
borderRadius: BorderRadius.lerp(null, borderRadius, factor),
|
||||
borderRadius: BorderRadiusGeometry.lerp(null, borderRadius, factor),
|
||||
boxShadow: BoxShadow.lerpList(null, boxShadow, factor),
|
||||
gradient: gradient?.scale(factor),
|
||||
shape: shape,
|
||||
|
@ -223,7 +223,7 @@ class BoxDecoration extends Decoration {
|
|||
color: Color.lerp(a.color, b.color, t),
|
||||
image: t < 0.5 ? a.image : b.image, // TODO(ianh): cross-fade the image
|
||||
border: BoxBorder.lerp(a.border, b.border, t),
|
||||
borderRadius: BorderRadius.lerp(a.borderRadius, b.borderRadius, t),
|
||||
borderRadius: BorderRadiusGeometry.lerp(a.borderRadius, b.borderRadius, t),
|
||||
boxShadow: BoxShadow.lerpList(a.boxShadow, b.boxShadow, t),
|
||||
gradient: Gradient.lerp(a.gradient, b.gradient, t),
|
||||
shape: t < 0.5 ? a.shape : b.shape,
|
||||
|
@ -269,20 +269,20 @@ class BoxDecoration extends Decoration {
|
|||
properties.add(new DiagnosticsProperty<Color>('color', color, defaultValue: null));
|
||||
properties.add(new DiagnosticsProperty<DecorationImage>('image', image, defaultValue: null));
|
||||
properties.add(new DiagnosticsProperty<BoxBorder>('border', border, defaultValue: null));
|
||||
properties.add(new DiagnosticsProperty<BorderRadius>('borderRadius', borderRadius, defaultValue: null));
|
||||
properties.add(new DiagnosticsProperty<BorderRadiusGeometry>('borderRadius', borderRadius, defaultValue: null));
|
||||
properties.add(new IterableProperty<BoxShadow>('boxShadow', boxShadow, defaultValue: null, style: DiagnosticsTreeStyle.whitespace));
|
||||
properties.add(new DiagnosticsProperty<Gradient>('gradient', gradient, defaultValue: null));
|
||||
properties.add(new EnumProperty<BoxShape>('shape', shape, defaultValue: BoxShape.rectangle));
|
||||
}
|
||||
|
||||
@override
|
||||
bool hitTest(Size size, Offset position) {
|
||||
bool hitTest(Size size, Offset position, { TextDirection textDirection }) {
|
||||
assert(shape != null);
|
||||
assert((Offset.zero & size).contains(position));
|
||||
switch (shape) {
|
||||
case BoxShape.rectangle:
|
||||
if (borderRadius != null) {
|
||||
final RRect bounds = borderRadius.toRRect(Offset.zero & size);
|
||||
final RRect bounds = borderRadius.resolve(textDirection).toRRect(Offset.zero & size);
|
||||
return bounds.contains(position);
|
||||
}
|
||||
return true;
|
||||
|
@ -332,7 +332,7 @@ class _BoxDecorationPainter extends BoxPainter {
|
|||
return _cachedBackgroundPaint;
|
||||
}
|
||||
|
||||
void _paintBox(Canvas canvas, Rect rect, Paint paint) {
|
||||
void _paintBox(Canvas canvas, Rect rect, Paint paint, TextDirection textDirection) {
|
||||
switch (_decoration.shape) {
|
||||
case BoxShape.circle:
|
||||
assert(_decoration.borderRadius == null);
|
||||
|
@ -344,13 +344,13 @@ class _BoxDecorationPainter extends BoxPainter {
|
|||
if (_decoration.borderRadius == null) {
|
||||
canvas.drawRect(rect, paint);
|
||||
} else {
|
||||
canvas.drawRRect(_decoration.borderRadius.toRRect(rect), paint);
|
||||
canvas.drawRRect(_decoration.borderRadius.resolve(textDirection).toRRect(rect), paint);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void _paintShadows(Canvas canvas, Rect rect) {
|
||||
void _paintShadows(Canvas canvas, Rect rect, TextDirection textDirection) {
|
||||
if (_decoration.boxShadow == null)
|
||||
return;
|
||||
for (BoxShadow boxShadow in _decoration.boxShadow) {
|
||||
|
@ -358,13 +358,13 @@ class _BoxDecorationPainter extends BoxPainter {
|
|||
..color = boxShadow.color
|
||||
..maskFilter = new MaskFilter.blur(BlurStyle.normal, boxShadow.blurSigma);
|
||||
final Rect bounds = rect.shift(boxShadow.offset).inflate(boxShadow.spreadRadius);
|
||||
_paintBox(canvas, bounds, paint);
|
||||
_paintBox(canvas, bounds, paint, textDirection);
|
||||
}
|
||||
}
|
||||
|
||||
void _paintBackgroundColor(Canvas canvas, Rect rect) {
|
||||
void _paintBackgroundColor(Canvas canvas, Rect rect, TextDirection textDirection) {
|
||||
if (_decoration.color != null || _decoration.gradient != null)
|
||||
_paintBox(canvas, rect, _getBackgroundPaint(rect));
|
||||
_paintBox(canvas, rect, _getBackgroundPaint(rect), textDirection);
|
||||
}
|
||||
|
||||
ImageStream _imageStream;
|
||||
|
@ -399,7 +399,7 @@ class _BoxDecorationPainter extends BoxPainter {
|
|||
if (_decoration.shape == BoxShape.circle)
|
||||
clipPath = new Path()..addOval(rect);
|
||||
else if (_decoration.borderRadius != null)
|
||||
clipPath = new Path()..addRRect(_decoration.borderRadius.toRRect(rect));
|
||||
clipPath = new Path()..addRRect(_decoration.borderRadius.resolve(configuration.textDirection).toRRect(rect));
|
||||
if (clipPath != null) {
|
||||
canvas.save();
|
||||
canvas.clipPath(clipPath);
|
||||
|
@ -444,8 +444,9 @@ class _BoxDecorationPainter extends BoxPainter {
|
|||
assert(configuration != null);
|
||||
assert(configuration.size != null);
|
||||
final Rect rect = offset & configuration.size;
|
||||
_paintShadows(canvas, rect);
|
||||
_paintBackgroundColor(canvas, rect);
|
||||
final TextDirection textDirection = configuration.textDirection;
|
||||
_paintShadows(canvas, rect, textDirection);
|
||||
_paintBackgroundColor(canvas, rect, textDirection);
|
||||
_paintBackgroundImage(canvas, rect, configuration);
|
||||
_decoration.border?.paint(
|
||||
canvas,
|
||||
|
|
|
@ -122,7 +122,12 @@ abstract class Decoration extends Diagnosticable {
|
|||
/// if the decoration only draws a circle, this function might
|
||||
/// return true if the point was inside the circle and false
|
||||
/// otherwise.
|
||||
bool hitTest(Size size, Offset position) => true;
|
||||
///
|
||||
/// The decoration may be sensitive to the [TextDirection]. The
|
||||
/// `textDirection` argument should therefore be provided. If it is known that
|
||||
/// the decoration is not affected by the text direction, then the argument
|
||||
/// may be ommitted or set to null.
|
||||
bool hitTest(Size size, Offset position, { TextDirection textDirection }) => true;
|
||||
|
||||
/// Returns a [BoxPainter] that will paint this decoration.
|
||||
///
|
||||
|
|
|
@ -195,7 +195,7 @@ class FlutterLogoDecoration extends Decoration {
|
|||
|
||||
@override
|
||||
// TODO(ianh): better hit testing
|
||||
bool hitTest(Size size, Offset position) => true;
|
||||
bool hitTest(Size size, Offset position, { TextDirection textDirection }) => true;
|
||||
|
||||
@override
|
||||
BoxPainter createBoxPainter([VoidCallback onChanged]) {
|
||||
|
|
|
@ -38,7 +38,7 @@ class RoundedRectangleBorder extends ShapeBorder {
|
|||
final BorderSide side;
|
||||
|
||||
/// The radii for each corner.
|
||||
final BorderRadius borderRadius;
|
||||
final BorderRadiusGeometry borderRadius;
|
||||
|
||||
@override
|
||||
EdgeInsetsGeometry get dimensions {
|
||||
|
@ -92,13 +92,13 @@ class RoundedRectangleBorder extends ShapeBorder {
|
|||
@override
|
||||
Path getInnerPath(Rect rect, { TextDirection textDirection }) {
|
||||
return new Path()
|
||||
..addRRect(borderRadius.toRRect(rect).deflate(side.width));
|
||||
..addRRect(borderRadius.resolve(textDirection).toRRect(rect).deflate(side.width));
|
||||
}
|
||||
|
||||
@override
|
||||
Path getOuterPath(Rect rect, { TextDirection textDirection }) {
|
||||
return new Path()
|
||||
..addRRect(borderRadius.toRRect(rect));
|
||||
..addRRect(borderRadius.resolve(textDirection).toRRect(rect));
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -109,9 +109,9 @@ class RoundedRectangleBorder extends ShapeBorder {
|
|||
case BorderStyle.solid:
|
||||
final double width = side.width;
|
||||
if (width == 0.0) {
|
||||
canvas.drawRRect(borderRadius.toRRect(rect), side.toPaint());
|
||||
canvas.drawRRect(borderRadius.resolve(textDirection).toRRect(rect), side.toPaint());
|
||||
} else {
|
||||
final RRect outer = borderRadius.toRRect(rect);
|
||||
final RRect outer = borderRadius.resolve(textDirection).toRRect(rect);
|
||||
final RRect inner = outer.deflate(width);
|
||||
final Paint paint = new Paint()
|
||||
..color = side.color;
|
||||
|
|
|
@ -1482,7 +1482,7 @@ class RenderDecoratedBox extends RenderProxyBox {
|
|||
@required Decoration decoration,
|
||||
DecorationPosition position: DecorationPosition.background,
|
||||
ImageConfiguration configuration: ImageConfiguration.empty,
|
||||
RenderBox child
|
||||
RenderBox child,
|
||||
}) : assert(decoration != null),
|
||||
assert(position != null),
|
||||
assert(configuration != null),
|
||||
|
@ -1522,6 +1522,9 @@ class RenderDecoratedBox extends RenderProxyBox {
|
|||
/// The settings to pass to the decoration when painting, so that it can
|
||||
/// resolve images appropriately. See [ImageProvider.resolve] and
|
||||
/// [BoxPainter.paint].
|
||||
///
|
||||
/// The [ImageConfiguration.textDirection] field is also used by
|
||||
/// direction-sensitive [Decoration]s for painting and hit-testing.
|
||||
ImageConfiguration get configuration => _configuration;
|
||||
ImageConfiguration _configuration;
|
||||
set configuration(ImageConfiguration value) {
|
||||
|
@ -1541,7 +1544,7 @@ class RenderDecoratedBox extends RenderProxyBox {
|
|||
|
||||
@override
|
||||
bool hitTestSelf(Offset position) {
|
||||
return _decoration.hitTest(size, position);
|
||||
return _decoration.hitTest(size, position, textDirection: configuration.textDirection);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
45
packages/flutter/test/painting/box_decoration_test.dart
Normal file
45
packages/flutter/test/painting/box_decoration_test.dart
Normal file
|
@ -0,0 +1,45 @@
|
|||
// 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_test/flutter_test.dart';
|
||||
import 'package:flutter/painting.dart';
|
||||
|
||||
import '../rendering/mock_canvas.dart';
|
||||
|
||||
void main() {
|
||||
test('BoxDecoration with BorderRadiusDirectional', () {
|
||||
final BoxDecoration decoration = const BoxDecoration(
|
||||
color: const Color(0xFF000000),
|
||||
borderRadius: const BorderRadiusDirectional.only(topStart: const Radius.circular(100.0)),
|
||||
);
|
||||
final BoxPainter painter = decoration.createBoxPainter();
|
||||
const Size size = const Size(1000.0, 1000.0);
|
||||
expect(
|
||||
(Canvas canvas) {
|
||||
painter.paint(
|
||||
canvas,
|
||||
const Offset(0.0, 0.0),
|
||||
const ImageConfiguration(size: size, textDirection: TextDirection.rtl),
|
||||
);
|
||||
},
|
||||
paints
|
||||
..rrect(rrect: new RRect.fromRectAndCorners(Offset.zero & size, topRight: const Radius.circular(100.0)))
|
||||
);
|
||||
expect(decoration.hitTest(size, const Offset(10.0, 10.0), textDirection: TextDirection.rtl), isTrue);
|
||||
expect(decoration.hitTest(size, const Offset(990.0, 10.0), textDirection: TextDirection.rtl), isFalse);
|
||||
expect(
|
||||
(Canvas canvas) {
|
||||
painter.paint(
|
||||
canvas,
|
||||
const Offset(0.0, 0.0),
|
||||
const ImageConfiguration(size: size, textDirection: TextDirection.ltr),
|
||||
);
|
||||
},
|
||||
paints
|
||||
..rrect(rrect: new RRect.fromRectAndCorners(Offset.zero & size, topLeft: const Radius.circular(100.0)))
|
||||
);
|
||||
expect(decoration.hitTest(size, const Offset(10.0, 10.0), textDirection: TextDirection.ltr), isFalse);
|
||||
expect(decoration.hitTest(size, const Offset(990.0, 10.0), textDirection: TextDirection.ltr), isTrue);
|
||||
});
|
||||
}
|
|
@ -138,7 +138,7 @@ void main() {
|
|||
expect(border.left.width, closeTo(1.9, 0.1));
|
||||
expect(border.left.style, BorderStyle.solid);
|
||||
expect(border.left.color, const Color(0xFF151515));
|
||||
expect(actualDecoration.borderRadius.topLeft.x, closeTo(6.8, 0.1));
|
||||
expect(actualDecoration.borderRadius.resolve(TextDirection.ltr).topLeft.x, closeTo(6.8, 0.1));
|
||||
expect(actualDecoration.shape, BoxShape.rectangle);
|
||||
expect(actualDecoration.boxShadow[0].blurRadius, closeTo(3.1, 0.1));
|
||||
expect(actualDecoration.boxShadow[0].spreadRadius, closeTo(1.2, 0.1));
|
||||
|
|
Loading…
Reference in a new issue