Bruno Leroux c825031ba2
Fix SegmentedButton border doesn't reflect states (#172754)
## Description

This PR fixes `SegmentedButton` border side not depending on the current
state.

It's based on one @TahaTesser 's great PR: see
https://github.com/flutter/flutter/pull/161942. 🙏
I updated some logic related to disabled border which led to Taha’s PR
failing internal Google tests.
I also added a test to verify the disabled border.

<details><summary>Code sample for screenshots</summary>

```dart
import 'package:flutter/material.dart';

void main() {
  runApp(const SegmentedButtonApp());
}

enum Calendar { day, week, month, year }

class SegmentedButtonApp extends StatefulWidget {
  const SegmentedButtonApp({super.key});

  @override
  State<SegmentedButtonApp> createState() => _SegmentedButtonAppState();
}

class _SegmentedButtonAppState extends State<SegmentedButtonApp> {
  Calendar? calendarView;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        segmentedButtonTheme: SegmentedButtonThemeData(
          style: ButtonStyle(
            side: WidgetStateProperty.fromMap(<WidgetStatesConstraint, BorderSide?>{
              WidgetState.disabled: const BorderSide(color: Colors.grey, width: 2),
              WidgetState.selected & WidgetState.hovered: const BorderSide(
                color: Colors.blue,
                width: 2,
              ),
              WidgetState.selected & WidgetState.focused: const BorderSide(
                color: Colors.pinkAccent,
                width: 2,
              ),
              WidgetState.hovered: const BorderSide(color: Colors.green, width: 2),
              WidgetState.focused: const BorderSide(color: Colors.purple, width: 2),
              WidgetState.any: const BorderSide(color: Colors.amber, width: 2),
            }),
          ),
        ),
      ),
      home: Scaffold(
        body: Center(
          child: SegmentedButton<Calendar>(
            segments: const <ButtonSegment<Calendar>>[
              ButtonSegment<Calendar>(
                value: Calendar.day,
                label: Text('Day'),
                icon: Icon(Icons.calendar_view_day),
                enabled: false,
              ),
              ButtonSegment<Calendar>(
                value: Calendar.week,
                label: Text('Week'),
                icon: Icon(Icons.calendar_view_week),
              ),
              ButtonSegment<Calendar>(
                value: Calendar.month,
                label: Text('Month'),
                icon: Icon(Icons.calendar_view_month),
              ),
              ButtonSegment<Calendar>(
                value: Calendar.year,
                label: Text('Year'),
                icon: Icon(Icons.calendar_today),
              ),
            ],
            selected: <Calendar>{?calendarView},
            emptySelectionAllowed: true,
            onSelectionChanged: (Set<Calendar> newSelection) {
              setState(() {
                calendarView = newSelection.isEmpty ? null : newSelection.first;
              });
            },
          ),
        ),
        floatingActionButton: FloatingActionButton(onPressed: () {}, child: const Icon(Icons.add)),
      ),
    );
  }
}

``` 

</details> 

# Before


https://github.com/user-attachments/assets/1581f431-f87a-4af3-8ef6-f1f0d170e54a


# After


https://github.com/user-attachments/assets/156a8a64-3d9f-4323-9a1d-60624f5ac5d4


## Related Issue

Fixes [SegmentedButton does not set its MaterialState for side
](https://github.com/flutter/flutter/issues/159884)

## Tests

Adds 2 tests.
2025-07-29 23:53:22 +00:00
..