Fix SegmentedButton
clipping when drawing segments (#149739)
fixes [`SegmentedButton` doesn't clip properly when one of the segments has `ColorFiltered`](https://github.com/flutter/flutter/issues/144990) ### Code sample <details> <summary>expand to view the code sample</summary> ```dart import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Center( child: SegmentedButton<int>( segments: const <ButtonSegment<int>>[ ButtonSegment<int>( value: 0, label: ColorFiltered( colorFilter: ColorFilter.mode(Colors.amber, BlendMode.colorBurn), child: Text('Option 1'), ), ), ButtonSegment<int>( value: 1, label: Text('Option 2'), ), ], onSelectionChanged: (Set<int> selected) {}, selected: const <int>{0}, ), ), ), ); } } ``` </details> ### Before  ### After 
This commit is contained in:
parent
bb831b7a64
commit
fc19ecfc58
@ -895,12 +895,11 @@ class _RenderSegmentedButton<T> extends RenderBox with
|
|||||||
Path? enabledClipPath;
|
Path? enabledClipPath;
|
||||||
Path? disabledClipPath;
|
Path? disabledClipPath;
|
||||||
|
|
||||||
context.canvas..save()..clipPath(borderClipPath);
|
|
||||||
while (child != null) {
|
while (child != null) {
|
||||||
final _SegmentedButtonContainerBoxParentData childParentData = child.parentData! as _SegmentedButtonContainerBoxParentData;
|
final _SegmentedButtonContainerBoxParentData childParentData = child.parentData! as _SegmentedButtonContainerBoxParentData;
|
||||||
final Rect childRect = childParentData.surroundingRect!.outerRect.shift(offset);
|
final Rect childRect = childParentData.surroundingRect!.outerRect.shift(offset);
|
||||||
|
|
||||||
context.canvas..save()..clipRect(childRect);
|
context.canvas..save()..clipPath(borderClipPath);
|
||||||
context.paintChild(child, childParentData.offset + offset);
|
context.paintChild(child, childParentData.offset + offset);
|
||||||
context.canvas.restore();
|
context.canvas.restore();
|
||||||
|
|
||||||
@ -935,8 +934,8 @@ class _RenderSegmentedButton<T> extends RenderBox with
|
|||||||
final BorderSide divider = segments[index - 1].enabled || segments[index].enabled
|
final BorderSide divider = segments[index - 1].enabled || segments[index].enabled
|
||||||
? enabledBorder.side.copyWith(strokeAlign: 0.0)
|
? enabledBorder.side.copyWith(strokeAlign: 0.0)
|
||||||
: disabledBorder.side.copyWith(strokeAlign: 0.0);
|
: disabledBorder.side.copyWith(strokeAlign: 0.0);
|
||||||
final Offset top = Offset(dividerPos, childRect.top);
|
final Offset top = Offset(dividerPos, borderRect.top);
|
||||||
final Offset bottom = Offset(dividerPos, childRect.bottom);
|
final Offset bottom = Offset(dividerPos, borderRect.bottom);
|
||||||
context.canvas.drawLine(top, bottom, divider.toPaint());
|
context.canvas.drawLine(top, bottom, divider.toPaint());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -944,7 +943,6 @@ class _RenderSegmentedButton<T> extends RenderBox with
|
|||||||
child = childAfter(child);
|
child = childAfter(child);
|
||||||
index += 1;
|
index += 1;
|
||||||
}
|
}
|
||||||
context.canvas.restore();
|
|
||||||
|
|
||||||
// Paint the outer border for both disabled and enabled clip rect if needed.
|
// Paint the outer border for both disabled and enabled clip rect if needed.
|
||||||
if (disabledClipPath == null) {
|
if (disabledClipPath == null) {
|
||||||
|
@ -1045,6 +1045,79 @@ void main() {
|
|||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
expect(getOverlayColor(tester), paints..rect(color: overlayColor));
|
expect(getOverlayColor(tester), paints..rect(color: overlayColor));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// This is a regression test for https://github.com/flutter/flutter/issues/144990.
|
||||||
|
testWidgets('SegmentedButton clips border path when drawing segments', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
home: Scaffold(
|
||||||
|
body: Center(
|
||||||
|
child: SegmentedButton<int>(
|
||||||
|
segments: const <ButtonSegment<int>>[
|
||||||
|
ButtonSegment<int>(
|
||||||
|
value: 0,
|
||||||
|
label: Text('Option 1'),
|
||||||
|
),
|
||||||
|
ButtonSegment<int>(
|
||||||
|
value: 1,
|
||||||
|
label: Text('Option 2'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
onSelectionChanged: (Set<int> selected) {},
|
||||||
|
selected: const <int>{0},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
find.byType(SegmentedButton<int>),
|
||||||
|
paints
|
||||||
|
..save()
|
||||||
|
..clipPath() // Clip the border.
|
||||||
|
..path(color: const Color(0xffe8def8)) // Draw segment 0.
|
||||||
|
..save()
|
||||||
|
..clipPath() // Clip the border.
|
||||||
|
..path(color: const Color(0x00000000)), // Draw segment 1.
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// This is a regression test for https://github.com/flutter/flutter/issues/144990.
|
||||||
|
testWidgets('SegmentedButton dividers matches border rect size', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
home: Scaffold(
|
||||||
|
body: Center(
|
||||||
|
child: SegmentedButton<int>(
|
||||||
|
segments: const <ButtonSegment<int>>[
|
||||||
|
ButtonSegment<int>(
|
||||||
|
value: 0,
|
||||||
|
label: Text('Option 1'),
|
||||||
|
),
|
||||||
|
ButtonSegment<int>(
|
||||||
|
value: 1,
|
||||||
|
label: Text('Option 2'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
onSelectionChanged: (Set<int> selected) {},
|
||||||
|
selected: const <int>{0},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
const double tapTargetSize = 48.0;
|
||||||
|
expect(
|
||||||
|
find.byType(SegmentedButton<int>),
|
||||||
|
paints
|
||||||
|
..line(
|
||||||
|
p1: const Offset(166.8000030517578, 4.0),
|
||||||
|
p2: const Offset(166.8000030517578, tapTargetSize - 4.0),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<MaterialState> enabled = const <MaterialState>{};
|
Set<MaterialState> enabled = const <MaterialState>{};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user