From edc20aca60dea87b39faa2e07aafa9ddd034e068 Mon Sep 17 00:00:00 2001 From: Lucas Goldner <65627237+lucas-goldner@users.noreply.github.com> Date: Fri, 21 Feb 2025 09:03:58 +0900 Subject: [PATCH] feat: Add selectionColor property to selectable text (#162177) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR aims to add a `selectionColor` property to the `SelectableText` widget. Below I have an image attached showing a SelectableText with a custom selectionColor ```dart SelectableText( 'Hello, world! (Selectable)', selectionColor: Colors.red, ) ``` ![image](https://github.com/user-attachments/assets/ab71a6d7-af87-4a0e-a87a-f16d8b03aaf8) Fixes #162165 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md P.S. This is my first PR to the Flutter repo, so if I can improve something, please let me know 🙇🏽 --------- Co-authored-by: Tong Mu --- .../lib/src/material/selectable_text.dart | 16 +++++++++++++++- .../test/widgets/selectable_text_test.dart | 19 +++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/material/selectable_text.dart b/packages/flutter/lib/src/material/selectable_text.dart index b75a3cb9ea..77d5cd8895 100644 --- a/packages/flutter/lib/src/material/selectable_text.dart +++ b/packages/flutter/lib/src/material/selectable_text.dart @@ -183,6 +183,7 @@ class SelectableText extends StatefulWidget { this.cursorHeight, this.cursorRadius, this.cursorColor, + this.selectionColor, this.selectionHeightStyle = ui.BoxHeightStyle.tight, this.selectionWidthStyle = ui.BoxWidthStyle.tight, this.dragStartBehavior = DragStartBehavior.start, @@ -241,6 +242,7 @@ class SelectableText extends StatefulWidget { this.cursorHeight, this.cursorRadius, this.cursorColor, + this.selectionColor, this.selectionHeightStyle = ui.BoxHeightStyle.tight, this.selectionWidthStyle = ui.BoxWidthStyle.tight, this.dragStartBehavior = DragStartBehavior.start, @@ -361,6 +363,15 @@ class SelectableText extends StatefulWidget { /// Otherwise [ColorScheme.primary] of [ThemeData.colorScheme] is used. final Color? cursorColor; + /// The color to use when painting the selection. + /// + /// If this property is null, this widget gets the selection color from the + /// inherited [DefaultSelectionStyle] (if any); if none, the selection + /// color is derived from the [CupertinoThemeData.primaryColor] on + /// Apple platforms and [ColorScheme.primary] of [ThemeData.colorScheme] on + /// other platforms. + final Color? selectionColor; + /// Controls how tall the selection highlight boxes are computed to be. /// /// See [ui.BoxHeightStyle] for details on available styles. @@ -472,6 +483,9 @@ class SelectableText extends StatefulWidget { properties.add(DoubleProperty('cursorHeight', cursorHeight, defaultValue: null)); properties.add(DiagnosticsProperty('cursorRadius', cursorRadius, defaultValue: null)); properties.add(DiagnosticsProperty('cursorColor', cursorColor, defaultValue: null)); + properties.add( + DiagnosticsProperty('selectionColor', selectionColor, defaultValue: null), + ); properties.add( FlagProperty( 'selectionEnabled', @@ -761,7 +775,7 @@ class _SelectableTextState extends State forceLine: false, minLines: widget.minLines, maxLines: widget.maxLines ?? defaultTextStyle.maxLines, - selectionColor: selectionColor, + selectionColor: widget.selectionColor ?? selectionColor, selectionControls: widget.selectionEnabled ? textSelectionControls : null, onSelectionChanged: _handleSelectionChanged, onSelectionHandleTapped: _handleSelectionHandleTapped, diff --git a/packages/flutter/test/widgets/selectable_text_test.dart b/packages/flutter/test/widgets/selectable_text_test.dart index 0ccece18ed..6927dca416 100644 --- a/packages/flutter/test/widgets/selectable_text_test.dart +++ b/packages/flutter/test/widgets/selectable_text_test.dart @@ -423,6 +423,25 @@ void main() { expect(state.widget.cursorColor, cursorColor); }); + testWidgets('Selectable Text can have custom selection color', (WidgetTester tester) async { + const Color selectionColor = Colors.orange; + const Color defaultSelectionColor = Colors.red; + + await tester.pumpWidget( + const MaterialApp( + home: Material( + child: DefaultSelectionStyle( + selectionColor: defaultSelectionColor, + child: SelectableText('text', selectionColor: selectionColor), + ), + ), + ), + ); + await tester.pump(); + final EditableTextState state = tester.state(find.byType(EditableText)); + expect(state.widget.selectionColor, selectionColor); + }); + testWidgets('Selectable Text has adaptive size', (WidgetTester tester) async { await tester.pumpWidget(boilerplate(child: const SelectableText('s')));