Skip to content
This repository has been archived by the owner on Feb 22, 2023. It is now read-only.

Commit

Permalink
Support theming CupertinoSwitchs (#116510)
Browse files Browse the repository at this point in the history
* Introduce flag to maximally apply CupertinoTheme

* add missing docs

* add tests

* fix docs

* fix test
  • Loading branch information
guidezpl committed Dec 6, 2022
1 parent 921f077 commit 1e696d3
Show file tree
Hide file tree
Showing 9 changed files with 228 additions and 6 deletions.
68 changes: 68 additions & 0 deletions examples/api/lib/material/switch/switch.3.dart
@@ -0,0 +1,68 @@
// 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.

/// Flutter code sample for [Switch].
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

void main() => runApp(const SwitchApp());

class SwitchApp extends StatelessWidget {
const SwitchApp({super.key});

@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.light(useMaterial3: true).copyWith(
// Use the ambient [CupetinoThemeData] to style all widgets which would
// otherwise use iOS defaults.
cupertinoOverrideTheme: const CupertinoThemeData(applyThemeToAll: true),
),
home: Scaffold(
appBar: AppBar(title: const Text('Switch Sample')),
body: const Center(
child: SwitchExample(),
),
),
);
}
}

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

@override
State<SwitchExample> createState() => _SwitchExampleState();
}

class _SwitchExampleState extends State<SwitchExample> {
bool light = true;

@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Switch.adaptive(
value: light,
onChanged: (bool value) {
setState(() {
light = value;
});
},
),
Switch.adaptive(
// Don't use the ambient [CupetinoThemeData] to style this switch.
applyCupertinoTheme: false,
value: light,
onChanged: (bool value) {
setState(() {
light = value;
});
},
),
],
);
}
}
2 changes: 1 addition & 1 deletion examples/api/test/material/switch/switch.1_test.dart
Expand Up @@ -3,7 +3,7 @@
// found in the LICENSE file.

import 'package:flutter/material.dart';
import 'package:flutter_api_samples/material/switch/switch.0.dart' as example;
import 'package:flutter_api_samples/material/switch/switch.1.dart' as example;
import 'package:flutter_test/flutter_test.dart';

void main() {
Expand Down
24 changes: 24 additions & 0 deletions examples/api/test/material/switch/switch.3_test.dart
@@ -0,0 +1,24 @@
// 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';
import 'package:flutter_api_samples/material/switch/switch.3.dart' as example;
import 'package:flutter_test/flutter_test.dart';

void main() {
testWidgets('Can toggle switch', (WidgetTester tester) async {
await tester.pumpWidget(
const example.SwitchApp(),
);

final Finder switchFinder = find.byType(Switch).first;
Switch materialSwitch = tester.widget<Switch>(switchFinder);
expect(materialSwitch.value, true);

await tester.tap(switchFinder);
await tester.pumpAndSettle();
materialSwitch = tester.widget<Switch>(switchFinder);
expect(materialSwitch.value, false);
});
}
27 changes: 22 additions & 5 deletions packages/flutter/lib/src/cupertino/switch.dart
Expand Up @@ -14,6 +14,7 @@ import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';

import 'colors.dart';
import 'theme.dart';
import 'thumb_painter.dart';

// Examples can assume:
Expand Down Expand Up @@ -72,6 +73,7 @@ class CupertinoSwitch extends StatefulWidget {
this.activeColor,
this.trackColor,
this.thumbColor,
this.applyTheme,
this.dragStartBehavior = DragStartBehavior.start,
}) : assert(value != null),
assert(dragStartBehavior != null);
Expand Down Expand Up @@ -105,13 +107,15 @@ class CupertinoSwitch extends StatefulWidget {
/// ```
final ValueChanged<bool>? onChanged;

/// The color to use when this switch is on.
/// The color to use for the track when the switch is on.
///
/// Defaults to [CupertinoColors.systemGreen] when null and ignores
/// the [CupertinoTheme] in accordance to native iOS behavior.
/// If null and [applyTheme] is false, defaults to [CupertinoColors.systemGreen]
/// in accordance to native iOS behavior. Otherwise, defaults to
/// [CupertinoThemeData.primaryColor].
final Color? activeColor;

/// The color to use for the background when the switch is off.

/// The color to use for the track when the switch is off.
///
/// Defaults to [CupertinoColors.secondarySystemFill] when null.
final Color? trackColor;
Expand All @@ -121,6 +125,16 @@ class CupertinoSwitch extends StatefulWidget {
/// Defaults to [CupertinoColors.white] when null.
final Color? thumbColor;

/// {@template flutter.cupertino.CupertinoSwitch.applyTheme}
/// Whether to apply the ambient [CupertinoThemeData].
///
/// If true, the track uses [CupertinoThemeData.primaryColor] for the track
/// when the switch is on.
///
/// Defaults to [CupertinoThemeData.applyThemeToAll].
/// {@endtemplate}
final bool? applyTheme;

/// {@template flutter.cupertino.CupertinoSwitch.dragStartBehavior}
/// Determines the way that drag start behavior is handled.
///
Expand Down Expand Up @@ -310,6 +324,7 @@ class _CupertinoSwitchState extends State<CupertinoSwitch> with TickerProviderSt

@override
Widget build(BuildContext context) {
final CupertinoThemeData theme = CupertinoTheme.of(context);
if (needsPositionAnimation) {
_resumePositionAnimation();
}
Expand All @@ -320,7 +335,9 @@ class _CupertinoSwitchState extends State<CupertinoSwitch> with TickerProviderSt
child: _CupertinoSwitchRenderObjectWidget(
value: widget.value,
activeColor: CupertinoDynamicColor.resolve(
widget.activeColor ?? CupertinoColors.systemGreen,
widget.activeColor
?? ((widget.applyTheme ?? theme.applyThemeToAll) ? theme.primaryColor : null)
?? CupertinoColors.systemGreen,
context,
),
trackColor: CupertinoDynamicColor.resolve(widget.trackColor ?? CupertinoColors.secondarySystemFill, context),
Expand Down
38 changes: 38 additions & 0 deletions packages/flutter/lib/src/cupertino/theme.dart
Expand Up @@ -22,6 +22,7 @@ const _CupertinoThemeDefaults _kDefaultTheme = _CupertinoThemeDefaults(
// Values extracted from navigation bar. For toolbar or tabbar the dark color is 0xF0161616.
),
CupertinoColors.systemBackground,
false,
_CupertinoTextThemeDefaults(CupertinoColors.label, CupertinoColors.inactiveGray),
);

Expand Down Expand Up @@ -172,13 +173,15 @@ class CupertinoThemeData extends NoDefaultCupertinoThemeData with Diagnosticable
CupertinoTextThemeData? textTheme,
Color? barBackgroundColor,
Color? scaffoldBackgroundColor,
bool? applyThemeToAll,
}) : this.raw(
brightness,
primaryColor,
primaryContrastingColor,
textTheme,
barBackgroundColor,
scaffoldBackgroundColor,
applyThemeToAll,
);

/// Same as the default constructor but with positional arguments to avoid
Expand All @@ -193,13 +196,15 @@ class CupertinoThemeData extends NoDefaultCupertinoThemeData with Diagnosticable
CupertinoTextThemeData? textTheme,
Color? barBackgroundColor,
Color? scaffoldBackgroundColor,
bool? applyThemeToAll,
) : this._rawWithDefaults(
brightness,
primaryColor,
primaryContrastingColor,
textTheme,
barBackgroundColor,
scaffoldBackgroundColor,
applyThemeToAll,
_kDefaultTheme,
);

Expand All @@ -210,6 +215,7 @@ class CupertinoThemeData extends NoDefaultCupertinoThemeData with Diagnosticable
CupertinoTextThemeData? textTheme,
Color? barBackgroundColor,
Color? scaffoldBackgroundColor,
bool? applyThemeToAll,
this._defaults,
) : super(
brightness: brightness,
Expand All @@ -218,6 +224,7 @@ class CupertinoThemeData extends NoDefaultCupertinoThemeData with Diagnosticable
textTheme: textTheme,
barBackgroundColor: barBackgroundColor,
scaffoldBackgroundColor: scaffoldBackgroundColor,
applyThemeToAll: applyThemeToAll,
);

final _CupertinoThemeDefaults _defaults;
Expand All @@ -239,6 +246,9 @@ class CupertinoThemeData extends NoDefaultCupertinoThemeData with Diagnosticable
@override
Color get scaffoldBackgroundColor => super.scaffoldBackgroundColor ?? _defaults.scaffoldBackgroundColor;

@override
bool get applyThemeToAll => super.applyThemeToAll ?? _defaults.applyThemeToAll;

@override
NoDefaultCupertinoThemeData noDefault() {
return NoDefaultCupertinoThemeData(
Expand All @@ -248,6 +258,7 @@ class CupertinoThemeData extends NoDefaultCupertinoThemeData with Diagnosticable
textTheme: super.textTheme,
barBackgroundColor: super.barBackgroundColor,
scaffoldBackgroundColor: super.scaffoldBackgroundColor,
applyThemeToAll: super.applyThemeToAll,
);
}

Expand All @@ -262,6 +273,7 @@ class CupertinoThemeData extends NoDefaultCupertinoThemeData with Diagnosticable
super.textTheme?.resolveFrom(context),
convertColor(super.barBackgroundColor),
convertColor(super.scaffoldBackgroundColor),
applyThemeToAll,
_defaults.resolveFrom(context, super.textTheme == null),
);
}
Expand All @@ -274,6 +286,7 @@ class CupertinoThemeData extends NoDefaultCupertinoThemeData with Diagnosticable
CupertinoTextThemeData? textTheme,
Color? barBackgroundColor,
Color? scaffoldBackgroundColor,
bool? applyThemeToAll,
}) {
return CupertinoThemeData._rawWithDefaults(
brightness ?? super.brightness,
Expand All @@ -282,6 +295,7 @@ class CupertinoThemeData extends NoDefaultCupertinoThemeData with Diagnosticable
textTheme ?? super.textTheme,
barBackgroundColor ?? super.barBackgroundColor,
scaffoldBackgroundColor ?? super.scaffoldBackgroundColor,
applyThemeToAll ?? super.applyThemeToAll,
_defaults,
);
}
Expand All @@ -295,6 +309,7 @@ class CupertinoThemeData extends NoDefaultCupertinoThemeData with Diagnosticable
properties.add(createCupertinoColorProperty('primaryContrastingColor', primaryContrastingColor, defaultValue: defaultData.primaryContrastingColor));
properties.add(createCupertinoColorProperty('barBackgroundColor', barBackgroundColor, defaultValue: defaultData.barBackgroundColor));
properties.add(createCupertinoColorProperty('scaffoldBackgroundColor', scaffoldBackgroundColor, defaultValue: defaultData.scaffoldBackgroundColor));
properties.add(DiagnosticsProperty<bool>('applyThemeToAll', applyThemeToAll, defaultValue: defaultData.applyThemeToAll));
textTheme.debugFillProperties(properties);
}
}
Expand Down Expand Up @@ -322,6 +337,7 @@ class NoDefaultCupertinoThemeData {
this.textTheme,
this.barBackgroundColor,
this.scaffoldBackgroundColor,
this.applyThemeToAll,
});

/// The brightness override for Cupertino descendants.
Expand Down Expand Up @@ -389,6 +405,22 @@ class NoDefaultCupertinoThemeData {
/// Defaults to [CupertinoColors.systemBackground].
final Color? scaffoldBackgroundColor;

/// Flag to apply this theme to all descendant Cupertino widgets.
///
/// Certain Cupertino widgets previously didn't use theming, matching past
/// versions of iOS. For example, [CupertinoSwitch]s always used
/// [CupertinoColors.systemGreen] when active.
///
/// Today, however, these widgets can indeed be themed on iOS. Moreover on
/// macOS, the accent color is reflected in these widgets. Turning this flag
/// on ensures that descendant Cupertino widgets will be themed accordingly.
///
/// This flag currently applies to the following widgets:
/// - [CupertinoSwitch] & [Switch.adaptive]
///
/// Defaults to false.
final bool? applyThemeToAll;

/// Returns an instance of the theme data whose property getters only return
/// the construction time specifications with no derived values.
///
Expand All @@ -412,6 +444,7 @@ class NoDefaultCupertinoThemeData {
textTheme: textTheme?.resolveFrom(context),
barBackgroundColor: convertColor(barBackgroundColor),
scaffoldBackgroundColor: convertColor(scaffoldBackgroundColor),
applyThemeToAll: applyThemeToAll,
);
}

Expand All @@ -428,6 +461,7 @@ class NoDefaultCupertinoThemeData {
CupertinoTextThemeData? textTheme,
Color? barBackgroundColor ,
Color? scaffoldBackgroundColor,
bool? applyThemeToAll,
}) {
return NoDefaultCupertinoThemeData(
brightness: brightness ?? this.brightness,
Expand All @@ -436,6 +470,7 @@ class NoDefaultCupertinoThemeData {
textTheme: textTheme ?? this.textTheme,
barBackgroundColor: barBackgroundColor ?? this.barBackgroundColor,
scaffoldBackgroundColor: scaffoldBackgroundColor ?? this.scaffoldBackgroundColor,
applyThemeToAll: applyThemeToAll ?? this.applyThemeToAll,
);
}
}
Expand All @@ -448,6 +483,7 @@ class _CupertinoThemeDefaults {
this.primaryContrastingColor,
this.barBackgroundColor,
this.scaffoldBackgroundColor,
this.applyThemeToAll,
this.textThemeDefaults,
);

Expand All @@ -456,6 +492,7 @@ class _CupertinoThemeDefaults {
final Color primaryContrastingColor;
final Color barBackgroundColor;
final Color scaffoldBackgroundColor;
final bool applyThemeToAll;
final _CupertinoTextThemeDefaults textThemeDefaults;

_CupertinoThemeDefaults resolveFrom(BuildContext context, bool resolveTextTheme) {
Expand All @@ -467,6 +504,7 @@ class _CupertinoThemeDefaults {
convertColor(primaryContrastingColor),
convertColor(barBackgroundColor),
convertColor(scaffoldBackgroundColor),
applyThemeToAll,
resolveTextTheme ? textThemeDefaults.resolveFrom(context) : textThemeDefaults,
);
}
Expand Down
6 changes: 6 additions & 0 deletions packages/flutter/lib/src/material/switch.dart
Expand Up @@ -117,6 +117,7 @@ class Switch extends StatelessWidget {
this.onFocusChange,
this.autofocus = false,
}) : _switchType = _SwitchType.material,
applyCupertinoTheme = false,
assert(dragStartBehavior != null),
assert(activeThumbImage != null || onActiveThumbImageError == null),
assert(inactiveThumbImage != null || onInactiveThumbImageError == null);
Expand Down Expand Up @@ -161,6 +162,7 @@ class Switch extends StatelessWidget {
this.focusNode,
this.onFocusChange,
this.autofocus = false,
this.applyCupertinoTheme,
}) : assert(autofocus != null),
assert(activeThumbImage != null || onActiveThumbImageError == null),
assert(inactiveThumbImage != null || onInactiveThumbImageError == null),
Expand Down Expand Up @@ -381,6 +383,9 @@ class Switch extends StatelessWidget {

final _SwitchType _switchType;

/// {@macro flutter.cupertino.CupertinoSwitch.applyTheme}
final bool? applyCupertinoTheme;

/// {@macro flutter.cupertino.CupertinoSwitch.dragStartBehavior}
final DragStartBehavior dragStartBehavior;

Expand Down Expand Up @@ -495,6 +500,7 @@ class Switch extends StatelessWidget {
onChanged: onChanged,
activeColor: activeColor,
trackColor: inactiveTrackColor,
applyTheme: applyCupertinoTheme,
),
),
);
Expand Down

0 comments on commit 1e696d3

Please sign in to comment.