Allow ClipRRect.borderRadius to support BorderRadiusDirectional (#101200)

This commit is contained in:
MrBirb 2022-04-09 11:44:04 +03:00 committed by GitHub
parent 8ff3640c9f
commit 074ee4b2f4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 108 additions and 8 deletions

View file

@ -1504,11 +1504,13 @@ class RenderClipRRect extends _RenderCustomClip<RRect> {
/// [Clip.none], no clipping will be applied.
RenderClipRRect({
RenderBox? child,
BorderRadius borderRadius = BorderRadius.zero,
BorderRadiusGeometry borderRadius = BorderRadius.zero,
CustomClipper<RRect>? clipper,
Clip clipBehavior = Clip.antiAlias,
TextDirection? textDirection,
}) : assert(clipBehavior != null),
_borderRadius = borderRadius,
_textDirection = textDirection,
super(child: child, clipper: clipper, clipBehavior: clipBehavior) {
assert(_borderRadius != null || clipper != null);
}
@ -1519,9 +1521,9 @@ class RenderClipRRect extends _RenderCustomClip<RRect> {
/// exceed width/height.
///
/// This value is ignored if [clipper] is non-null.
BorderRadius get borderRadius => _borderRadius;
BorderRadius _borderRadius;
set borderRadius(BorderRadius value) {
BorderRadiusGeometry get borderRadius => _borderRadius;
BorderRadiusGeometry _borderRadius;
set borderRadius(BorderRadiusGeometry value) {
assert(value != null);
if (_borderRadius == value)
return;
@ -1529,8 +1531,18 @@ class RenderClipRRect extends _RenderCustomClip<RRect> {
_markNeedsClip();
}
/// The text direction with which to resolve [borderRadius].
TextDirection? get textDirection => _textDirection;
TextDirection? _textDirection;
set textDirection(TextDirection? value) {
if (_textDirection == value)
return;
_textDirection = value;
_markNeedsClip();
}
@override
RRect get _defaultClip => _borderRadius.toRRect(Offset.zero & size);
RRect get _defaultClip => _borderRadius.resolve(textDirection).toRRect(Offset.zero & size);
@override
bool hitTest(BoxHitTestResult result, { required Offset position }) {

View file

@ -743,7 +743,7 @@ class ClipRRect extends SingleChildRenderObjectWidget {
/// exceed width/height.
///
/// This value is ignored if [clipper] is non-null.
final BorderRadius? borderRadius;
final BorderRadiusGeometry? borderRadius;
/// If non-null, determines which clip to use.
final CustomClipper<RRect>? clipper;
@ -759,6 +759,7 @@ class ClipRRect extends SingleChildRenderObjectWidget {
borderRadius: borderRadius!,
clipper: clipper,
clipBehavior: clipBehavior,
textDirection: Directionality.maybeOf(context),
);
}
@ -767,13 +768,14 @@ class ClipRRect extends SingleChildRenderObjectWidget {
renderObject
..borderRadius = borderRadius!
..clipBehavior = clipBehavior
..clipper = clipper;
..clipper = clipper
..textDirection = Directionality.maybeOf(context);
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(DiagnosticsProperty<BorderRadius>('borderRadius', borderRadius, showName: false, defaultValue: null));
properties.add(DiagnosticsProperty<BorderRadiusGeometry>('borderRadius', borderRadius, showName: false, defaultValue: null));
properties.add(DiagnosticsProperty<CustomClipper<RRect>>('clipper', clipper, defaultValue: null));
}
}

View file

@ -883,4 +883,90 @@ void main() {
..restore(),
);
});
testWidgets('ClipRRect supports BorderRadiusDirectional', (WidgetTester tester) async {
const Radius startRadius = Radius.circular(15.0);
const Radius endRadius = Radius.circular(30.0);
Widget buildClipRRect(TextDirection textDirection) {
return Directionality(
textDirection: textDirection,
child: const ClipRRect(
borderRadius: BorderRadiusDirectional.horizontal(
start: startRadius,
end: endRadius,
),
),
);
}
for (final TextDirection textDirection in TextDirection.values) {
await tester.pumpWidget(buildClipRRect(textDirection));
final RenderClipRRect renderClip = tester.allRenderObjects.whereType<RenderClipRRect>().first;
final bool isRtl = textDirection == TextDirection.rtl;
expect(renderClip.borderRadius.resolve(textDirection).topLeft, isRtl ? endRadius : startRadius);
expect(renderClip.borderRadius.resolve(textDirection).topRight, isRtl ? startRadius : endRadius);
expect(renderClip.borderRadius.resolve(textDirection).bottomLeft, isRtl ? endRadius : startRadius);
expect(renderClip.borderRadius.resolve(textDirection).bottomRight, isRtl ? startRadius : endRadius);
}
});
testWidgets('ClipRRect is direction-aware', (WidgetTester tester) async {
const Radius startRadius = Radius.circular(15.0);
const Radius endRadius = Radius.circular(30.0);
TextDirection textDirection = TextDirection.ltr;
Widget buildClipRRect(TextDirection textDirection) {
return Directionality(
textDirection: textDirection,
child: const ClipRRect(
borderRadius: BorderRadiusDirectional.horizontal(
start: startRadius,
end: endRadius,
),
),
);
}
Widget buildStatefulClipRRect() {
return StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Directionality(
textDirection: textDirection,
child: SizedBox(
width: 100.0,
height: 100.0,
child: ClipRRect(
borderRadius: const BorderRadiusDirectional.horizontal(
start: startRadius,
end: endRadius,
),
child: GestureDetector(
onTap: () {
setState(() {
textDirection = TextDirection.rtl;
});
},
),
),
),
);
},
);
}
for (final TextDirection textDirection in TextDirection.values) {
await tester.pumpWidget(buildClipRRect(textDirection));
final RenderClipRRect renderClip = tester.allRenderObjects.whereType<RenderClipRRect>().first;
final bool isRtl = textDirection == TextDirection.rtl;
expect(renderClip.textDirection, isRtl ? TextDirection.rtl : TextDirection.ltr);
}
await tester.pumpWidget(buildStatefulClipRRect());
final RenderClipRRect renderClip = tester.allRenderObjects.whereType<RenderClipRRect>().first;
expect(renderClip.textDirection, TextDirection.ltr);
await tester.tapAt(Offset.zero);
await tester.pump();
expect(renderClip.textDirection, TextDirection.rtl);
});
}