diff --git a/examples/api/lib/widgets/widget_state/widget_state_border_side.0.dart b/examples/api/lib/widgets/widget_state/widget_state_border_side.0.dart new file mode 100644 index 0000000000..06762c0f0b --- /dev/null +++ b/examples/api/lib/widgets/widget_state/widget_state_border_side.0.dart @@ -0,0 +1,60 @@ +// Copyright 2014 The Flutter 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/material.dart'; + +/// Flutter code sample for [WidgetStateBorderSide]. + +void main() { + runApp(const WidgetStateBorderSideExampleApp()); +} + +class WidgetStateBorderSideExampleApp extends StatelessWidget { + const WidgetStateBorderSideExampleApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + home: Scaffold( + appBar: AppBar(title: const Text('WidgetStateBorderSide Sample')), + body: const Center( + child: WidgetStateBorderSideExample(), + ), + ), + ); + } +} + +class WidgetStateBorderSideExample extends StatefulWidget { + const WidgetStateBorderSideExample({super.key}); + + @override + State createState() => _WidgetStateBorderSideExampleState(); +} + +class _WidgetStateBorderSideExampleState extends State { + bool _isSelected = true; + + @override + Widget build(BuildContext context) { + return FilterChip( + label: const Text('Select chip'), + selected: _isSelected, + onSelected: (bool value) { + setState(() { + _isSelected = value; + }); + }, + side: const WidgetStateBorderSide.fromMap( + { + WidgetState.pressed: BorderSide(color: Colors.green), + WidgetState.hovered: BorderSide(color: Colors.blue), + WidgetState.selected: BorderSide(color: Colors.red), + // Resolves to null if no keys match, deferring to the default value + // of the theme or widget. + }, + ), + ); + } +} diff --git a/examples/api/test/widgets/widget_state/widget_state_border_side.0_test.dart b/examples/api/test/widgets/widget_state/widget_state_border_side.0_test.dart new file mode 100644 index 0000000000..548fe4fd8e --- /dev/null +++ b/examples/api/test/widgets/widget_state/widget_state_border_side.0_test.dart @@ -0,0 +1,76 @@ +// Copyright 2014 The Flutter 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 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:flutter_api_samples/widgets/widget_state/widget_state_border_side.0.dart' + as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + Finder findByBorderColor(Color color) { + return find.byWidgetPredicate((Widget widget) { + if (widget is! Material) { + return false; + } + + final ShapeBorder? shape = widget.shape; + return shape is OutlinedBorder && shape.side.color == color; + }); + } + + testWidgets('FilterChip displays the blue colored border when hovered', (WidgetTester tester) async { + await tester.pumpWidget( + const example.WidgetStateBorderSideExampleApp(), + ); + + // Hover over the FilterChip. + final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); + await gesture.moveTo(tester.getCenter(find.byType(FilterChip))); + + await tester.pumpAndSettle(); + + expect(findByBorderColor(Colors.blue), findsOneWidget); + }); + + testWidgets('FilterChip displays the green colored border when pressed', (WidgetTester tester) async { + await tester.pumpWidget( + const example.WidgetStateBorderSideExampleApp(), + ); + + // Press on the FilterChip. + final TestGesture gesture = await tester.createGesture(); + await gesture.down(tester.getCenter(find.byType(FilterChip))); + + await tester.pumpAndSettle(); + + expect(findByBorderColor(Colors.green), findsOneWidget); + }); + + testWidgets('FilterChip displays the red colored border when selected', (WidgetTester tester) async { + await tester.pumpWidget( + const example.WidgetStateBorderSideExampleApp(), + ); + + expect(findByBorderColor(Colors.red), findsOneWidget); + }); + + testWidgets('FilterChip displays the correct border color when not selected', (WidgetTester tester) async { + await tester.pumpWidget( + const example.WidgetStateBorderSideExampleApp(), + ); + + await tester.tap(find.byType(FilterChip)); + await tester.pumpAndSettle(); + + final ThemeData theme = Theme.of(tester.element(find.byType(FilterChip))); + + // FilterChip's border color defaults to ColorScheme.outlineVariant. + expect( + findByBorderColor(theme.colorScheme.outlineVariant), + findsOneWidget, + ); + }); +} diff --git a/packages/flutter/lib/src/widgets/widget_state.dart b/packages/flutter/lib/src/widgets/widget_state.dart index 14d46bbc96..0cd809def4 100644 --- a/packages/flutter/lib/src/widgets/widget_state.dart +++ b/packages/flutter/lib/src/widgets/widget_state.dart @@ -480,6 +480,13 @@ class _EnabledAndDisabledMouseCursor extends WidgetStateMouseCursor { /// property values. [WidgetStateBorderSide] should only be used with widgets that document /// their support, like [ActionChip.side]. /// +/// {@tool dartpad} +/// This example defines a [WidgetStateBorderSide] which resolves to different +/// border colors depending on how the user interacts with it. +/// +/// ** See code in examples/api/lib/widgets/widget_state/widget_state_border_side.0.dart ** +/// {@end-tool} +/// /// This class should only be used for parameters which are documented to take /// [WidgetStateBorderSide], otherwise only the default state will be used. ///