flutter/dev/tools/gen_defaults/lib/segmented_button_template.dart
Furkan Acar 83ac76050d
Add SegmentedButton.styleFrom (#137542)
fixes https://github.com/flutter/flutter/issues/138289

---

SegmentedButtom.styleFrom has been added to the segment button, so there is no longer any need to the button style from the beginning. It works like ElevatedButton.styleFrom only I added selectedForegroundColor, selectedBackgroundColor. In this way, the user will be able to change the color first without checking the MaterialState states. I added tests of the same controls.

#129215 I opened this problem myself, but I was rejected because I handled too many items in a PR. For now, I wrote a structure that only handles MaterialStates instead of users.

old (still avaliable)
<img width="626" alt="image" src="https://github.com/flutter/flutter/assets/65075121/9446b13b-c355-4d20-bda2-c47a23d42d4f">

new (just an option for developer)
<img width="483" alt="image" src="https://github.com/flutter/flutter/assets/65075121/0a645257-4c83-4029-9484-bd746c02265f">

### Code sample

<details>
<summary>expand to view the code sample</summary> 

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

/// Flutter code sample for [SegmentedButton].

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 = Calendar.day;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(useMaterial3: true),
      home: Scaffold(
        body: Center(
          child: SegmentedButton<Calendar>(
            style: SegmentedButton.styleFrom(
              foregroundColor: Colors.amber,
              visualDensity: VisualDensity.comfortable,
            ),
            // style: const ButtonStyle(
            //   foregroundColor: MaterialStatePropertyAll<Color>(Colors.deepPurple),
            //   visualDensity: VisualDensity.comfortable,
            // ),
            segments: const <ButtonSegment<Calendar>>[
              ButtonSegment<Calendar>(
                  value: Calendar.day,
                  label: Text('Day'),
                  icon: Icon(Icons.calendar_view_day)),
              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},
            onSelectionChanged: (Set<Calendar> newSelection) {
              setState(() {
                calendarView = newSelection.first;
              });
            },
          ),
        ),
      ),
    );
  }
}

```

</details>
2024-01-03 21:26:02 +00:00

152 lines
6.0 KiB
Dart

// 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 'template.dart';
class SegmentedButtonTemplate extends TokenTemplate {
const SegmentedButtonTemplate(this.tokenGroup, super.blockName, super.fileName, super.tokens, {
super.colorSchemePrefix = '_colors.',
});
final String tokenGroup;
String _layerOpacity(String layerToken) {
if (tokenAvailable(layerToken)) {
final String layerValue = getToken(layerToken) as String;
if (tokenAvailable(layerValue)) {
final String? opacityValue = opacity(layerValue);
if (opacityValue != null) {
return '.withOpacity($opacityValue)';
}
}
}
return '';
}
String _stateColor(String componentToken, String type, String state) {
final String baseColor = color('$componentToken.$type.$state.state-layer.color', '');
if (baseColor.isEmpty) {
return 'null';
}
final String opacity = _layerOpacity('$componentToken.$state.state-layer.opacity');
return '$baseColor$opacity';
}
@override
String generate() => '''
class _${blockName}DefaultsM3 extends SegmentedButtonThemeData {
_${blockName}DefaultsM3(this.context);
final BuildContext context;
late final ThemeData _theme = Theme.of(context);
late final ColorScheme _colors = _theme.colorScheme;
@override ButtonStyle? get style {
return ButtonStyle(
textStyle: MaterialStatePropertyAll<TextStyle?>(${textStyle('$tokenGroup.label-text')}),
backgroundColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
return ${componentColor('$tokenGroup.disabled')};
}
if (states.contains(MaterialState.selected)) {
return ${componentColor('$tokenGroup.selected.container')};
}
return ${componentColor('$tokenGroup.unselected.container')};
}),
foregroundColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
return ${componentColor('$tokenGroup.disabled.label-text')};
}
if (states.contains(MaterialState.selected)) {
if (states.contains(MaterialState.pressed)) {
return ${componentColor('$tokenGroup.selected.pressed.label-text')};
}
if (states.contains(MaterialState.hovered)) {
return ${componentColor('$tokenGroup.selected.hover.label-text')};
}
if (states.contains(MaterialState.focused)) {
return ${componentColor('$tokenGroup.selected.focus.label-text')};
}
return ${componentColor('$tokenGroup.selected.label-text')};
} else {
if (states.contains(MaterialState.pressed)) {
return ${componentColor('$tokenGroup.unselected.pressed.label-text')};
}
if (states.contains(MaterialState.hovered)) {
return ${componentColor('$tokenGroup.unselected.hover.label-text')};
}
if (states.contains(MaterialState.focused)) {
return ${componentColor('$tokenGroup.unselected.focus.label-text')};
}
return ${componentColor('$tokenGroup.unselected.label-text')};
}
}),
overlayColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.selected)) {
if (states.contains(MaterialState.pressed)) {
return ${_stateColor(tokenGroup, 'selected', 'pressed')};
}
if (states.contains(MaterialState.hovered)) {
return ${_stateColor(tokenGroup, 'selected', 'hover')};
}
if (states.contains(MaterialState.focused)) {
return ${_stateColor(tokenGroup, 'selected', 'focus')};
}
} else {
if (states.contains(MaterialState.pressed)) {
return ${_stateColor(tokenGroup, 'unselected', 'pressed')};
}
if (states.contains(MaterialState.hovered)) {
return ${_stateColor(tokenGroup, 'unselected', 'hover')};
}
if (states.contains(MaterialState.focused)) {
return ${_stateColor(tokenGroup, 'unselected', 'focus')};
}
}
return null;
}),
surfaceTintColor: const MaterialStatePropertyAll<Color>(Colors.transparent),
elevation: const MaterialStatePropertyAll<double>(0),
iconSize: const MaterialStatePropertyAll<double?>(${getToken('$tokenGroup.with-icon.icon.size')}),
side: MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
return ${border("$tokenGroup.disabled.outline")};
}
return ${border("$tokenGroup.outline")};
}),
shape: const MaterialStatePropertyAll<OutlinedBorder>(${shape(tokenGroup, '')}),
minimumSize: const MaterialStatePropertyAll<Size?>(Size.fromHeight(${getToken('$tokenGroup.container.height')})),
);
}
@override
Widget? get selectedIcon => const Icon(Icons.check);
static MaterialStateProperty<Color?> resolveStateColor(Color? unselectedColor, Color? selectedColor){
return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.selected)) {
if (states.contains(MaterialState.pressed)) {
return selectedColor?.withOpacity(0.12);
}
if (states.contains(MaterialState.hovered)) {
return selectedColor?.withOpacity(0.08);
}
if (states.contains(MaterialState.focused)) {
return selectedColor?.withOpacity(0.12);
}
} else {
if (states.contains(MaterialState.pressed)) {
return unselectedColor?.withOpacity(0.12);
}
if (states.contains(MaterialState.hovered)) {
return unselectedColor?.withOpacity(0.08);
}
if (states.contains(MaterialState.focused)) {
return unselectedColor?.withOpacity(0.12);
}
}
return Colors.transparent;
});
}
}
''';
}