mirror of
https://github.com/flutter/flutter
synced 2024-09-13 05:11:45 +00:00
Fix: selection handles do not inherit color from local Theme
widget (#142476)
This change uses `CapturedTheme`s to capture the themes from the context the selection handles were built in and wraps the handles with them so they can correctly inherit `Theme`s from local `Theme` widgets. `CapturedTheme`s only captures `InheritedTheme`s, so this change also makes `_InheritedCupertinoTheme` an `InheritedTheme`. This is so we can capture themes declared under a `CupertinoTheme`, for example `primaryColor` is used as the selection handle color. Fixes #74890
This commit is contained in:
parent
bd715036b5
commit
1daac1b875
|
@ -130,7 +130,7 @@ class CupertinoTheme extends StatelessWidget {
|
|||
}
|
||||
}
|
||||
|
||||
class _InheritedCupertinoTheme extends InheritedWidget {
|
||||
class _InheritedCupertinoTheme extends InheritedTheme {
|
||||
const _InheritedCupertinoTheme({
|
||||
required this.theme,
|
||||
required super.child,
|
||||
|
@ -138,6 +138,11 @@ class _InheritedCupertinoTheme extends InheritedWidget {
|
|||
|
||||
final CupertinoTheme theme;
|
||||
|
||||
@override
|
||||
Widget wrap(BuildContext context, Widget child) {
|
||||
return CupertinoTheme(data: theme.data, child: child);
|
||||
}
|
||||
|
||||
@override
|
||||
bool updateShouldNotify(_InheritedCupertinoTheme old) => theme.data != old.theme.data;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import 'debug.dart';
|
|||
import 'editable_text.dart';
|
||||
import 'framework.dart';
|
||||
import 'gesture_detector.dart';
|
||||
import 'inherited_theme.dart';
|
||||
import 'magnifier.dart';
|
||||
import 'overlay.dart';
|
||||
import 'scrollable.dart';
|
||||
|
@ -1375,12 +1376,22 @@ class SelectionOverlay {
|
|||
return;
|
||||
}
|
||||
|
||||
_handles = (
|
||||
start: OverlayEntry(builder: _buildStartHandle),
|
||||
end: OverlayEntry(builder: _buildEndHandle),
|
||||
final OverlayState overlay = Overlay.of(context, rootOverlay: true, debugRequiredFor: debugRequiredFor);
|
||||
|
||||
final CapturedThemes capturedThemes = InheritedTheme.capture(
|
||||
from: context,
|
||||
to: overlay.context,
|
||||
);
|
||||
Overlay.of(context, rootOverlay: true, debugRequiredFor: debugRequiredFor)
|
||||
.insertAll(<OverlayEntry>[_handles!.start, _handles!.end]);
|
||||
|
||||
_handles = (
|
||||
start: OverlayEntry(builder: (BuildContext context) {
|
||||
return capturedThemes.wrap(_buildStartHandle(context));
|
||||
}),
|
||||
end: OverlayEntry(builder: (BuildContext context) {
|
||||
return capturedThemes.wrap(_buildEndHandle(context));
|
||||
}),
|
||||
);
|
||||
overlay.insertAll(<OverlayEntry>[_handles!.start, _handles!.end]);
|
||||
}
|
||||
|
||||
/// {@template flutter.widgets.SelectionOverlay.hideHandles}
|
||||
|
|
|
@ -621,6 +621,47 @@ void main() {
|
|||
},
|
||||
);
|
||||
|
||||
testWidgets('selection handles color respects CupertinoTheme', (WidgetTester tester) async {
|
||||
// Regression test for https://github.com/flutter/flutter/issues/74890.
|
||||
const Color expectedSelectionHandleColor = Color.fromARGB(255, 10, 200, 255);
|
||||
|
||||
final TextEditingController controller = TextEditingController(text: 'Some text.');
|
||||
|
||||
await tester.pumpWidget(
|
||||
CupertinoApp(
|
||||
theme: const CupertinoThemeData(
|
||||
primaryColor: Colors.red,
|
||||
),
|
||||
home: Center(
|
||||
child: CupertinoTheme(
|
||||
data: const CupertinoThemeData(
|
||||
primaryColor: expectedSelectionHandleColor,
|
||||
),
|
||||
child: CupertinoTextField(controller: controller),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.tapAt(textOffsetToPosition(tester, 0));
|
||||
await tester.pump();
|
||||
await tester.tapAt(textOffsetToPosition(tester, 0));
|
||||
await tester.pumpAndSettle();
|
||||
final Iterable<RenderBox> boxes = tester.renderObjectList<RenderBox>(
|
||||
find.descendant(
|
||||
of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_SelectionHandleOverlay'),
|
||||
matching: find.byType(CustomPaint),
|
||||
),
|
||||
);
|
||||
expect(boxes.length, 2);
|
||||
|
||||
for (final RenderBox box in boxes) {
|
||||
expect(box, paints..path(color: expectedSelectionHandleColor));
|
||||
}
|
||||
},
|
||||
variant: TargetPlatformVariant.only(TargetPlatform.iOS),
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'uses DefaultSelectionStyle for selection and cursor colors if provided',
|
||||
(WidgetTester tester) async {
|
||||
|
|
|
@ -9292,6 +9292,49 @@ void main() {
|
|||
expect(editableText.style.color, isNull);
|
||||
});
|
||||
|
||||
testWidgets('selection handles color respects Theme', (WidgetTester tester) async {
|
||||
// Regression test for https://github.com/flutter/flutter/issues/74890.
|
||||
const Color expectedSelectionHandleColor = Color.fromARGB(255, 10, 200, 255);
|
||||
|
||||
final TextEditingController controller = TextEditingController(text: 'Some text.');
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeData(
|
||||
textSelectionTheme: const TextSelectionThemeData(
|
||||
selectionHandleColor: Colors.red,
|
||||
),
|
||||
),
|
||||
home: Material(
|
||||
child: Theme(
|
||||
data: ThemeData(
|
||||
textSelectionTheme: const TextSelectionThemeData(
|
||||
selectionHandleColor: expectedSelectionHandleColor,
|
||||
),
|
||||
),
|
||||
child: TextField(controller: controller),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.longPressAt(textOffsetToPosition(tester, 0));
|
||||
await tester.pumpAndSettle();
|
||||
final Iterable<RenderBox> boxes = tester.renderObjectList<RenderBox>(
|
||||
find.descendant(
|
||||
of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_SelectionHandleOverlay'),
|
||||
matching: find.byType(CustomPaint),
|
||||
),
|
||||
);
|
||||
expect(boxes.length, 2);
|
||||
|
||||
for (final RenderBox box in boxes) {
|
||||
expect(box, paints..path(color: expectedSelectionHandleColor));
|
||||
}
|
||||
},
|
||||
variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android, TargetPlatform.fuchsia }),
|
||||
);
|
||||
|
||||
testWidgets('style enforces required fields', (WidgetTester tester) async {
|
||||
Widget buildFrame(TextStyle style) {
|
||||
return MaterialApp(
|
||||
|
|
Loading…
Reference in a new issue