@@ -2467,6 +2467,173 @@ void main() {
24672467 // The icon is aligned to the left of the button.
24682468 expect (buttonTopLeft.dx, iconTopLeft.dx - 24.0 ); // 24.0 - padding between icon and button edge.
24692469 });
2470+
2471+ testWidgets ("OutlinedButton.icon response doesn't hover when disabled" , (WidgetTester tester) async {
2472+ FocusManager .instance.highlightStrategy = FocusHighlightStrategy .alwaysTouch;
2473+ final FocusNode focusNode = FocusNode (debugLabel: 'OutlinedButton.icon Focus' );
2474+ final GlobalKey childKey = GlobalKey ();
2475+ bool hovering = false ;
2476+ await tester.pumpWidget (
2477+ Directionality (
2478+ textDirection: TextDirection .ltr,
2479+ child: SizedBox (
2480+ width: 100 ,
2481+ height: 100 ,
2482+ child: OutlinedButton .icon (
2483+ autofocus: true ,
2484+ onPressed: () {},
2485+ onLongPress: () {},
2486+ onHover: (bool value) { hovering = value; },
2487+ focusNode: focusNode,
2488+ label: SizedBox (key: childKey),
2489+ icon: const Icon (Icons .add),
2490+ ),
2491+ ),
2492+ ),
2493+ );
2494+ await tester.pumpAndSettle ();
2495+ expect (focusNode.hasPrimaryFocus, isTrue);
2496+ final TestGesture gesture = await tester.createGesture (kind: PointerDeviceKind .mouse);
2497+ await gesture.addPointer ();
2498+ await gesture.moveTo (tester.getCenter (find.byKey (childKey)));
2499+ await tester.pumpAndSettle ();
2500+ expect (hovering, isTrue);
2501+
2502+ await tester.pumpWidget (
2503+ Directionality (
2504+ textDirection: TextDirection .ltr,
2505+ child: SizedBox (
2506+ width: 100 ,
2507+ height: 100 ,
2508+ child: OutlinedButton .icon (
2509+ focusNode: focusNode,
2510+ onHover: (bool value) { hovering = value; },
2511+ onPressed: null ,
2512+ label: SizedBox (key: childKey),
2513+ icon: const Icon (Icons .add),
2514+ ),
2515+ ),
2516+ ),
2517+ );
2518+
2519+ await tester.pumpAndSettle ();
2520+ expect (focusNode.hasPrimaryFocus, isFalse);
2521+ focusNode.dispose ();
2522+ });
2523+
2524+ testWidgets ('disabled and hovered OutlinedButton.icon responds to mouse-exit' , (WidgetTester tester) async {
2525+ int onHoverCount = 0 ;
2526+ late bool hover;
2527+ const Key key = Key ('OutlinedButton.icon' );
2528+ Widget buildFrame ({ required bool enabled }) {
2529+ return Directionality (
2530+ textDirection: TextDirection .ltr,
2531+ child: Center (
2532+ child: SizedBox (
2533+ width: 100 ,
2534+ height: 100 ,
2535+ child: OutlinedButton .icon (
2536+ key: key,
2537+ onPressed: enabled ? () { } : null ,
2538+ onHover: (bool value) {
2539+ onHoverCount += 1 ;
2540+ hover = value;
2541+ },
2542+ label: const Text ('OutlinedButton' ),
2543+ icon: const Icon (Icons .add),
2544+ ),
2545+ ),
2546+ ),
2547+ );
2548+ }
2549+
2550+ await tester.pumpWidget (buildFrame (enabled: true ));
2551+ final TestGesture gesture = await tester.createGesture (kind: PointerDeviceKind .mouse);
2552+ await gesture.addPointer ();
2553+
2554+ await gesture.moveTo (tester.getCenter (find.byKey (key)));
2555+ await tester.pumpAndSettle ();
2556+ expect (onHoverCount, 1 );
2557+ expect (hover, true );
2558+
2559+ await tester.pumpWidget (buildFrame (enabled: false ));
2560+ await tester.pumpAndSettle ();
2561+ await gesture.moveTo (Offset .zero);
2562+ // Even though the OutlinedButton has been disabled, the mouse-exit still
2563+ // causes onHover(false) to be called.
2564+ expect (onHoverCount, 2 );
2565+ expect (hover, false );
2566+
2567+ await gesture.moveTo (tester.getCenter (find.byKey (key)));
2568+ await tester.pumpAndSettle ();
2569+ // We no longer see hover events because the OutlinedButton is disabled
2570+ // and it's no longer in the "hovering" state.
2571+ expect (onHoverCount, 2 );
2572+ expect (hover, false );
2573+
2574+ await tester.pumpWidget (buildFrame (enabled: true ));
2575+ await tester.pumpAndSettle ();
2576+ // The OutlinedButton was enabled while it contained the mouse, however
2577+ // we do not call onHover() because it may call setState().
2578+ expect (onHoverCount, 2 );
2579+ expect (hover, false );
2580+
2581+ await gesture.moveTo (tester.getCenter (find.byKey (key)) - const Offset (1 , 1 ));
2582+ await tester.pumpAndSettle ();
2583+ // Moving the mouse a little within the OutlinedButton doesn't change anything.
2584+ expect (onHoverCount, 2 );
2585+ expect (hover, false );
2586+ });
2587+
2588+ testWidgets ('Can set OutlinedButton.icon focus and Can set unFocus.' , (WidgetTester tester) async {
2589+ final FocusNode node = FocusNode (debugLabel: 'OutlinedButton.icon Focus' );
2590+ bool gotFocus = false ;
2591+ await tester.pumpWidget (
2592+ Directionality (
2593+ textDirection: TextDirection .ltr,
2594+ child: OutlinedButton .icon (
2595+ focusNode: node,
2596+ onFocusChange: (bool focused) => gotFocus = focused,
2597+ onPressed: () { },
2598+ label: const SizedBox (),
2599+ icon: const Icon (Icons .add),
2600+ ),
2601+ ),
2602+ );
2603+
2604+ node.requestFocus ();
2605+ await tester.pump ();
2606+ expect (gotFocus, isTrue);
2607+ expect (node.hasFocus, isTrue);
2608+ node.unfocus ();
2609+ await tester.pump ();
2610+ expect (gotFocus, isFalse);
2611+ expect (node.hasFocus, isFalse);
2612+ node.dispose ();
2613+ });
2614+
2615+ testWidgets ('When OutlinedButton.icon disable, Can not set OutlinedButton.icon focus.' , (WidgetTester tester) async {
2616+ final FocusNode node = FocusNode (debugLabel: 'OutlinedButton.icon Focus' );
2617+ bool gotFocus = false ;
2618+ await tester.pumpWidget (
2619+ Directionality (
2620+ textDirection: TextDirection .ltr,
2621+ child: OutlinedButton .icon (
2622+ focusNode: node,
2623+ onFocusChange: (bool focused) => gotFocus = focused,
2624+ onPressed: null ,
2625+ label: const SizedBox (),
2626+ icon: const Icon (Icons .add),
2627+ ),
2628+ ),
2629+ );
2630+
2631+ node.requestFocus ();
2632+ await tester.pump ();
2633+ expect (gotFocus, isFalse);
2634+ expect (node.hasFocus, isFalse);
2635+ node.dispose ();
2636+ });
24702637}
24712638
24722639TextStyle _iconStyle (WidgetTester tester, IconData icon) {
0 commit comments