This reverts commit 80f80ab08c0dad8551c91087cd1017aba094d22c.
This commit is contained in:
parent
53de41cac6
commit
04a26778c5
@ -2,9 +2,10 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// This program generates a Dart "localizations" Map definition that combines
|
||||
// the contents of the arb files. The map can be used to lookup a localized
|
||||
// string: `localizations[localeString][resourceId]`.
|
||||
// This program generates a getTranslation() function that looks up the
|
||||
// translations contained by the arb files. The returned value is an
|
||||
// instance of GlobalMaterialLocalizations that corresponds to a single
|
||||
// locale.
|
||||
//
|
||||
// The *.arb files are in packages/flutter_localizations/lib/src/l10n.
|
||||
//
|
||||
@ -273,6 +274,8 @@ String generateType(Map<String, dynamic> attributes) {
|
||||
switch (attributes['x-flutter-type']) {
|
||||
case 'icuShortTimePattern':
|
||||
return 'TimeOfDayFormat';
|
||||
case 'scriptCategory':
|
||||
return 'ScriptCategory';
|
||||
}
|
||||
}
|
||||
return 'String';
|
||||
@ -308,6 +311,12 @@ const Map<String, String> _icuTimeOfDayToEnum = <String, String>{
|
||||
'ah:mm': 'TimeOfDayFormat.a_space_h_colon_mm',
|
||||
};
|
||||
|
||||
const Map<String, String> _scriptCategoryToEnum = <String, String>{
|
||||
'English-like': 'ScriptCategory.englishLike',
|
||||
'dense': 'ScriptCategory.dense',
|
||||
'tall': 'ScriptCategory.tall',
|
||||
};
|
||||
|
||||
/// Returns the literal that describes the value returned by getters
|
||||
/// with the given attributes.
|
||||
///
|
||||
@ -330,6 +339,15 @@ String generateValue(String value, Map<String, dynamic> attributes) {
|
||||
);
|
||||
}
|
||||
return _icuTimeOfDayToEnum[value];
|
||||
case 'scriptCategory':
|
||||
if (!_scriptCategoryToEnum.containsKey(value)) {
|
||||
throw Exception(
|
||||
'"$value" is not one of the scriptCategory values supported '
|
||||
'by the material library. Here is the list of supported '
|
||||
'values:\n ' + _scriptCategoryToEnum.keys.join('\n ')
|
||||
);
|
||||
}
|
||||
return _scriptCategoryToEnum[value];
|
||||
}
|
||||
}
|
||||
return generateString(value);
|
||||
|
@ -57,7 +57,7 @@ class TypographyDemo extends StatelessWidget {
|
||||
TextStyleItem(name: 'Body 2', style: textTheme.body2, text: 'Medium 14sp'),
|
||||
TextStyleItem(name: 'Body 1', style: textTheme.body1, text: 'Regular 14sp'),
|
||||
TextStyleItem(name: 'Caption', style: textTheme.caption, text: 'Regular 12sp'),
|
||||
TextStyleItem(name: 'Button', style: textTheme.button, text: 'MEDIUM (ALL CAPS) 14sp')
|
||||
TextStyleItem(name: 'Button', style: textTheme.button, text: 'MEDIUM (ALL CAPS) 14sp'),
|
||||
];
|
||||
|
||||
if (MediaQuery.of(context).size.width > 500.0) {
|
||||
|
@ -24,17 +24,23 @@ TextTheme _buildTextTheme(TextTheme base) {
|
||||
|
||||
ThemeData _buildDarkTheme() {
|
||||
const Color primaryColor = Color(0xFF0175c2);
|
||||
const Color secondaryColor = Color(0xFF13B9FD);
|
||||
final ThemeData base = ThemeData.dark();
|
||||
final ColorScheme colorScheme = const ColorScheme.dark().copyWith(
|
||||
primary: primaryColor,
|
||||
secondary: secondaryColor,
|
||||
);
|
||||
return base.copyWith(
|
||||
primaryColor: primaryColor,
|
||||
buttonColor: primaryColor,
|
||||
indicatorColor: Colors.white,
|
||||
accentColor: const Color(0xFF13B9FD),
|
||||
accentColor: secondaryColor,
|
||||
canvasColor: const Color(0xFF202124),
|
||||
scaffoldBackgroundColor: const Color(0xFF202124),
|
||||
backgroundColor: const Color(0xFF202124),
|
||||
errorColor: const Color(0xFFB00020),
|
||||
buttonTheme: const ButtonThemeData(
|
||||
buttonTheme: ButtonThemeData(
|
||||
colorScheme: colorScheme,
|
||||
textTheme: ButtonTextTheme.primary,
|
||||
),
|
||||
textTheme: _buildTextTheme(base.textTheme),
|
||||
@ -45,19 +51,26 @@ ThemeData _buildDarkTheme() {
|
||||
|
||||
ThemeData _buildLightTheme() {
|
||||
const Color primaryColor = Color(0xFF0175c2);
|
||||
const Color secondaryColor = Color(0xFF13B9FD);
|
||||
final ColorScheme colorScheme = const ColorScheme.light().copyWith(
|
||||
primary: primaryColor,
|
||||
secondary: secondaryColor,
|
||||
);
|
||||
final ThemeData base = ThemeData.light();
|
||||
return base.copyWith(
|
||||
colorScheme: colorScheme,
|
||||
primaryColor: primaryColor,
|
||||
buttonColor: primaryColor,
|
||||
indicatorColor: Colors.white,
|
||||
splashColor: Colors.white24,
|
||||
splashFactory: InkRipple.splashFactory,
|
||||
accentColor: const Color(0xFF13B9FD),
|
||||
accentColor: secondaryColor,
|
||||
canvasColor: Colors.white,
|
||||
scaffoldBackgroundColor: Colors.white,
|
||||
backgroundColor: Colors.white,
|
||||
errorColor: const Color(0xFFB00020),
|
||||
buttonTheme: const ButtonThemeData(
|
||||
buttonTheme: ButtonThemeData(
|
||||
colorScheme: colorScheme,
|
||||
textTheme: ButtonTextTheme.primary,
|
||||
),
|
||||
textTheme: _buildTextTheme(base.textTheme),
|
||||
|
@ -649,12 +649,14 @@ void main() {
|
||||
handle.dispose();
|
||||
});
|
||||
|
||||
testWidgets('overscroll_demo $themeName', (WidgetTester tester) async {
|
||||
final SemanticsHandle handle = tester.ensureSemantics();
|
||||
await tester.pumpWidget(MaterialApp(theme: theme, home: const OverscrollDemo()));
|
||||
await expectLater(tester, meetsGuideline(textContrastGuideline));
|
||||
handle.dispose();
|
||||
});
|
||||
testWidgets('overscroll_demo', (WidgetTester tester) async {
|
||||
final AutomatedTestWidgetsFlutterBinding binding = tester.binding;
|
||||
binding.addTime(const Duration(seconds: 3));
|
||||
final SemanticsHandle handle = tester.ensureSemantics();
|
||||
await tester.pumpWidget(const MaterialApp(home: OverscrollDemo()));
|
||||
await expectLater(tester, meetsGuideline(textContrastGuideline));
|
||||
handle.dispose();
|
||||
});
|
||||
|
||||
testWidgets('page_selector_demo $themeName', (WidgetTester tester) async {
|
||||
final AutomatedTestWidgetsFlutterBinding binding = tester.binding;
|
||||
|
@ -32,6 +32,7 @@ export 'src/material/checkbox_list_tile.dart';
|
||||
export 'src/material/chip.dart';
|
||||
export 'src/material/chip_theme.dart';
|
||||
export 'src/material/circle_avatar.dart';
|
||||
export 'src/material/color_scheme.dart';
|
||||
export 'src/material/colors.dart';
|
||||
export 'src/material/constants.dart';
|
||||
export 'src/material/data_table.dart';
|
||||
@ -65,6 +66,7 @@ export 'src/material/input_border.dart';
|
||||
export 'src/material/input_decorator.dart';
|
||||
export 'src/material/list_tile.dart';
|
||||
export 'src/material/material.dart';
|
||||
export 'src/material/material_button.dart';
|
||||
export 'src/material/material_localizations.dart';
|
||||
export 'src/material/mergeable_material.dart';
|
||||
export 'src/material/outline_button.dart';
|
||||
@ -95,6 +97,7 @@ export 'src/material/tabs.dart';
|
||||
export 'src/material/text_field.dart';
|
||||
export 'src/material/text_form_field.dart';
|
||||
export 'src/material/text_selection.dart';
|
||||
export 'src/material/text_theme.dart';
|
||||
export 'src/material/theme.dart';
|
||||
export 'src/material/theme_data.dart';
|
||||
export 'src/material/time.dart';
|
||||
|
@ -19,8 +19,8 @@ import 'material.dart';
|
||||
import 'material_localizations.dart';
|
||||
import 'scaffold.dart';
|
||||
import 'tabs.dart';
|
||||
import 'text_theme.dart';
|
||||
import 'theme.dart';
|
||||
import 'typography.dart';
|
||||
|
||||
// Examples can assume:
|
||||
// void _airDress() { }
|
||||
|
@ -14,8 +14,8 @@ import 'debug.dart';
|
||||
import 'ink_well.dart';
|
||||
import 'material.dart';
|
||||
import 'material_localizations.dart';
|
||||
import 'text_theme.dart';
|
||||
import 'theme.dart';
|
||||
import 'typography.dart';
|
||||
|
||||
const double _kActiveFontSize = 14.0;
|
||||
const double _kInactiveFontSize = 12.0;
|
||||
|
@ -9,7 +9,6 @@ import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'button_theme.dart';
|
||||
import 'colors.dart';
|
||||
import 'constants.dart';
|
||||
import 'ink_well.dart';
|
||||
import 'material.dart';
|
||||
@ -225,238 +224,6 @@ class _RawMaterialButtonState extends State<RawMaterialButton> {
|
||||
}
|
||||
}
|
||||
|
||||
/// A utility class for building Material buttons that depend on the
|
||||
/// ambient [ButtonTheme] and [Theme].
|
||||
///
|
||||
/// The button's size will expand to fit the child widget, if necessary.
|
||||
///
|
||||
/// MaterialButtons whose [onPressed] handler is null will be disabled. To have
|
||||
/// an enabled button, make sure to pass a non-null value for onPressed.
|
||||
///
|
||||
/// Rather than using this class directly, consider using [FlatButton] or
|
||||
/// [RaisedButton], which configure this class with appropriate defaults that
|
||||
/// match the material design specification.
|
||||
///
|
||||
/// To create a button directly, without inheriting theme defaults, use
|
||||
/// [RawMaterialButton].
|
||||
///
|
||||
/// If you want an ink-splash effect for taps, but don't want to use a button,
|
||||
/// consider using [InkWell] directly.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [IconButton], to create buttons that contain icons rather than text.
|
||||
class MaterialButton extends StatelessWidget {
|
||||
/// Creates a material button.
|
||||
///
|
||||
/// Rather than creating a material button directly, consider using
|
||||
/// [FlatButton] or [RaisedButton]. To create a custom Material button
|
||||
/// consider using [RawMaterialButton].
|
||||
///
|
||||
/// The [clipBehavior] argument must not be null.
|
||||
const MaterialButton({
|
||||
Key key,
|
||||
this.colorBrightness,
|
||||
this.textTheme,
|
||||
this.textColor,
|
||||
this.color,
|
||||
this.highlightColor,
|
||||
this.splashColor,
|
||||
this.elevation,
|
||||
this.highlightElevation,
|
||||
this.minWidth,
|
||||
this.height,
|
||||
this.padding,
|
||||
this.materialTapTargetSize,
|
||||
this.clipBehavior = Clip.none,
|
||||
@required this.onPressed,
|
||||
this.child
|
||||
}) : assert(clipBehavior != null), super(key: key);
|
||||
|
||||
/// The theme brightness to use for this button.
|
||||
///
|
||||
/// Defaults to the brightness from [ThemeData.brightness].
|
||||
final Brightness colorBrightness;
|
||||
|
||||
/// Defines the button's base colors, and the defaults for the button's minimum
|
||||
/// size, internal padding, and shape.
|
||||
final ButtonTextTheme textTheme;
|
||||
|
||||
/// The color to use for this button's text.
|
||||
final Color textColor;
|
||||
|
||||
/// The button's fill color, displayed by its [Material], while the button
|
||||
/// is in its default (unpressed, enabled) state.
|
||||
///
|
||||
/// Defaults to null, meaning that the color is automatically derived from the [Theme].
|
||||
///
|
||||
/// Typically, a material design color will be used, as follows:
|
||||
///
|
||||
/// ```dart
|
||||
/// MaterialButton(
|
||||
/// color: Colors.blue[500],
|
||||
/// onPressed: _handleTap,
|
||||
/// child: Text('DEMO'),
|
||||
/// ),
|
||||
/// ```
|
||||
final Color color;
|
||||
|
||||
/// The primary color of the button when the button is in the down (pressed)
|
||||
/// state.
|
||||
///
|
||||
/// The splash is represented as a circular overlay that appears above the
|
||||
/// [highlightColor] overlay. The splash overlay has a center point that
|
||||
/// matches the hit point of the user touch event. The splash overlay will
|
||||
/// expand to fill the button area if the touch is held for long enough time.
|
||||
/// If the splash color has transparency then the highlight and button color
|
||||
/// will show through.
|
||||
///
|
||||
/// Defaults to the Theme's splash color, [ThemeData.splashColor].
|
||||
final Color splashColor;
|
||||
|
||||
/// The secondary color of the button when the button is in the down (pressed)
|
||||
/// state.
|
||||
///
|
||||
/// The highlight color is represented as a solid color that is overlaid over
|
||||
/// the button color (if any). If the highlight color has transparency, the
|
||||
/// button color will show through. The highlight fades in quickly as the
|
||||
/// button is held down.
|
||||
///
|
||||
/// Defaults to the Theme's highlight color, [ThemeData.highlightColor].
|
||||
final Color highlightColor;
|
||||
|
||||
/// The z-coordinate at which to place this button. This controls the size of
|
||||
/// the shadow below the button.
|
||||
///
|
||||
/// Defaults to 0.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [FlatButton], a material button specialized for the case where the
|
||||
/// elevation is zero.
|
||||
/// * [RaisedButton], a material button specialized for the case where the
|
||||
/// elevation is non-zero.
|
||||
final double elevation;
|
||||
|
||||
/// The z-coordinate at which to place this button when highlighted. This
|
||||
/// controls the size of the shadow below the button.
|
||||
///
|
||||
/// Defaults to 0.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [elevation], the default elevation.
|
||||
final double highlightElevation;
|
||||
|
||||
/// The smallest horizontal extent that the button will occupy.
|
||||
///
|
||||
/// Defaults to the value from the current [ButtonTheme].
|
||||
final double minWidth;
|
||||
|
||||
/// The vertical extent of the button.
|
||||
///
|
||||
/// Defaults to the value from the current [ButtonTheme].
|
||||
final double height;
|
||||
|
||||
/// The internal padding for the button's [child].
|
||||
///
|
||||
/// Defaults to the value from the current [ButtonTheme],
|
||||
/// [ButtonThemeData.padding].
|
||||
final EdgeInsetsGeometry padding;
|
||||
|
||||
/// The callback that is called when the button is tapped or otherwise activated.
|
||||
///
|
||||
/// If this is set to null, the button will be disabled.
|
||||
final VoidCallback onPressed;
|
||||
|
||||
/// The widget below this widget in the tree.
|
||||
///
|
||||
/// {@macro flutter.widgets.child}
|
||||
final Widget child;
|
||||
|
||||
/// Configures the minimum size of the tap target.
|
||||
///
|
||||
/// Defaults to [ThemeData.materialTapTargetSize].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [MaterialTapTargetSize], for a description of how this affects tap targets.
|
||||
final MaterialTapTargetSize materialTapTargetSize;
|
||||
|
||||
/// {@macro flutter.widgets.Clip}
|
||||
final Clip clipBehavior;
|
||||
|
||||
/// Whether the button is enabled or disabled. Buttons are disabled by default. To
|
||||
/// enable a button, set its [onPressed] property to a non-null value.
|
||||
bool get enabled => onPressed != null;
|
||||
|
||||
Brightness _getBrightness(ThemeData theme) {
|
||||
return colorBrightness ?? theme.brightness;
|
||||
}
|
||||
|
||||
ButtonTextTheme _getTextTheme(ButtonThemeData buttonTheme) {
|
||||
return textTheme ?? buttonTheme.textTheme;
|
||||
}
|
||||
|
||||
Color _getTextColor(ThemeData theme, ButtonThemeData buttonTheme, Color fillColor) {
|
||||
if (textColor != null)
|
||||
return textColor;
|
||||
|
||||
final bool themeIsDark = _getBrightness(theme) == Brightness.dark;
|
||||
final bool fillIsDark = fillColor != null
|
||||
? ThemeData.estimateBrightnessForColor(fillColor) == Brightness.dark
|
||||
: themeIsDark;
|
||||
|
||||
switch (_getTextTheme(buttonTheme)) {
|
||||
case ButtonTextTheme.normal:
|
||||
return enabled
|
||||
? (themeIsDark ? Colors.white : Colors.black87)
|
||||
: theme.disabledColor;
|
||||
case ButtonTextTheme.accent:
|
||||
return enabled
|
||||
? theme.accentColor
|
||||
: theme.disabledColor;
|
||||
case ButtonTextTheme.primary:
|
||||
return enabled
|
||||
? (fillIsDark ? Colors.white : Colors.black)
|
||||
: (themeIsDark ? Colors.white30 : Colors.black38);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final ThemeData theme = Theme.of(context);
|
||||
final ButtonThemeData buttonTheme = ButtonTheme.of(context);
|
||||
final Color textColor = _getTextColor(theme, buttonTheme, color);
|
||||
|
||||
return RawMaterialButton(
|
||||
onPressed: onPressed,
|
||||
fillColor: color,
|
||||
textStyle: theme.textTheme.button.copyWith(color: textColor),
|
||||
highlightColor: highlightColor ?? theme.highlightColor,
|
||||
splashColor: splashColor ?? theme.splashColor,
|
||||
elevation: elevation ?? 2.0,
|
||||
highlightElevation: highlightElevation ?? 8.0,
|
||||
padding: padding ?? buttonTheme.padding,
|
||||
constraints: buttonTheme.constraints.copyWith(
|
||||
minWidth: minWidth,
|
||||
minHeight: height,
|
||||
),
|
||||
shape: buttonTheme.shape,
|
||||
child: child,
|
||||
materialTapTargetSize: materialTapTargetSize ?? theme.materialTapTargetSize,
|
||||
clipBehavior: clipBehavior,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
super.debugFillProperties(properties);
|
||||
properties.add(FlagProperty('enabled', value: enabled, ifFalse: 'disabled'));
|
||||
}
|
||||
}
|
||||
|
||||
/// A widget to pad the area around a [MaterialButton]'s inner [Material].
|
||||
///
|
||||
/// Redirect taps that occur in the padded area around the child to the center
|
||||
|
@ -5,7 +5,15 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'color_scheme.dart';
|
||||
import 'colors.dart';
|
||||
import 'constants.dart';
|
||||
import 'flat_button.dart';
|
||||
import 'material_button.dart';
|
||||
import 'outline_button.dart';
|
||||
import 'raised_button.dart';
|
||||
import 'theme.dart';
|
||||
import 'theme_data.dart' show MaterialTapTargetSize;
|
||||
|
||||
/// Used with [ButtonTheme] and [ButtonThemeData] to define a button's base
|
||||
/// colors, and the defaults for the button's minimum size, internal padding,
|
||||
@ -13,8 +21,8 @@ import 'theme.dart';
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [RaisedButton], which styles itself based on the ambient [ButtonTheme].
|
||||
/// * [FlatButton], which styles itself based on the ambient [ButtonTheme].
|
||||
/// * [RaisedButton], [FlatButton], [OutlineButton], which are configured
|
||||
/// based on the ambient [ButtonTheme].
|
||||
enum ButtonTextTheme {
|
||||
/// Button text is black or white depending on [ThemeData.brightness].
|
||||
normal,
|
||||
@ -46,30 +54,19 @@ enum ButtonBarLayoutBehavior {
|
||||
/// can be overridden with [ButtonTheme].
|
||||
///
|
||||
/// The actual appearance of buttons depends on the button theme, the
|
||||
/// button's enabled state, its elevation (if any) and the overall Material
|
||||
/// theme.
|
||||
/// button's enabled state, its elevation (if any), and the overall [Theme].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [FlatButton] and [RaisedButton], which are styled based on the
|
||||
/// ambient button theme.
|
||||
/// * [ThemeData.textTheme], `button` is the default text style for button labels.
|
||||
/// * [ThemeData.buttonColor], the fill color for [RaisedButton]s unless the
|
||||
/// button theme's text theme is [ButtonTextTheme.primary].
|
||||
/// * [ThemeData.primaryColor], the fill or text color if a button theme's text
|
||||
/// theme is [ButtonTextTheme.primary].
|
||||
/// * [ThemeData.accentColor], the text color for buttons when button theme's
|
||||
/// text theme is [ButtonTextTheme.accent].
|
||||
/// * [ThemeData.disabled], the default text color for disabled buttons.
|
||||
/// * [ThemeData.brightness], used to select contrasting text and fill colors.
|
||||
/// * [ThemeData.highlightColor], a button [InkWell]'s default highlight color.
|
||||
/// * [ThemeData.splashColor], a button [InkWell]'s default splash color.
|
||||
/// * [FlatButton] [RaisedButton], and [OutlineButton], which are styled
|
||||
/// based on the ambient button theme.
|
||||
/// * [RawMaterialButton], which can be used to configure a button that doesn't
|
||||
/// depend on any inherited themes.
|
||||
class ButtonTheme extends InheritedWidget {
|
||||
/// Creates a button theme.
|
||||
///
|
||||
/// The [textTheme], [minWidth], and [height] arguments must not be null.
|
||||
/// The [textTheme], [minWidth], [height], and [colorScheme] arguments
|
||||
/// must not be null.
|
||||
ButtonTheme({
|
||||
Key key,
|
||||
ButtonTextTheme textTheme = ButtonTextTheme.normal,
|
||||
@ -79,6 +76,12 @@ class ButtonTheme extends InheritedWidget {
|
||||
EdgeInsetsGeometry padding,
|
||||
ShapeBorder shape,
|
||||
bool alignedDropdown = false,
|
||||
Color buttonColor,
|
||||
Color disabledColor,
|
||||
Color highlightColor,
|
||||
Color splashColor,
|
||||
ColorScheme colorScheme,
|
||||
MaterialTapTargetSize materialTapTargetSize,
|
||||
Widget child,
|
||||
}) : assert(textTheme != null),
|
||||
assert(minWidth != null && minWidth >= 0.0),
|
||||
@ -93,6 +96,12 @@ class ButtonTheme extends InheritedWidget {
|
||||
shape: shape,
|
||||
alignedDropdown: alignedDropdown,
|
||||
layoutBehavior: layoutBehavior,
|
||||
buttonColor: buttonColor,
|
||||
disabledColor: disabledColor,
|
||||
highlightColor: highlightColor,
|
||||
splashColor: splashColor,
|
||||
colorScheme: colorScheme,
|
||||
materialTapTargetSize: materialTapTargetSize,
|
||||
),
|
||||
super(key: key, child: child);
|
||||
|
||||
@ -128,6 +137,11 @@ class ButtonTheme extends InheritedWidget {
|
||||
EdgeInsetsGeometry padding = const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
ShapeBorder shape,
|
||||
bool alignedDropdown = false,
|
||||
Color buttonColor,
|
||||
Color disabledColor,
|
||||
Color highlightColor,
|
||||
Color splashColor,
|
||||
ColorScheme colorScheme,
|
||||
Widget child,
|
||||
ButtonBarLayoutBehavior layoutBehavior = ButtonBarLayoutBehavior.padded,
|
||||
}) : assert(textTheme != null),
|
||||
@ -142,6 +156,11 @@ class ButtonTheme extends InheritedWidget {
|
||||
shape: shape,
|
||||
alignedDropdown: alignedDropdown,
|
||||
layoutBehavior: layoutBehavior,
|
||||
buttonColor: buttonColor,
|
||||
disabledColor: disabledColor,
|
||||
highlightColor: highlightColor,
|
||||
splashColor: splashColor,
|
||||
colorScheme: colorScheme,
|
||||
),
|
||||
super(key: key, child: child);
|
||||
|
||||
@ -156,8 +175,19 @@ class ButtonTheme extends InheritedWidget {
|
||||
/// ButtonThemeData theme = ButtonTheme.of(context);
|
||||
/// ```
|
||||
static ButtonThemeData of(BuildContext context) {
|
||||
final ButtonTheme result = context.inheritFromWidgetOfExactType(ButtonTheme);
|
||||
return result?.data ?? Theme.of(context).buttonTheme;
|
||||
final ButtonTheme inheritedButtonTheme = context.inheritFromWidgetOfExactType(ButtonTheme);
|
||||
ButtonThemeData buttonTheme = inheritedButtonTheme?.data;
|
||||
if (buttonTheme?.colorScheme == null) { // if buttonTheme or buttonTheme.colorScheme is null
|
||||
final ThemeData theme = Theme.of(context);
|
||||
buttonTheme ??= theme.buttonTheme;
|
||||
if (buttonTheme.colorScheme == null) {
|
||||
buttonTheme = buttonTheme.copyWith(
|
||||
colorScheme: theme.buttonTheme.colorScheme ?? theme.colorScheme,
|
||||
);
|
||||
assert(buttonTheme.colorScheme != null);
|
||||
}
|
||||
}
|
||||
return buttonTheme;
|
||||
}
|
||||
|
||||
@override
|
||||
@ -173,7 +203,13 @@ class ButtonThemeData extends Diagnosticable {
|
||||
/// Create a button theme object that can be used with [ButtonTheme]
|
||||
/// or [ThemeData].
|
||||
///
|
||||
/// The [textTheme], [minWidth], and [height] parameters must not be null.
|
||||
/// The [textTheme], [minWidth], [height], [alignedDropDown], and
|
||||
/// [layoutBehavior] parameters must not be null. The [minWidth] and
|
||||
/// [height] parameters must greater than or equal to zero.
|
||||
///
|
||||
/// The ButtonTheme's methods that have a [MaterialButton] parameter and
|
||||
/// have a name with a `get` prefix are used by [RaisedButton],
|
||||
/// [OutlineButton], and [FlatButton] to configure a [RawMaterialButton].
|
||||
const ButtonThemeData({
|
||||
this.textTheme = ButtonTextTheme.normal,
|
||||
this.minWidth = 88.0,
|
||||
@ -182,13 +218,24 @@ class ButtonThemeData extends Diagnosticable {
|
||||
ShapeBorder shape,
|
||||
this.layoutBehavior = ButtonBarLayoutBehavior.padded,
|
||||
this.alignedDropdown = false,
|
||||
Color buttonColor,
|
||||
Color disabledColor,
|
||||
Color highlightColor,
|
||||
Color splashColor,
|
||||
this.colorScheme,
|
||||
MaterialTapTargetSize materialTapTargetSize,
|
||||
}) : assert(textTheme != null),
|
||||
assert(minWidth != null && minWidth >= 0.0),
|
||||
assert(height != null && height >= 0.0),
|
||||
assert(alignedDropdown != null),
|
||||
assert(layoutBehavior != null),
|
||||
_buttonColor = buttonColor,
|
||||
_disabledColor = disabledColor,
|
||||
_highlightColor = highlightColor,
|
||||
_splashColor = splashColor,
|
||||
_padding = padding,
|
||||
_shape = shape;
|
||||
_shape = shape,
|
||||
_materialTapTargetSize = materialTapTargetSize;
|
||||
|
||||
/// The minimum width for buttons.
|
||||
///
|
||||
@ -205,10 +252,13 @@ class ButtonThemeData extends Diagnosticable {
|
||||
|
||||
/// Defines a button's base colors, and the defaults for the button's minimum
|
||||
/// size, internal padding, and shape.
|
||||
///
|
||||
/// Despite the name, this property is not a [TextTheme], its value is not a
|
||||
/// collection of [TextStyle]s.
|
||||
final ButtonTextTheme textTheme;
|
||||
|
||||
/// Defines whether a button bar should size itself with a minimum size
|
||||
/// constraint or padding.
|
||||
/// Defines whether a [ButtonBar] should size itself with a minimum size
|
||||
/// constraint or with padding.
|
||||
///
|
||||
/// Defaults to [ButtonBarLayoutBehavior.padded].
|
||||
final ButtonBarLayoutBehavior layoutBehavior;
|
||||
@ -232,16 +282,22 @@ class ButtonThemeData extends Diagnosticable {
|
||||
///
|
||||
/// Defaults to 24.0 on the left and right if [textTheme] is
|
||||
/// [ButtonTextTheme.primary], 16.0 on the left and right otherwise.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [getPadding], which is used by [RaisedButton], [OutlineButton]
|
||||
/// and [FlatButton].
|
||||
EdgeInsetsGeometry get padding {
|
||||
if (_padding != null)
|
||||
return _padding;
|
||||
switch (textTheme) {
|
||||
switch (textTheme) {
|
||||
case ButtonTextTheme.normal:
|
||||
case ButtonTextTheme.accent:
|
||||
return const EdgeInsets.symmetric(horizontal: 16.0);
|
||||
case ButtonTextTheme.primary:
|
||||
return const EdgeInsets.symmetric(horizontal: 24.0);
|
||||
return const EdgeInsets.symmetric(horizontal: 24.0);
|
||||
}
|
||||
assert(false);
|
||||
return EdgeInsets.zero;
|
||||
}
|
||||
final EdgeInsetsGeometry _padding;
|
||||
@ -255,6 +311,11 @@ class ButtonThemeData extends Diagnosticable {
|
||||
/// Defaults to a rounded rectangle with circular corner radii of 4.0 if
|
||||
/// [textTheme] is [ButtonTextTheme.primary], a rounded rectangle with
|
||||
/// circular corner radii of 2.0 otherwise.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [getShape], which is used by [RaisedButton], [OutlineButton]
|
||||
/// and [FlatButton].
|
||||
ShapeBorder get shape {
|
||||
if (_shape != null)
|
||||
return _shape;
|
||||
@ -284,23 +345,417 @@ class ButtonThemeData extends Diagnosticable {
|
||||
/// This property only affects [DropdownButton] and its menu.
|
||||
final bool alignedDropdown;
|
||||
|
||||
/// The background fill color for [RaisedButton]s.
|
||||
///
|
||||
/// This property is null by default.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [getFillColor], which is used by [RaisedButton] to compute its
|
||||
/// background fill color.
|
||||
final Color _buttonColor;
|
||||
|
||||
/// The background fill color for disabled [RaisedButton]s.
|
||||
///
|
||||
/// This property is null by default.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [getDisabledFillColor], which is used by [RaisedButton] to compute its
|
||||
/// background fill color.
|
||||
final Color _disabledColor;
|
||||
|
||||
/// The color of the overlay that appears when a button is pressed.
|
||||
///
|
||||
/// This property is null by default.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [getHighlightColor], which is used by [RaisedButton], [OutlineButton]
|
||||
/// and [FlatButton].
|
||||
final Color _highlightColor;
|
||||
|
||||
/// The color of the ink "splash" overlay that appears when a button is tapped.
|
||||
///
|
||||
/// This property is null by default.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [getSplashColor], which is used by [RaisedButton], [OutlineButton]
|
||||
/// and [FlatButton].
|
||||
final Color _splashColor;
|
||||
|
||||
/// A set of thirteen colors that can be used to derive the button theme's
|
||||
/// colors.
|
||||
///
|
||||
/// This property was added much later than the theme's set of highly
|
||||
/// specific colors, like [ThemeData.buttonColor], [ThemeData.highlightColor],
|
||||
/// [ThemeData.splashColor] etc.
|
||||
///
|
||||
/// The colors for new button classes can be defined exclusively in terms
|
||||
/// of [colorScheme]. When it's possible, the existing buttons will
|
||||
/// (continue to) gradually migrate to it.
|
||||
final ColorScheme colorScheme;
|
||||
|
||||
// The minimum size of a button's tap target.
|
||||
//
|
||||
// This property is null by default.
|
||||
//
|
||||
// See also:
|
||||
//
|
||||
// * [getMaterialTargetTapSize], which is used by [RaisedButton],
|
||||
// [OutlineButton] and [FlatButton].
|
||||
final MaterialTapTargetSize _materialTapTargetSize;
|
||||
|
||||
/// The [button]'s overall brightness.
|
||||
///
|
||||
/// Returns the button's [MaterialButton.colorBrightness] if it is non-null,
|
||||
/// otherwise the color scheme's [ColorScheme.brightness] is returned.
|
||||
Brightness getBrightness(MaterialButton button) {
|
||||
return button.colorBrightness ?? colorScheme.brightness;
|
||||
}
|
||||
|
||||
/// Defines the [button]'s base colors, and the defaults for the button's
|
||||
/// minimum size, internal padding, and shape.
|
||||
///
|
||||
/// Despite the name, this property is not the [TextTheme] whose
|
||||
/// [TextTheme.button] is used as the button text's [TextStyle].
|
||||
ButtonTextTheme getTextTheme(MaterialButton button) {
|
||||
return button.textTheme ?? textTheme;
|
||||
}
|
||||
|
||||
Color _getDisabledColor(MaterialButton button) {
|
||||
return getBrightness(button) == Brightness.dark
|
||||
? colorScheme.onSurface.withOpacity(0.30) // default == Colors.white30
|
||||
: colorScheme.onSurface.withOpacity(0.38); // default == Colors.black38;
|
||||
}
|
||||
|
||||
/// The foreground color of the [button]'s text and icon when
|
||||
/// [MaterialButton.onPressed] is null (when MaterialButton.enabled is false).
|
||||
///
|
||||
/// Returns the button's [MaterialButton.disabledColor] if it is non-null.
|
||||
/// Otherwise the color scheme's [ColorScheme.onSurface] color is returned
|
||||
/// with its opacity set to 0.30 if [getBrightness] is dark, 0.38 otherwise.
|
||||
Color getDisabledTextColor(MaterialButton button) {
|
||||
if (button.disabledTextColor != null)
|
||||
return button.disabledTextColor;
|
||||
return _getDisabledColor(button);
|
||||
}
|
||||
|
||||
/// The [button]'s background color when [MaterialButton.onPressed] is null
|
||||
/// (when MaterialButton.enabled is false).
|
||||
///
|
||||
/// Returns the button's [MaterialButton.disabledColor] if it is non-null.
|
||||
///
|
||||
/// Otherwise the the value of the `disabledColor` constructor parameter
|
||||
/// is returned, if it is non-null.
|
||||
///
|
||||
/// Otherwise the color scheme's [ColorScheme.onSurface] color is returned
|
||||
/// with its opacity set to 0.3 if [getBrightness] is dark, 0.38 otherwise.
|
||||
Color getDisabledFillColor(MaterialButton button) {
|
||||
if (button.disabledColor != null)
|
||||
return button.disabledColor;
|
||||
if (_disabledColor != null)
|
||||
return _disabledColor;
|
||||
return _getDisabledColor(button);
|
||||
}
|
||||
|
||||
/// The button's background fill color or null for buttons that don't have
|
||||
/// a background color.
|
||||
///
|
||||
/// Returns [MaterialButton.color] if it is non-null and the button
|
||||
/// is enabled.
|
||||
///
|
||||
/// Otherwise, returns [MaterialButton.disabledColor] if it is non-null and
|
||||
/// the button is disabled.
|
||||
///
|
||||
/// Otherwise, if button is a [FlatButton] or an [OutlineButton] then null is
|
||||
/// returned.
|
||||
///
|
||||
/// Otherwise, if button is a [RaisedButton], returns the `buttonColor`
|
||||
/// constructor parameter if it was non-null and the button is enabled.
|
||||
///
|
||||
/// Otherwise the fill color depends on the value of [getTextTheme].
|
||||
///
|
||||
/// * [ButtonTextTheme.normal] or [ButtonTextTheme.accent], the
|
||||
/// color scheme's [ColorScheme.primary] color if the [button] is enabled
|
||||
/// the value of [getDisabledFillColor] otherwise.
|
||||
/// * [ButtonTextTheme.primary], if the [button] is enabled then the value
|
||||
/// of the `buttonColor` constructor parameter if it is non-null,
|
||||
/// otherwise the color scheme's ColorScheme.primary color. If the button
|
||||
/// is not enabled then the colorScheme's [ColorScheme.onSurface] color
|
||||
/// with opacity 0.12.
|
||||
Color getFillColor(MaterialButton button) {
|
||||
final Color fillColor = button.enabled ? button.color : button.disabledColor;
|
||||
if (fillColor != null)
|
||||
return fillColor;
|
||||
|
||||
if (button is FlatButton || button is OutlineButton)
|
||||
return null;
|
||||
|
||||
if (button.enabled && button is RaisedButton && _buttonColor != null)
|
||||
return _buttonColor;
|
||||
|
||||
switch (getTextTheme(button)) {
|
||||
case ButtonTextTheme.normal:
|
||||
case ButtonTextTheme.accent:
|
||||
return button.enabled ? colorScheme.primary : getDisabledFillColor(button);
|
||||
case ButtonTextTheme.primary:
|
||||
return button.enabled
|
||||
? _buttonColor ?? colorScheme.primary
|
||||
: colorScheme.onSurface.withOpacity(0.12);
|
||||
}
|
||||
|
||||
assert(false);
|
||||
return null;
|
||||
}
|
||||
|
||||
/// The foreground color of the [button]'s text and icon.
|
||||
///
|
||||
/// If [button] is not [MaterialButton.enabled], the value of
|
||||
/// [getDisabledTextColor] is returned. If the button is enabled and
|
||||
/// [buttonTextColor] is non-null, then [buttonTextColor] is returned.
|
||||
///
|
||||
/// Otherwise the text color depends on the value of [getTextTheme]
|
||||
/// and [getBrightness].
|
||||
///
|
||||
/// * [ButtonTextTheme.normal], [Colors.white] if [getBrightness] is dark,
|
||||
/// otherwise [Colors.black87].
|
||||
/// * ButtonTextTheme.accent], [colorScheme.secondary].
|
||||
/// * [ButtonTextTheme.primary], if [getFillColor] is dark then [Colors.white],
|
||||
/// otherwise if [button] is a [FlatButton] or an [OutlineButton] then
|
||||
/// [colorScheme.primary], otherwise [Colors.black].
|
||||
Color getTextColor(MaterialButton button) {
|
||||
if (!button.enabled)
|
||||
return getDisabledTextColor(button);
|
||||
|
||||
if (button.textColor != null)
|
||||
return button.textColor;
|
||||
|
||||
switch (getTextTheme(button)) {
|
||||
case ButtonTextTheme.normal:
|
||||
return getBrightness(button) == Brightness.dark ? Colors.white : Colors.black87;
|
||||
|
||||
case ButtonTextTheme.accent:
|
||||
return colorScheme.secondary;
|
||||
|
||||
case ButtonTextTheme.primary: {
|
||||
final Color fillColor = getFillColor(button);
|
||||
final bool fillIsDark = fillColor != null
|
||||
? ThemeData.estimateBrightnessForColor(fillColor) == Brightness.dark
|
||||
: getBrightness(button) == Brightness.dark;
|
||||
if (fillIsDark)
|
||||
return Colors.white;
|
||||
if (button is FlatButton || button is OutlineButton)
|
||||
return colorScheme.primary;
|
||||
return Colors.black;
|
||||
}
|
||||
}
|
||||
|
||||
assert(false);
|
||||
return null;
|
||||
}
|
||||
|
||||
/// The color of the ink "splash" overlay that appears when the (enabled)
|
||||
/// [button] is tapped.
|
||||
///
|
||||
/// Returns the button's [MaterialButton.splashColor] if it is non-null.
|
||||
///
|
||||
/// Otherwise, returns the value of the `splashColor` constructor parameter
|
||||
/// it is non-null and [button] is a [RaisedButton] or an [OutlineButton].
|
||||
///
|
||||
/// Otherwise, returns the value of the `splashColor` constructor parameter
|
||||
/// if it is non-null and [button] is a [FlatButton] and
|
||||
/// [getTextTheme] is not [ButtonTextTheme.primary]
|
||||
///
|
||||
/// Otherwise, returns [getTextColor] with an opacity of 0.12.
|
||||
Color getSplashColor(MaterialButton button) {
|
||||
if (button.splashColor != null)
|
||||
return button.splashColor;
|
||||
|
||||
if (_splashColor != null && (button is RaisedButton || button is OutlineButton))
|
||||
return _splashColor;
|
||||
|
||||
if (_splashColor != null && button is FlatButton) {
|
||||
switch (getTextTheme(button)) {
|
||||
case ButtonTextTheme.normal:
|
||||
case ButtonTextTheme.accent:
|
||||
return _splashColor;
|
||||
case ButtonTextTheme.primary:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return getTextColor(button).withOpacity(0.12);
|
||||
}
|
||||
|
||||
/// The color of the overlay that appears when the [button] is pressed.
|
||||
///
|
||||
/// Returns the button's [MaterialButton.highlightColor] if it is non-null.
|
||||
/// Otherwise the highlight color depends on [getTextTheme]:
|
||||
///
|
||||
/// * [ButtonTextTheme.normal], [ButtonTextTheme.accent]: returns the
|
||||
/// value of the `highlightColor` constructor parameter if it is non-null,
|
||||
/// otherwise the value of [getTextColor] with opacity 0.16.
|
||||
/// * [ButtonTextTheme.primary], returns [Colors.transparent].
|
||||
Color getHighlightColor(MaterialButton button) {
|
||||
if (button.highlightColor != null)
|
||||
return button.highlightColor;
|
||||
|
||||
switch (getTextTheme(button)) {
|
||||
case ButtonTextTheme.normal:
|
||||
case ButtonTextTheme.accent:
|
||||
return _highlightColor ?? getTextColor(button).withOpacity(0.16);
|
||||
case ButtonTextTheme.primary:
|
||||
return Colors.transparent;
|
||||
}
|
||||
|
||||
assert(false);
|
||||
return Colors.transparent;
|
||||
}
|
||||
|
||||
/// The [button]'s elevation when it is enabled and has not been pressed.
|
||||
///
|
||||
/// Returns the button's [MaterialButton.elevation] if it is non-null.
|
||||
///
|
||||
/// If button is a [FlatButton] then elevation is 0.0, otherwise it is 2.0.
|
||||
double getElevation(MaterialButton button) {
|
||||
if (button.elevation != null)
|
||||
return button.elevation;
|
||||
if (button is FlatButton)
|
||||
return 0.0;
|
||||
return 2.0;
|
||||
}
|
||||
|
||||
/// The [button]'s elevation when it is enabled and has been pressed.
|
||||
///
|
||||
/// Returns the button's [MaterialButton.highlightElevation] if it is non-null.
|
||||
///
|
||||
/// If button is a [FlatButton] then the highlight elevation is 0.0, if it's
|
||||
/// a [OutlineButton] then the highlight elevation is 2.0, otherise the
|
||||
/// highlight elevation is 8.0.
|
||||
double getHighlightElevation(MaterialButton button) {
|
||||
if (button.highlightElevation != null)
|
||||
return button.highlightElevation;
|
||||
if (button is FlatButton)
|
||||
return 0.0;
|
||||
if (button is OutlineButton)
|
||||
return 2.0;
|
||||
return 8.0;
|
||||
}
|
||||
|
||||
/// The [button]'s elevation when [MaterialButton.onPressed] is null (when
|
||||
/// MaterialButton.enabled is false).
|
||||
///
|
||||
/// Returns the button's [MaterialButton.elevation] if it is non-null.
|
||||
///
|
||||
/// Otheriwse the disabled elevation is 0.0.
|
||||
double getDisabledElevation(MaterialButton button) {
|
||||
if (button.disabledElevation != null)
|
||||
return button.disabledElevation;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
/// Padding for the [button]'s child (typically the button's label).
|
||||
///
|
||||
/// Returns the button's [MaterialButton.padding] if it is non-null.
|
||||
///
|
||||
/// If this is a button constructed with [RaisedButton.icon] or
|
||||
/// [FlatButton.icon] or [OutlineButton.icon] then the padding is:
|
||||
/// `EdgeInsetsDirectional.only(start: 12.0, end: 16.0)`.
|
||||
///
|
||||
/// Otherwise, returns [padding] if it is non-null.
|
||||
///
|
||||
/// Otherwise, returns horizontal padding of 24.0 on the left and right if
|
||||
/// [getTextTheme] is [ButtonTextTheme.primary], 16.0 on the left and right
|
||||
/// otherwise.
|
||||
EdgeInsetsGeometry getPadding(MaterialButton button) {
|
||||
if (button.padding != null)
|
||||
return button.padding;
|
||||
|
||||
if (button is MaterialButtonWithIconMixin)
|
||||
return const EdgeInsetsDirectional.only(start: 12.0, end: 16.0);
|
||||
|
||||
if (_padding != null)
|
||||
return _padding;
|
||||
|
||||
switch (getTextTheme(button)) {
|
||||
case ButtonTextTheme.normal:
|
||||
case ButtonTextTheme.accent:
|
||||
return const EdgeInsets.symmetric(horizontal: 16.0);
|
||||
case ButtonTextTheme.primary:
|
||||
return const EdgeInsets.symmetric(horizontal: 24.0);
|
||||
}
|
||||
assert(false);
|
||||
return EdgeInsets.zero;
|
||||
}
|
||||
|
||||
/// The shape of the [button]'s [Material].
|
||||
///
|
||||
/// Returns the button's [MaterialButton.shape] if it is non-null, otherwise
|
||||
/// [shape] is returned.
|
||||
ShapeBorder getShape(MaterialButton button) {
|
||||
return button.shape ?? shape;
|
||||
}
|
||||
|
||||
/// The duration of the [button]'s highlight animation.
|
||||
///
|
||||
/// Returns the button's [MaterialButton.animationDuration] it if is non-null,
|
||||
/// otherwise 200ms.
|
||||
Duration getAnimationDuration(MaterialButton button) {
|
||||
return button.animationDuration ?? kThemeChangeDuration;
|
||||
}
|
||||
|
||||
/// The [BoxConstraints] that the define the [button]'s size.
|
||||
///
|
||||
/// By default this method just returns [constraints]. Subclasses
|
||||
/// could override this method to return a value that was,
|
||||
/// for example, based on the button's type.
|
||||
BoxConstraints getConstraints(MaterialButton button) => constraints;
|
||||
|
||||
/// The minimum size of the [button]'s tap target.
|
||||
///
|
||||
/// Returns the button's [MaterialButton.tapTargetSize] if it is non-null.
|
||||
///
|
||||
/// Otherwise the value of the [materialTapTargetSize] constructor
|
||||
/// parameter is returned if that's non-null.
|
||||
///
|
||||
/// Otherwise [MaterialTapTargetSize.padded] is returned.
|
||||
MaterialTapTargetSize getMaterialTapTargetSize(MaterialButton button) {
|
||||
return button.materialTapTargetSize ?? _materialTapTargetSize ?? MaterialTapTargetSize.padded;
|
||||
}
|
||||
|
||||
/// Creates a copy of this button theme data object with the matching fields
|
||||
/// replaced with the non-null parameter values.
|
||||
ButtonThemeData copyWith({
|
||||
ButtonTextTheme textTheme,
|
||||
ButtonBarLayoutBehavior layoutBehavior,
|
||||
double minWidth,
|
||||
double height,
|
||||
EdgeInsetsGeometry padding,
|
||||
ShapeBorder shape,
|
||||
bool alignedDropdown,
|
||||
Color buttonColor,
|
||||
Color disabledColor,
|
||||
Color highlightColor,
|
||||
Color splashColor,
|
||||
ColorScheme colorScheme,
|
||||
MaterialTapTargetSize materialTapTargetSize,
|
||||
}) {
|
||||
return ButtonThemeData(
|
||||
textTheme: textTheme ?? this.textTheme,
|
||||
layoutBehavior: layoutBehavior ?? this.layoutBehavior,
|
||||
minWidth: minWidth ?? this.minWidth,
|
||||
height: height ?? this.height,
|
||||
padding: padding ?? this.padding,
|
||||
shape: shape ?? this.shape,
|
||||
alignedDropdown: alignedDropdown ?? this.alignedDropdown,
|
||||
buttonColor: buttonColor ?? _buttonColor,
|
||||
disabledColor: disabledColor ?? _disabledColor,
|
||||
highlightColor: highlightColor ?? _highlightColor,
|
||||
splashColor: splashColor ?? _splashColor,
|
||||
colorScheme: colorScheme ?? this.colorScheme,
|
||||
materialTapTargetSize: materialTapTargetSize ?? _materialTapTargetSize,
|
||||
);
|
||||
}
|
||||
|
||||
@ -314,7 +769,13 @@ class ButtonThemeData extends Diagnosticable {
|
||||
&& height == typedOther.height
|
||||
&& padding == typedOther.padding
|
||||
&& shape == typedOther.shape
|
||||
&& alignedDropdown == typedOther.alignedDropdown;
|
||||
&& alignedDropdown == typedOther.alignedDropdown
|
||||
&& _buttonColor == typedOther._buttonColor
|
||||
&& _disabledColor == typedOther._disabledColor
|
||||
&& _highlightColor == typedOther._highlightColor
|
||||
&& _splashColor == typedOther._splashColor
|
||||
&& colorScheme == typedOther.colorScheme
|
||||
&& _materialTapTargetSize == typedOther._materialTapTargetSize;
|
||||
}
|
||||
|
||||
@override
|
||||
@ -326,6 +787,12 @@ class ButtonThemeData extends Diagnosticable {
|
||||
padding,
|
||||
shape,
|
||||
alignedDropdown,
|
||||
_buttonColor,
|
||||
_disabledColor,
|
||||
_highlightColor,
|
||||
_splashColor,
|
||||
colorScheme,
|
||||
_materialTapTargetSize,
|
||||
);
|
||||
}
|
||||
|
||||
@ -343,5 +810,11 @@ class ButtonThemeData extends Diagnosticable {
|
||||
defaultValue: defaultTheme.alignedDropdown,
|
||||
ifTrue: 'dropdown width matches button',
|
||||
));
|
||||
properties.add(DiagnosticsProperty<Color>('buttonColor', _buttonColor, defaultValue: null));
|
||||
properties.add(DiagnosticsProperty<Color>('disabledColor', _disabledColor, defaultValue: null));
|
||||
properties.add(DiagnosticsProperty<Color>('highlightColor', _highlightColor, defaultValue: null));
|
||||
properties.add(DiagnosticsProperty<Color>('splashColor', _splashColor, defaultValue: null));
|
||||
properties.add(DiagnosticsProperty<ColorScheme>('colorScheme', colorScheme, defaultValue: defaultTheme.colorScheme));
|
||||
properties.add(DiagnosticsProperty<MaterialTapTargetSize>('materialTapTargetSize', _materialTapTargetSize, defaultValue: null));
|
||||
}
|
||||
}
|
||||
|
324
packages/flutter/lib/src/material/color_scheme.dart
Normal file
324
packages/flutter/lib/src/material/color_scheme.dart
Normal file
@ -0,0 +1,324 @@
|
||||
// Copyright 2018 The Chromium 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/foundation.dart';
|
||||
import 'package:flutter/services.dart' show Brightness;
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'colors.dart';
|
||||
import 'theme_data.dart';
|
||||
|
||||
/// A set of twelve colors based on the
|
||||
/// [Material spec](https://material.io/design/color/the-color-system.html)
|
||||
/// that can be used to configure the color properties of most components.
|
||||
///
|
||||
/// The [Theme] has a color scheme, [ThemeData.colorScheme], which is constructed
|
||||
/// with [ColorScheme.fromSwatch].
|
||||
@immutable
|
||||
class ColorScheme extends Diagnosticable {
|
||||
/// Create a ColorScheme instance.
|
||||
const ColorScheme({
|
||||
@required this.primary,
|
||||
@required this.primaryVariant,
|
||||
@required this.secondary,
|
||||
@required this.secondaryVariant,
|
||||
@required this.surface,
|
||||
@required this.background,
|
||||
@required this.error,
|
||||
@required this.onPrimary,
|
||||
@required this.onSecondary,
|
||||
@required this.onSurface,
|
||||
@required this.onBackground,
|
||||
@required this.onError,
|
||||
@required this.brightness,
|
||||
}) : assert(primary != null),
|
||||
assert(primaryVariant != null),
|
||||
assert(secondary != null),
|
||||
assert(secondaryVariant != null),
|
||||
assert(surface != null),
|
||||
assert(background != null),
|
||||
assert(error != null),
|
||||
assert(onPrimary != null),
|
||||
assert(onSecondary != null),
|
||||
assert(onSurface != null),
|
||||
assert(onBackground != null),
|
||||
assert(onError != null),
|
||||
assert(brightness != null);
|
||||
|
||||
/// Create a ColorScheme based on a purple primary color that matches the
|
||||
/// [baseline Material color scheme](https://material.io/design/color/the-color-system.html#color-theme-creation).
|
||||
const ColorScheme.light({
|
||||
this.primary = const Color(0xff6200ee),
|
||||
this.primaryVariant = const Color(0xff3700b3),
|
||||
this.secondary = const Color(0xff03dac6),
|
||||
this.secondaryVariant = const Color(0xff018786),
|
||||
this.surface = Colors.white,
|
||||
this.background = Colors.white,
|
||||
this.error = const Color(0xffb00020),
|
||||
this.onPrimary = Colors.white,
|
||||
this.onSecondary = Colors.black,
|
||||
this.onSurface = Colors.black,
|
||||
this.onBackground = Colors.black,
|
||||
this.onError = Colors.white,
|
||||
this.brightness = Brightness.light,
|
||||
}) : assert(primary != null),
|
||||
assert(primaryVariant != null),
|
||||
assert(secondary != null),
|
||||
assert(secondaryVariant != null),
|
||||
assert(surface != null),
|
||||
assert(background != null),
|
||||
assert(error != null),
|
||||
assert(onPrimary != null),
|
||||
assert(onSecondary != null),
|
||||
assert(onSurface != null),
|
||||
assert(onBackground != null),
|
||||
assert(onError != null),
|
||||
assert(brightness != null);
|
||||
|
||||
/// Create dark version of the
|
||||
/// [baseline Material color scheme](https://material.io/design/color/the-color-system.html#color-theme-creation).
|
||||
const ColorScheme.dark({
|
||||
this.primary = const Color(0xffbb86fc),
|
||||
this.primaryVariant = const Color(0xff4b01d0),
|
||||
this.secondary = const Color(0xff03dac6),
|
||||
this.secondaryVariant = const Color(0xff03dac6),
|
||||
this.surface = Colors.black,
|
||||
this.background = Colors.black,
|
||||
this.error = const Color(0xffb00020),
|
||||
this.onPrimary = Colors.black,
|
||||
this.onSecondary = Colors.black,
|
||||
this.onSurface = Colors.white,
|
||||
this.onBackground = Colors.white,
|
||||
this.onError = Colors.black,
|
||||
this.brightness = Brightness.dark,
|
||||
}) : assert(primary != null),
|
||||
assert(primaryVariant != null),
|
||||
assert(secondary != null),
|
||||
assert(secondaryVariant != null),
|
||||
assert(surface != null),
|
||||
assert(background != null),
|
||||
assert(error != null),
|
||||
assert(onPrimary != null),
|
||||
assert(onSecondary != null),
|
||||
assert(onSurface != null),
|
||||
assert(onBackground != null),
|
||||
assert(onError != null),
|
||||
assert(brightness != null);
|
||||
|
||||
/// Create a color scheme from a [MaterialColor] swatch.
|
||||
///
|
||||
/// This constructor is used by [ThemeData] to create its default
|
||||
/// color scheme.
|
||||
factory ColorScheme.fromSwatch({
|
||||
MaterialColor primarySwatch = Colors.blue,
|
||||
Color primaryColorDark,
|
||||
Color accentColor,
|
||||
Color cardColor,
|
||||
Color backgroundColor,
|
||||
Color errorColor,
|
||||
Brightness brightness = Brightness.light,
|
||||
}) {
|
||||
assert(primarySwatch != null);
|
||||
assert(brightness != null);
|
||||
|
||||
final bool isDark = brightness == Brightness.dark;
|
||||
final bool primaryIsDark = _brightnessFor(primarySwatch) == Brightness.dark;
|
||||
final Color secondary = accentColor ?? (isDark ? Colors.tealAccent[200] : primarySwatch);
|
||||
final bool secondaryIsDark = _brightnessFor(secondary) == Brightness.dark;
|
||||
|
||||
return ColorScheme(
|
||||
primary: primarySwatch,
|
||||
primaryVariant: primaryColorDark ?? (isDark ? Colors.black : primarySwatch[700]),
|
||||
secondary: secondary,
|
||||
secondaryVariant: isDark ? Colors.tealAccent[700] : primarySwatch[700],
|
||||
surface: cardColor ?? (isDark ? Colors.grey[800] : Colors.white),
|
||||
background: backgroundColor ?? (isDark ? Colors.grey[700] : primarySwatch[200]),
|
||||
error: errorColor ?? Colors.red[700],
|
||||
onPrimary: primaryIsDark ? Colors.white : Colors.black,
|
||||
onSecondary: secondaryIsDark ? Colors.white : Colors.black,
|
||||
onSurface: isDark ? Colors.white : Colors.black,
|
||||
onBackground: primaryIsDark ? Colors.white : Colors.black,
|
||||
onError: isDark ? Colors.black : Colors.white,
|
||||
brightness: brightness,
|
||||
);
|
||||
}
|
||||
|
||||
static Brightness _brightnessFor(Color color) => ThemeData.estimateBrightnessForColor(color);
|
||||
|
||||
/// The color displayed most frequently across your app’s screens and components.
|
||||
final Color primary;
|
||||
|
||||
/// A darker version of the primary color.
|
||||
final Color primaryVariant;
|
||||
|
||||
/// An accent color that, when used sparingly, calls attention to parts
|
||||
/// of your app.
|
||||
final Color secondary;
|
||||
|
||||
/// A darker version of the secondary color.
|
||||
final Color secondaryVariant;
|
||||
|
||||
/// The background color for widgets like [Card].
|
||||
final Color surface;
|
||||
|
||||
/// A color that typically appears behind scrollable content.
|
||||
final Color background;
|
||||
|
||||
/// The color to use for input validation errors, e.g. for
|
||||
/// [InputDecoration.errorText].
|
||||
final Color error;
|
||||
|
||||
/// A color that's clearly legible when drawn on [primary].
|
||||
///
|
||||
/// To ensure that an app is accessibile, a contrast ratio of 4.5:1 for [primary]
|
||||
/// and [onPrimary] is recommended. See
|
||||
/// <https://www.w3.org/TR/UNDERSTANDING-WCAG20/visual-audio-contrast-contrast.html>.
|
||||
final Color onPrimary;
|
||||
|
||||
/// A color that's clearly legible when drawn on [secondary].
|
||||
///
|
||||
/// To ensure that an app is accessibile, a contrast ratio of 4.5:1 for [secondary]
|
||||
/// and [onSecondary] is recommended. See
|
||||
/// <https://www.w3.org/TR/UNDERSTANDING-WCAG20/visual-audio-contrast-contrast.html>.
|
||||
final Color onSecondary;
|
||||
|
||||
/// A color that's clearly legible when drawn on [surface].
|
||||
///
|
||||
/// To ensure that an app is accessibile, a contrast ratio of 4.5:1 for [surface]
|
||||
/// and [onSurface] is recommended. See
|
||||
/// <https://www.w3.org/TR/UNDERSTANDING-WCAG20/visual-audio-contrast-contrast.html>.
|
||||
final Color onSurface;
|
||||
|
||||
/// A color that's clearly legible when drawn on [background].
|
||||
///
|
||||
/// To ensure that an app is accessibile, a contrast ratio of 4.5:1 for [background]
|
||||
/// and [onBackground] is recommended. See
|
||||
/// <https://www.w3.org/TR/UNDERSTANDING-WCAG20/visual-audio-contrast-contrast.html>.
|
||||
final Color onBackground;
|
||||
|
||||
/// A color that's clearly legible when drawn on [error].
|
||||
///
|
||||
/// To ensure that an app is accessibile, a contrast ratio of 4.5:1 for [error]
|
||||
/// and [onError] is recommended. See
|
||||
/// <https://www.w3.org/TR/UNDERSTANDING-WCAG20/visual-audio-contrast-contrast.html>.
|
||||
final Color onError;
|
||||
|
||||
/// The overall brightness of this color scheme.
|
||||
final Brightness brightness;
|
||||
|
||||
/// Creates a copy of this color scheme with the given fields
|
||||
/// replaced by the non-null parameter values.
|
||||
ColorScheme copyWith({
|
||||
Color primary,
|
||||
Color primaryVariant,
|
||||
Color secondary,
|
||||
Color secondaryVariant,
|
||||
Color surface,
|
||||
Color background,
|
||||
Color error,
|
||||
Color onPrimary,
|
||||
Color onSecondary,
|
||||
Color onSurface,
|
||||
Color onBackground,
|
||||
Color onError,
|
||||
Brightness brightness,
|
||||
}) {
|
||||
return ColorScheme(
|
||||
primary: primary ?? this.primary,
|
||||
primaryVariant: primaryVariant ?? this.primaryVariant,
|
||||
secondary: secondary ?? this.secondary,
|
||||
secondaryVariant: secondaryVariant ?? this.secondaryVariant,
|
||||
surface: surface ?? this.surface,
|
||||
background: background ?? this.background,
|
||||
error: error ?? this.error,
|
||||
onPrimary: onPrimary ?? this.onPrimary,
|
||||
onSecondary: onSecondary ?? this.onSecondary,
|
||||
onSurface: onSurface ?? this.onSurface,
|
||||
onBackground: onBackground ?? this.onBackground,
|
||||
onError: onError ?? this.onError,
|
||||
brightness: brightness ?? this.brightness,
|
||||
);
|
||||
}
|
||||
|
||||
/// Linearly interpolate between two [ColorScheme] objects.
|
||||
///
|
||||
/// {@macro flutter.material.themeData.lerp}
|
||||
static ColorScheme lerp(ColorScheme a, ColorScheme b, double t) {
|
||||
return ColorScheme(
|
||||
primary: Color.lerp(a.primary, b.primary, t),
|
||||
primaryVariant: Color.lerp(a.primaryVariant, b.primaryVariant, t),
|
||||
secondary: Color.lerp(a.secondary, b.secondary, t),
|
||||
secondaryVariant: Color.lerp(a.secondaryVariant, b.secondaryVariant, t),
|
||||
surface: Color.lerp(a.surface, b.surface, t),
|
||||
background: Color.lerp(a.background, b.background, t),
|
||||
error: Color.lerp(a.error, b.error, t),
|
||||
onPrimary: Color.lerp(a.onPrimary, b.onPrimary, t),
|
||||
onSecondary: Color.lerp(a.onSecondary, b.onSecondary, t),
|
||||
onSurface: Color.lerp(a.onSurface, b.onSurface, t),
|
||||
onBackground: Color.lerp(a.onBackground, b.onBackground, t),
|
||||
onError: Color.lerp(a.onError, b.onError, t),
|
||||
brightness: t < 0.5 ? a.brightness : b.brightness,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other))
|
||||
return true;
|
||||
if (other.runtimeType != runtimeType)
|
||||
return false;
|
||||
final ColorScheme otherScheme = other;
|
||||
return otherScheme.primary == primary
|
||||
&& otherScheme.primaryVariant == primaryVariant
|
||||
&& otherScheme.secondary == secondary
|
||||
&& otherScheme.secondaryVariant == secondaryVariant
|
||||
&& otherScheme.surface == surface
|
||||
&& otherScheme.background == background
|
||||
&& otherScheme.error == error
|
||||
&& otherScheme.onPrimary == onPrimary
|
||||
&& otherScheme.onSecondary == onSecondary
|
||||
&& otherScheme.onSurface == onSurface
|
||||
&& otherScheme.onBackground == onBackground
|
||||
&& otherScheme.onError == onError
|
||||
&& otherScheme.brightness == brightness;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return hashValues(
|
||||
primary,
|
||||
primaryVariant,
|
||||
secondary,
|
||||
secondaryVariant,
|
||||
surface,
|
||||
background,
|
||||
error,
|
||||
onPrimary,
|
||||
onSecondary,
|
||||
onSurface,
|
||||
onBackground,
|
||||
onError,
|
||||
brightness,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
super.debugFillProperties(properties);
|
||||
const ColorScheme defaultScheme = ColorScheme.light();
|
||||
properties.add(DiagnosticsProperty<Color>('primary', primary, defaultValue: defaultScheme.primary));
|
||||
properties.add(DiagnosticsProperty<Color>('primaryVariant', primaryVariant, defaultValue: defaultScheme.primaryVariant));
|
||||
properties.add(DiagnosticsProperty<Color>('secondary', secondary, defaultValue: defaultScheme.secondary));
|
||||
properties.add(DiagnosticsProperty<Color>('secondaryVariant', secondaryVariant, defaultValue: defaultScheme.secondaryVariant));
|
||||
properties.add(DiagnosticsProperty<Color>('surface', surface, defaultValue: defaultScheme.surface));
|
||||
properties.add(DiagnosticsProperty<Color>('background', background, defaultValue: defaultScheme.background));
|
||||
properties.add(DiagnosticsProperty<Color>('error', error, defaultValue: defaultScheme.error));
|
||||
properties.add(DiagnosticsProperty<Color>('onPrimary', onPrimary, defaultValue: defaultScheme.onPrimary));
|
||||
properties.add(DiagnosticsProperty<Color>('onSecondary', onSecondary, defaultValue: defaultScheme.onSecondary));
|
||||
properties.add(DiagnosticsProperty<Color>('onSurface', onSurface, defaultValue: defaultScheme.onSurface));
|
||||
properties.add(DiagnosticsProperty<Color>('onBackground', onBackground, defaultValue: defaultScheme.onBackground));
|
||||
properties.add(DiagnosticsProperty<Color>('onError', onError, defaultValue: defaultScheme.onError));
|
||||
properties.add(DiagnosticsProperty<Brightness>('brightness', brightness, defaultValue: defaultScheme.brightness));
|
||||
}
|
||||
}
|
@ -21,8 +21,8 @@ import 'icons.dart';
|
||||
import 'ink_well.dart';
|
||||
import 'material.dart';
|
||||
import 'material_localizations.dart';
|
||||
import 'text_theme.dart';
|
||||
import 'theme.dart';
|
||||
import 'typography.dart';
|
||||
|
||||
/// Initial display mode of the date picker dialog.
|
||||
///
|
||||
|
@ -625,4 +625,4 @@ Future<T> showDialog<T>({
|
||||
transitionDuration: const Duration(milliseconds: 150),
|
||||
transitionBuilder: _buildMaterialDialogTransitions,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'button.dart';
|
||||
import 'button_theme.dart';
|
||||
import 'colors.dart';
|
||||
import 'material_button.dart';
|
||||
import 'theme.dart';
|
||||
import 'theme_data.dart';
|
||||
|
||||
@ -49,26 +49,43 @@ import 'theme_data.dart';
|
||||
/// * [InkWell], which implements the ink splash part of a flat button.
|
||||
/// * [RawMaterialButton], the widget this widget is based on.
|
||||
/// * <https://material.google.com/components/buttons.html>
|
||||
class FlatButton extends StatelessWidget {
|
||||
class FlatButton extends MaterialButton {
|
||||
/// Create a simple text button.
|
||||
const FlatButton({
|
||||
Key key,
|
||||
@required this.onPressed,
|
||||
this.onHighlightChanged,
|
||||
this.textTheme,
|
||||
this.textColor,
|
||||
this.disabledTextColor,
|
||||
this.color,
|
||||
this.disabledColor,
|
||||
this.highlightColor,
|
||||
this.splashColor,
|
||||
this.colorBrightness,
|
||||
this.padding,
|
||||
this.shape,
|
||||
this.clipBehavior = Clip.none,
|
||||
this.materialTapTargetSize,
|
||||
@required this.child,
|
||||
}) : assert(clipBehavior != null), super(key: key);
|
||||
@required VoidCallback onPressed,
|
||||
ValueChanged<bool> onHighlightChanged,
|
||||
ButtonTextTheme textTheme,
|
||||
Color textColor,
|
||||
Color disabledTextColor,
|
||||
Color color,
|
||||
Color disabledColor,
|
||||
Color highlightColor,
|
||||
Color splashColor,
|
||||
Brightness colorBrightness,
|
||||
EdgeInsetsGeometry padding,
|
||||
ShapeBorder shape,
|
||||
Clip clipBehavior = Clip.none,
|
||||
MaterialTapTargetSize materialTapTargetSize,
|
||||
@required Widget child,
|
||||
}) : super(
|
||||
key: key,
|
||||
onPressed: onPressed,
|
||||
onHighlightChanged: onHighlightChanged,
|
||||
textTheme: textTheme,
|
||||
textColor: textColor,
|
||||
disabledTextColor: disabledTextColor,
|
||||
color: color,
|
||||
disabledColor: disabledColor,
|
||||
highlightColor: highlightColor,
|
||||
splashColor: splashColor,
|
||||
colorBrightness: colorBrightness,
|
||||
padding: padding,
|
||||
shape: shape,
|
||||
clipBehavior: clipBehavior,
|
||||
materialTapTargetSize: materialTapTargetSize,
|
||||
child: child,
|
||||
);
|
||||
|
||||
/// Create a text button from a pair of widgets that serve as the button's
|
||||
/// [icon] and [label].
|
||||
@ -77,244 +94,47 @@ class FlatButton extends StatelessWidget {
|
||||
/// at the start, and 16 at the end, with an 8 pixel gap in between.
|
||||
///
|
||||
/// The [icon], [label], and [clipBehavior] arguments must not be null.
|
||||
FlatButton.icon({
|
||||
factory FlatButton.icon({
|
||||
Key key,
|
||||
@required this.onPressed,
|
||||
this.onHighlightChanged,
|
||||
this.textTheme,
|
||||
this.textColor,
|
||||
this.disabledTextColor,
|
||||
this.color,
|
||||
this.disabledColor,
|
||||
this.highlightColor,
|
||||
this.splashColor,
|
||||
this.colorBrightness,
|
||||
this.shape,
|
||||
this.clipBehavior = Clip.none,
|
||||
this.materialTapTargetSize,
|
||||
@required VoidCallback onPressed,
|
||||
ValueChanged<bool> onHighlightChanged,
|
||||
ButtonTextTheme textTheme,
|
||||
Color textColor,
|
||||
Color disabledTextColor,
|
||||
Color color,
|
||||
Color disabledColor,
|
||||
Color highlightColor,
|
||||
Color splashColor,
|
||||
Brightness colorBrightness,
|
||||
EdgeInsetsGeometry padding,
|
||||
ShapeBorder shape,
|
||||
Clip clipBehavior,
|
||||
MaterialTapTargetSize materialTapTargetSize,
|
||||
@required Widget icon,
|
||||
@required Widget label,
|
||||
}) : assert(icon != null),
|
||||
assert(label != null),
|
||||
assert(clipBehavior != null),
|
||||
padding = const EdgeInsetsDirectional.only(start: 12.0, end: 16.0),
|
||||
child = Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
icon,
|
||||
const SizedBox(width: 8.0),
|
||||
label,
|
||||
],
|
||||
),
|
||||
super(key: key);
|
||||
|
||||
/// Called when the button is tapped or otherwise activated.
|
||||
///
|
||||
/// If this is set to null, the button will be disabled, see [enabled].
|
||||
final VoidCallback onPressed;
|
||||
|
||||
/// Called by the underlying [InkWell] widget's [InkWell.onHighlightChanged]
|
||||
/// callback.
|
||||
final ValueChanged<bool> onHighlightChanged;
|
||||
|
||||
/// Defines the button's base colors, and the defaults for the button's minimum
|
||||
/// size, internal padding, and shape.
|
||||
///
|
||||
/// Defaults to `ButtonTheme.of(context).textTheme`.
|
||||
final ButtonTextTheme textTheme;
|
||||
|
||||
/// The color to use for this button's text.
|
||||
///
|
||||
/// The button's [Material.textStyle] will be the current theme's button
|
||||
/// text style, [ThemeData.textTheme.button], configured with this color.
|
||||
///
|
||||
/// The default text color depends on the button theme's text theme,
|
||||
/// [ButtonThemeData.textTheme].
|
||||
///
|
||||
/// See also:
|
||||
/// * [disabledTextColor], the text color to use when the button has been
|
||||
/// disabled.
|
||||
final Color textColor;
|
||||
|
||||
/// The color to use for this button's text when the button is disabled.
|
||||
///
|
||||
/// The button's [Material.textStyle] will be the current theme's button
|
||||
/// text style, [ThemeData.textTheme.button], configured with this color.
|
||||
///
|
||||
/// The default value is the theme's disabled color,
|
||||
/// [ThemeData.disabledColor].
|
||||
///
|
||||
/// See also:
|
||||
/// * [textColor] - The color to use for this button's text when the button is [enabled].
|
||||
final Color disabledTextColor;
|
||||
|
||||
/// The button's fill color, displayed by its [Material], while it
|
||||
/// is in its default (unpressed, enabled) state.
|
||||
///
|
||||
/// Typically not specified for [FlatButton]s.
|
||||
///
|
||||
/// The default is null.
|
||||
final Color color;
|
||||
|
||||
/// The fill color of the button when the button is disabled.
|
||||
///
|
||||
/// Typically not specified for [FlatButton]s.
|
||||
///
|
||||
/// The default is null.
|
||||
final Color disabledColor;
|
||||
|
||||
/// The splash color of the button's [InkWell].
|
||||
///
|
||||
/// The ink splash indicates that the button has been touched. It
|
||||
/// appears on top of the button's child and spreads in an expanding
|
||||
/// circle beginning where the touch occurred.
|
||||
///
|
||||
/// If [textTheme] is [ButtonTextTheme.primary], the default splash color is
|
||||
/// is based on the theme's primary color [ThemeData.primaryColor],
|
||||
/// otherwise it's the current theme's splash color, [ThemeData.splashColor].
|
||||
///
|
||||
/// The appearance of the splash can be configured with the theme's splash
|
||||
/// factory, [ThemeData.splashFactory].
|
||||
final Color splashColor;
|
||||
|
||||
/// The highlight color of the button's [InkWell].
|
||||
///
|
||||
/// The highlight indicates that the button is actively being pressed. It
|
||||
/// appears on top of the button's child and quickly spreads to fill
|
||||
/// the button, and then fades out.
|
||||
///
|
||||
/// If [textTheme] is [ButtonTextTheme.primary], the default highlight color is
|
||||
/// transparent (in other words the highlight doesn't appear). Otherwise it's
|
||||
/// the current theme's highlight color, [ThemeData.highlightColor].
|
||||
final Color highlightColor;
|
||||
|
||||
/// The theme brightness to use for this button.
|
||||
///
|
||||
/// Defaults to the theme's brightness, [ThemeData.brightness].
|
||||
final Brightness colorBrightness;
|
||||
|
||||
/// Configures the minimum size of the tap target.
|
||||
///
|
||||
/// Defaults to [ThemeData.materialTapTargetSize].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [MaterialTapTargetSize], for a description of how this affects tap targets.
|
||||
final MaterialTapTargetSize materialTapTargetSize;
|
||||
|
||||
/// The widget below this widget in the tree.
|
||||
///
|
||||
/// Typically a [Text] widget in all caps.
|
||||
final Widget child;
|
||||
|
||||
/// Whether the button is enabled or disabled.
|
||||
///
|
||||
/// Buttons are disabled by default. To enable a button, set its [onPressed]
|
||||
/// property to a non-null value.
|
||||
bool get enabled => onPressed != null;
|
||||
|
||||
/// The internal padding for the button's [child].
|
||||
///
|
||||
/// Defaults to the value from the current [ButtonTheme],
|
||||
/// [ButtonThemeData.padding].
|
||||
final EdgeInsetsGeometry padding;
|
||||
|
||||
/// The shape of the button's [Material].
|
||||
///
|
||||
/// The button's highlight and splash are clipped to this shape. If the
|
||||
/// button has an elevation, then its drop shadow is defined by this
|
||||
/// shape as well.
|
||||
final ShapeBorder shape;
|
||||
|
||||
/// {@macro flutter.widgets.Clip}
|
||||
final Clip clipBehavior;
|
||||
|
||||
Brightness _getBrightness(ThemeData theme) {
|
||||
return colorBrightness ?? theme.brightness;
|
||||
}
|
||||
|
||||
ButtonTextTheme _getTextTheme(ButtonThemeData buttonTheme) {
|
||||
return textTheme ?? buttonTheme.textTheme;
|
||||
}
|
||||
|
||||
Color _getTextColor(ThemeData theme, ButtonThemeData buttonTheme, Color fillColor) {
|
||||
final Color color = enabled ? textColor : disabledTextColor;
|
||||
if (color != null)
|
||||
return color;
|
||||
|
||||
final bool themeIsDark = _getBrightness(theme) == Brightness.dark;
|
||||
final bool fillIsDark = fillColor == null
|
||||
? themeIsDark
|
||||
: ThemeData.estimateBrightnessForColor(fillColor) == Brightness.dark;
|
||||
|
||||
switch (_getTextTheme(buttonTheme)) {
|
||||
case ButtonTextTheme.normal:
|
||||
return enabled
|
||||
? (themeIsDark ? Colors.white : Colors.black87)
|
||||
: theme.disabledColor;
|
||||
case ButtonTextTheme.accent:
|
||||
return enabled
|
||||
? theme.accentColor
|
||||
: theme.disabledColor;
|
||||
case ButtonTextTheme.primary:
|
||||
return enabled
|
||||
? (fillIsDark ? Colors.white : theme.primaryColor)
|
||||
: (themeIsDark ? Colors.white30 : Colors.black38);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Color _getSplashColor(ThemeData theme, ButtonThemeData buttonTheme) {
|
||||
if (splashColor != null)
|
||||
return splashColor;
|
||||
|
||||
switch (_getTextTheme(buttonTheme)) {
|
||||
case ButtonTextTheme.normal:
|
||||
case ButtonTextTheme.accent:
|
||||
return theme.splashColor;
|
||||
case ButtonTextTheme.primary:
|
||||
return _getBrightness(theme) == Brightness.dark
|
||||
? Colors.white12
|
||||
: theme.primaryColor.withOpacity(0.12);
|
||||
}
|
||||
return Colors.transparent;
|
||||
}
|
||||
|
||||
Color _getHighlightColor(ThemeData theme, ButtonThemeData buttonTheme) {
|
||||
if (highlightColor != null)
|
||||
return highlightColor;
|
||||
|
||||
switch (_getTextTheme(buttonTheme)) {
|
||||
case ButtonTextTheme.normal:
|
||||
case ButtonTextTheme.accent:
|
||||
return theme.highlightColor;
|
||||
case ButtonTextTheme.primary:
|
||||
return Colors.transparent;
|
||||
}
|
||||
return Colors.transparent;
|
||||
}
|
||||
}) = _FlatButtonWithIcon;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final ThemeData theme = Theme.of(context);
|
||||
final ButtonThemeData buttonTheme = ButtonTheme.of(context);
|
||||
final Color fillColor = enabled ? color : disabledColor;
|
||||
final Color textColor = _getTextColor(theme, buttonTheme, fillColor);
|
||||
|
||||
return RawMaterialButton(
|
||||
onPressed: onPressed,
|
||||
onHighlightChanged: onHighlightChanged,
|
||||
fillColor: fillColor,
|
||||
textStyle: theme.textTheme.button.copyWith(color: textColor),
|
||||
highlightColor: _getHighlightColor(theme, buttonTheme),
|
||||
splashColor: _getSplashColor(theme, buttonTheme),
|
||||
elevation: 0.0,
|
||||
highlightElevation: 0.0,
|
||||
materialTapTargetSize: materialTapTargetSize ?? theme.materialTapTargetSize,
|
||||
padding: padding ?? buttonTheme.padding,
|
||||
constraints: buttonTheme.constraints,
|
||||
shape: shape ?? buttonTheme.shape,
|
||||
clipBehavior: clipBehavior,
|
||||
clipBehavior: clipBehavior ?? Clip.none,
|
||||
fillColor: buttonTheme.getFillColor(this),
|
||||
textStyle: theme.textTheme.button.copyWith(color: buttonTheme.getTextColor(this)),
|
||||
highlightColor: buttonTheme.getHighlightColor(this),
|
||||
splashColor: buttonTheme.getSplashColor(this),
|
||||
elevation: buttonTheme.getElevation(this),
|
||||
highlightElevation: buttonTheme.getHighlightElevation(this),
|
||||
disabledElevation: buttonTheme.getDisabledElevation(this),
|
||||
padding: buttonTheme.getPadding(this),
|
||||
constraints: buttonTheme.getConstraints(this),
|
||||
shape: buttonTheme.getShape(this),
|
||||
animationDuration: buttonTheme.getAnimationDuration(this),
|
||||
materialTapTargetSize: buttonTheme.getMaterialTapTargetSize(this),
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
@ -336,3 +156,56 @@ class FlatButton extends StatelessWidget {
|
||||
properties.add(DiagnosticsProperty<MaterialTapTargetSize>('materialTapTargetSize', materialTapTargetSize, defaultValue: null));
|
||||
}
|
||||
}
|
||||
|
||||
/// The type of of FlatButtons created with [FlatButton.icon].
|
||||
///
|
||||
/// This class only exists to give FlatButtons created with [FlatButton.icon]
|
||||
/// a distinct class for the sake of [ButtonTheme]. It can not be instantiated.
|
||||
class _FlatButtonWithIcon extends FlatButton implements MaterialButtonWithIconMixin {
|
||||
_FlatButtonWithIcon({
|
||||
Key key,
|
||||
@required VoidCallback onPressed,
|
||||
ValueChanged<bool> onHighlightChanged,
|
||||
ButtonTextTheme textTheme,
|
||||
Color textColor,
|
||||
Color disabledTextColor,
|
||||
Color color,
|
||||
Color disabledColor,
|
||||
Color highlightColor,
|
||||
Color splashColor,
|
||||
Brightness colorBrightness,
|
||||
EdgeInsetsGeometry padding,
|
||||
ShapeBorder shape,
|
||||
Clip clipBehavior,
|
||||
MaterialTapTargetSize materialTapTargetSize,
|
||||
@required Widget icon,
|
||||
@required Widget label,
|
||||
}) : assert(icon != null),
|
||||
assert(label != null),
|
||||
super(
|
||||
key: key,
|
||||
onPressed: onPressed,
|
||||
onHighlightChanged: onHighlightChanged,
|
||||
textTheme: textTheme,
|
||||
textColor: textColor,
|
||||
disabledTextColor: disabledTextColor,
|
||||
color: color,
|
||||
disabledColor: disabledColor,
|
||||
highlightColor: highlightColor,
|
||||
splashColor: splashColor,
|
||||
colorBrightness: colorBrightness,
|
||||
padding: padding,
|
||||
shape: shape,
|
||||
clipBehavior: clipBehavior,
|
||||
materialTapTargetSize: materialTapTargetSize,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
icon,
|
||||
const SizedBox(width: 8.0),
|
||||
label,
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
}
|
||||
|
287
packages/flutter/lib/src/material/material_button.dart
Normal file
287
packages/flutter/lib/src/material/material_button.dart
Normal file
@ -0,0 +1,287 @@
|
||||
// Copyright 2018 The Chromium 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/foundation.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'button.dart';
|
||||
import 'button_theme.dart';
|
||||
import 'constants.dart';
|
||||
import 'ink_well.dart';
|
||||
import 'material.dart';
|
||||
import 'theme.dart';
|
||||
import 'theme_data.dart';
|
||||
|
||||
/// A utility class for building Material buttons that depend on the
|
||||
/// ambient [ButtonTheme] and [Theme].
|
||||
///
|
||||
/// The button's size will expand to fit the child widget, if necessary.
|
||||
///
|
||||
/// MaterialButtons whose [onPressed] handler is null will be disabled. To have
|
||||
/// an enabled button, make sure to pass a non-null value for onPressed.
|
||||
///
|
||||
/// Rather than using this class directly, consider using [FlatButton],
|
||||
/// OutlineButton, or [RaisedButton], which configure this class with
|
||||
/// appropriate defaults that match the material design specification.
|
||||
///
|
||||
/// To create a button directly, without inheriting theme defaults, use
|
||||
/// [RawMaterialButton].
|
||||
///
|
||||
/// If you want an ink-splash effect for taps, but don't want to use a button,
|
||||
/// consider using [InkWell] directly.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [IconButton], to create buttons that contain icons rather than text.
|
||||
class MaterialButton extends StatelessWidget {
|
||||
/// Creates a material button.
|
||||
///
|
||||
/// Rather than creating a material button directly, consider using
|
||||
/// [FlatButton] or [RaisedButton]. To create a custom Material button
|
||||
/// consider using [RawMaterialButton].
|
||||
///
|
||||
/// The [clipBehavior] argument must not be null.
|
||||
const MaterialButton({
|
||||
Key key,
|
||||
@required this.onPressed,
|
||||
this.onHighlightChanged,
|
||||
this.textTheme,
|
||||
this.textColor,
|
||||
this.disabledTextColor,
|
||||
this.color,
|
||||
this.disabledColor,
|
||||
this.highlightColor,
|
||||
this.splashColor,
|
||||
this.colorBrightness,
|
||||
this.elevation,
|
||||
this.highlightElevation,
|
||||
this.disabledElevation,
|
||||
this.padding,
|
||||
this.shape,
|
||||
this.clipBehavior = Clip.none,
|
||||
this.materialTapTargetSize,
|
||||
this.animationDuration,
|
||||
this.minWidth,
|
||||
this.height,
|
||||
this.child,
|
||||
}) : super(key: key);
|
||||
|
||||
/// The callback that is called when the button is tapped or otherwise activated.
|
||||
///
|
||||
/// If this is set to null, the button will be disabled.
|
||||
final VoidCallback onPressed;
|
||||
|
||||
/// Called by the underlying [InkWell] widget's [InkWell.onHighlightChanged]
|
||||
/// callback.
|
||||
final ValueChanged<bool> onHighlightChanged;
|
||||
|
||||
/// Defines the button's base colors, and the defaults for the button's minimum
|
||||
/// size, internal padding, and shape.
|
||||
///
|
||||
/// Defaults to `ButtonTheme.of(context).textTheme`.
|
||||
final ButtonTextTheme textTheme;
|
||||
|
||||
/// The color to use for this button's text.
|
||||
///
|
||||
/// The button's [Material.textStyle] will be the current theme's button
|
||||
/// text style, [ThemeData.textTheme.button], configured with this color.
|
||||
///
|
||||
/// The default text color depends on the button theme's text theme,
|
||||
/// [ButtonThemeData.textTheme].
|
||||
///
|
||||
/// See also:
|
||||
/// * [disabledTextColor], the text color to use when the button has been
|
||||
/// disabled.
|
||||
final Color textColor;
|
||||
|
||||
/// The color to use for this button's text when the button is disabled.
|
||||
///
|
||||
/// The button's [Material.textStyle] will be the current theme's button
|
||||
/// text style, [ThemeData.textTheme.button], configured with this color.
|
||||
///
|
||||
/// The default value is the theme's disabled color,
|
||||
/// [ThemeData.disabledColor].
|
||||
///
|
||||
/// See also:
|
||||
/// * [textColor] - The color to use for this button's text when the button is [enabled].
|
||||
final Color disabledTextColor;
|
||||
|
||||
/// The button's fill color, displayed by its [Material], while it
|
||||
/// is in its default (unpressed, [enabled]) state.
|
||||
///
|
||||
/// The default fill color is the theme's button color, [ThemeData.buttonColor].
|
||||
///
|
||||
/// See also:
|
||||
/// * [disabledColor] - the fill color of the button when the button is disabled.
|
||||
final Color color;
|
||||
|
||||
/// The fill color of the button when the button is disabled.
|
||||
///
|
||||
/// The default value of this color is the theme's disabled color,
|
||||
/// [ThemeData.disabledColor].
|
||||
///
|
||||
/// See also:
|
||||
/// * [color] - the fill color of the button when the button is [enabled].
|
||||
final Color disabledColor;
|
||||
|
||||
/// The splash color of the button's [InkWell].
|
||||
///
|
||||
/// The ink splash indicates that the button has been touched. It
|
||||
/// appears on top of the button's child and spreads in an expanding
|
||||
/// circle beginning where the touch occurred.
|
||||
///
|
||||
/// The default splash color is the current theme's splash color,
|
||||
/// [ThemeData.splashColor].
|
||||
///
|
||||
/// The appearance of the splash can be configured with the theme's splash
|
||||
/// factory, [ThemeData.splashFactory].
|
||||
final Color splashColor;
|
||||
|
||||
/// The highlight color of the button's [InkWell].
|
||||
///
|
||||
/// The highlight indicates that the button is actively being pressed. It
|
||||
/// appears on top of the button's child and quickly spreads to fill
|
||||
/// the button, and then fades out.
|
||||
///
|
||||
/// If [textTheme] is [ButtonTextTheme.primary], the default highlight color is
|
||||
/// transparent (in other words the highlight doesn't appear). Otherwise it's
|
||||
/// the current theme's highlight color, [ThemeData.highlightColor].
|
||||
final Color highlightColor;
|
||||
|
||||
/// The z-coordinate at which to place this button. This controls the size of
|
||||
/// the shadow below the raised button.
|
||||
///
|
||||
/// Defaults to 2, the appropriate elevation for raised buttons.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [FlatButton], a button with no elevation or fill color.
|
||||
/// * [disabledElevation], the elevation when the button is disabled.
|
||||
/// * [highlightElevation], the elevation when the button is pressed.
|
||||
final double elevation;
|
||||
|
||||
/// The elevation for the button's [Material] when the button
|
||||
/// is [enabled] and pressed.
|
||||
///
|
||||
/// This controls the size of the shadow below the button. When a tap
|
||||
/// down gesture occurs within the button, its [InkWell] displays a
|
||||
/// [highlightColor] "highlight".
|
||||
///
|
||||
/// Defaults to 8.0.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [elevation], the default elevation.
|
||||
/// * [disabledElevation], the elevation when the button is disabled.
|
||||
final double highlightElevation;
|
||||
|
||||
/// The elevation for the button's [Material] when the button
|
||||
/// is not [enabled].
|
||||
///
|
||||
/// Defaults to 0.0.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [elevation], the default elevation.
|
||||
/// * [highlightElevation], the elevation when the button is pressed.
|
||||
final double disabledElevation;
|
||||
|
||||
/// The theme brightness to use for this button.
|
||||
///
|
||||
/// Defaults to the theme's brightness, [ThemeData.brightness].
|
||||
final Brightness colorBrightness;
|
||||
|
||||
/// The button's label.
|
||||
///
|
||||
/// Often a [Text] widget in all caps.
|
||||
final Widget child;
|
||||
|
||||
/// Whether the button is enabled or disabled.
|
||||
///
|
||||
/// Buttons are disabled by default. To enable a button, set its [onPressed]
|
||||
/// property to a non-null value.
|
||||
bool get enabled => onPressed != null;
|
||||
|
||||
/// The internal padding for the button's [child].
|
||||
///
|
||||
/// Defaults to the value from the current [ButtonTheme],
|
||||
/// [ButtonThemeData.padding].
|
||||
final EdgeInsetsGeometry padding;
|
||||
|
||||
/// The shape of the button's [Material].
|
||||
///
|
||||
/// The button's highlight and splash are clipped to this shape. If the
|
||||
/// button has an elevation, then its drop shadow is defined by this
|
||||
/// shape as well.
|
||||
final ShapeBorder shape;
|
||||
|
||||
/// {@macro flutter.widgets.Clip}
|
||||
final Clip clipBehavior;
|
||||
|
||||
/// Defines the duration of animated changes for [shape] and [elevation].
|
||||
///
|
||||
/// The default value is [kThemeChangeDuration].
|
||||
final Duration animationDuration;
|
||||
|
||||
/// Configures the minimum size of the tap target.
|
||||
///
|
||||
/// Defaults to [ThemeData.materialTapTargetSize].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [MaterialTapTargetSize], for a description of how this affects tap targets.
|
||||
final MaterialTapTargetSize materialTapTargetSize;
|
||||
|
||||
/// The smallest horizontal extent that the button will occupy.
|
||||
///
|
||||
/// Defaults to the value from the current [ButtonTheme].
|
||||
final double minWidth;
|
||||
|
||||
/// The vertical extent of the button.
|
||||
///
|
||||
/// Defaults to the value from the current [ButtonTheme].
|
||||
final double height;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final ThemeData theme = Theme.of(context);
|
||||
final ButtonThemeData buttonTheme = ButtonTheme.of(context);
|
||||
|
||||
return RawMaterialButton(
|
||||
onPressed: onPressed,
|
||||
fillColor: color,
|
||||
textStyle: theme.textTheme.button.copyWith(color: buttonTheme.getTextColor(this)),
|
||||
highlightColor: highlightColor ?? theme.highlightColor,
|
||||
splashColor: splashColor ?? theme.splashColor,
|
||||
elevation: buttonTheme.getElevation(this),
|
||||
highlightElevation: buttonTheme.getHighlightElevation(this),
|
||||
padding: buttonTheme.getPadding(this),
|
||||
constraints: buttonTheme.getConstraints(this).copyWith(
|
||||
minWidth: minWidth,
|
||||
minHeight: height,
|
||||
),
|
||||
shape: buttonTheme.shape,
|
||||
clipBehavior: clipBehavior ?? Clip.none,
|
||||
animationDuration: buttonTheme.getAnimationDuration(this),
|
||||
child: child,
|
||||
materialTapTargetSize: materialTapTargetSize ?? theme.materialTapTargetSize,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
super.debugFillProperties(properties);
|
||||
properties.add(FlagProperty('enabled', value: enabled, ifFalse: 'disabled'));
|
||||
}
|
||||
}
|
||||
|
||||
/// The type of [MaterialButton]s created with [RaisedButton.icon], [FlatButton.icon],
|
||||
/// and [OutlineButton.icon].
|
||||
///
|
||||
/// This mixin only exists to give the "label and icon" button widgets a distinct
|
||||
/// type for the sake of [ButtonTheme].
|
||||
abstract class MaterialButtonWithIconMixin {
|
||||
MaterialButtonWithIconMixin._();
|
||||
}
|
@ -7,6 +7,7 @@ import 'dart:async';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'text_theme.dart';
|
||||
import 'time.dart';
|
||||
import 'typography.dart';
|
||||
|
||||
@ -34,6 +35,10 @@ import 'typography.dart';
|
||||
//
|
||||
// 5. If you are a Google employee, you should then also follow the instructions
|
||||
// at go/flutter-l10n. If you're not, don't worry about it.
|
||||
//
|
||||
// 6. If you're adding a String for the sake of Flutter, not for an app-specific
|
||||
// version of this interface, you are making a breaking API change. See
|
||||
// https://flutter.io/design-principles/#handling-breaking-changes.
|
||||
|
||||
/// Defines the localized resource values used by the Material widgets.
|
||||
///
|
||||
@ -168,22 +173,17 @@ abstract class MaterialLocalizations {
|
||||
/// each supported layout.
|
||||
TimeOfDayFormat timeOfDayFormat({ bool alwaysUse24HourFormat = false });
|
||||
|
||||
/// Provides geometric text preferences for the current locale.
|
||||
/// Defines the localized [TextStyle] geometry for [ThemeData.textTheme].
|
||||
///
|
||||
/// This text theme is incomplete. For example, it lacks text color
|
||||
/// information. This theme must be merged with another text theme that
|
||||
/// provides the missing values.
|
||||
/// The [scriptCategory] defines the overall geometry of a [TextTheme] for
|
||||
/// the static [MaterialTextGeometry.localizedFor] method in terms of the
|
||||
/// three language categories defined in https://material.io/go/design-typography.
|
||||
///
|
||||
/// Typically a complete theme is obtained via [Theme.of], which can be
|
||||
/// localized using the [Localizations] widget.
|
||||
///
|
||||
/// The text styles provided by this theme are expected to have their
|
||||
/// [TextStyle.inherit] property set to false, so that the [ThemeData]
|
||||
/// obtained from [Theme.of] no longer inherits text style properties and
|
||||
/// contains a complete set of properties needed to style a [Text] widget.
|
||||
///
|
||||
/// See also: https://material.io/go/design-typography
|
||||
TextTheme get localTextGeometry;
|
||||
/// Generally speaking, font sizes for [ScriptCategory.tall] and
|
||||
/// [ScriptCategory.dense] scripts - for text styles that are smaller than the
|
||||
/// title style - are one unit larger than they are for
|
||||
/// [ScriptCategory.englishLike] scripts.
|
||||
ScriptCategory get scriptCategory;
|
||||
|
||||
/// Formats [number] as a decimal, inserting locale-appropriate thousands
|
||||
/// separators as necessary.
|
||||
@ -652,6 +652,9 @@ class DefaultMaterialLocalizations implements MaterialLocalizations {
|
||||
@override
|
||||
String get modalBarrierDismissLabel => 'Dismiss';
|
||||
|
||||
@override
|
||||
ScriptCategory get scriptCategory => ScriptCategory.englishLike;
|
||||
|
||||
@override
|
||||
TimeOfDayFormat timeOfDayFormat({ bool alwaysUse24HourFormat = false }) {
|
||||
return alwaysUse24HourFormat
|
||||
@ -659,10 +662,6 @@ class DefaultMaterialLocalizations implements MaterialLocalizations {
|
||||
: TimeOfDayFormat.h_colon_mm_space_a;
|
||||
}
|
||||
|
||||
/// Looks up text geometry defined in [MaterialTextGeometry].
|
||||
@override
|
||||
TextTheme get localTextGeometry => MaterialTextGeometry.englishLike;
|
||||
|
||||
@override
|
||||
String get signedInLabel => 'Signed in';
|
||||
|
||||
|
@ -7,6 +7,7 @@ import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'button_theme.dart';
|
||||
import 'colors.dart';
|
||||
import 'material_button.dart';
|
||||
import 'raised_button.dart';
|
||||
import 'theme.dart';
|
||||
|
||||
@ -48,31 +49,44 @@ const Duration _kElevationDuration = Duration(milliseconds: 75);
|
||||
/// * [IconButton], to create buttons that just contain icons.
|
||||
/// * [InkWell], which implements the ink splash part of a flat button.
|
||||
/// * <https://material.google.com/components/buttons.html>
|
||||
class OutlineButton extends StatefulWidget {
|
||||
class OutlineButton extends MaterialButton {
|
||||
/// Create a filled button.
|
||||
///
|
||||
/// The [highlightElevation], [borderWidth], and [clipBehavior]
|
||||
/// arguments must not be null.
|
||||
const OutlineButton({
|
||||
Key key,
|
||||
@required this.onPressed,
|
||||
this.textTheme,
|
||||
this.textColor,
|
||||
this.disabledTextColor,
|
||||
this.color,
|
||||
this.highlightColor,
|
||||
this.splashColor,
|
||||
this.highlightElevation = 2.0,
|
||||
@required VoidCallback onPressed,
|
||||
ButtonTextTheme textTheme,
|
||||
Color textColor,
|
||||
Color disabledTextColor,
|
||||
Color color,
|
||||
Color highlightColor,
|
||||
Color splashColor,
|
||||
double highlightElevation,
|
||||
this.borderSide,
|
||||
this.disabledBorderColor,
|
||||
this.highlightedBorderColor,
|
||||
this.padding,
|
||||
this.shape,
|
||||
this.clipBehavior = Clip.none,
|
||||
this.child,
|
||||
}) : assert(highlightElevation != null && highlightElevation >= 0.0),
|
||||
assert(clipBehavior != null),
|
||||
super(key: key);
|
||||
EdgeInsetsGeometry padding,
|
||||
ShapeBorder shape,
|
||||
Clip clipBehavior = Clip.none,
|
||||
Widget child,
|
||||
}) : assert(highlightElevation == null || highlightElevation >= 0.0),
|
||||
super(
|
||||
key: key,
|
||||
onPressed: onPressed,
|
||||
textTheme: textTheme,
|
||||
textColor: textColor,
|
||||
disabledTextColor: disabledTextColor,
|
||||
color: color,
|
||||
highlightColor: highlightColor,
|
||||
splashColor: splashColor,
|
||||
highlightElevation: highlightElevation,
|
||||
padding: padding,
|
||||
shape: shape,
|
||||
clipBehavior: clipBehavior,
|
||||
child: child,
|
||||
);
|
||||
|
||||
/// Create an outline button from a pair of widgets that serve as the button's
|
||||
/// [icon] and [label].
|
||||
@ -82,125 +96,25 @@ class OutlineButton extends StatefulWidget {
|
||||
///
|
||||
/// The [highlightElevation], [icon], [label], and [clipBehavior] must not be
|
||||
/// null.
|
||||
OutlineButton.icon({
|
||||
factory OutlineButton.icon({
|
||||
Key key,
|
||||
@required this.onPressed,
|
||||
this.textTheme,
|
||||
this.textColor,
|
||||
this.disabledTextColor,
|
||||
this.color,
|
||||
this.highlightColor,
|
||||
this.splashColor,
|
||||
this.highlightElevation = 2.0,
|
||||
this.borderSide,
|
||||
this.disabledBorderColor,
|
||||
this.highlightedBorderColor,
|
||||
this.shape,
|
||||
this.clipBehavior = Clip.none,
|
||||
@required VoidCallback onPressed,
|
||||
ButtonTextTheme textTheme,
|
||||
Color textColor,
|
||||
Color disabledTextColor,
|
||||
Color color,
|
||||
Color highlightColor,
|
||||
Color splashColor,
|
||||
double highlightElevation,
|
||||
Color highlightedBorderColor,
|
||||
Color disabledBorderColor,
|
||||
BorderSide borderSide,
|
||||
EdgeInsetsGeometry padding,
|
||||
ShapeBorder shape,
|
||||
Clip clipBehavior,
|
||||
@required Widget icon,
|
||||
@required Widget label,
|
||||
}) : assert(highlightElevation != null && highlightElevation >= 0.0),
|
||||
assert(icon != null),
|
||||
assert(label != null),
|
||||
assert(clipBehavior != null),
|
||||
padding = const EdgeInsetsDirectional.only(start: 12.0, end: 16.0),
|
||||
child = Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
icon,
|
||||
const SizedBox(width: 8.0),
|
||||
label,
|
||||
],
|
||||
),
|
||||
super(key: key);
|
||||
|
||||
/// Called when the button is tapped or otherwise activated.
|
||||
///
|
||||
/// If this is set to null, the button will be disabled, see [enabled].
|
||||
final VoidCallback onPressed;
|
||||
|
||||
/// Defines the button's base colors, and the defaults for the button's minimum
|
||||
/// size, internal padding, and shape.
|
||||
///
|
||||
/// Defaults to `ButtonTheme.of(context).textTheme`.
|
||||
final ButtonTextTheme textTheme;
|
||||
|
||||
/// The color to use for this button's text.
|
||||
///
|
||||
/// The button's [Material.textStyle] will be the current theme's button
|
||||
/// text style, [ThemeData.textTheme.button], configured with this color.
|
||||
///
|
||||
/// The default text color depends on the button theme's text theme,
|
||||
/// [ButtonThemeData.textTheme].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [disabledTextColor], the text color to use when the button has been
|
||||
/// disabled.
|
||||
final Color textColor;
|
||||
|
||||
/// The color to use for this button's text when the button is disabled.
|
||||
///
|
||||
/// The button's [Material.textStyle] will be the current theme's button
|
||||
/// text style, [ThemeData.textTheme.button], configured with this color.
|
||||
///
|
||||
/// The default value is the theme's disabled color,
|
||||
/// [ThemeData.disabledColor].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [textColor], which specifies the color to use for this button's text
|
||||
/// when the button is [enabled].
|
||||
final Color disabledTextColor;
|
||||
|
||||
/// The button's opaque fill color when it's [enabled] and has been pressed.
|
||||
///
|
||||
/// If null this value defaults to white for light themes (see
|
||||
/// [ThemeData.brightness]), and black for dark themes.
|
||||
final Color color;
|
||||
|
||||
/// The splash color of the button's [InkWell].
|
||||
///
|
||||
/// The ink splash indicates that the button has been touched. It
|
||||
/// appears on top of the button's child and spreads in an expanding
|
||||
/// circle beginning where the touch occurred.
|
||||
///
|
||||
/// If [textTheme] is [ButtonTextTheme.primary], the default splash color is
|
||||
/// is based on the theme's primary color [ThemeData.primaryColor],
|
||||
/// otherwise it's the current theme's splash color, [ThemeData.splashColor].
|
||||
///
|
||||
/// The appearance of the splash can be configured with the theme's splash
|
||||
/// factory, [ThemeData.splashFactory].
|
||||
final Color splashColor;
|
||||
|
||||
/// The highlight color of the button's [InkWell].
|
||||
///
|
||||
/// The highlight indicates that the button is actively being pressed. It
|
||||
/// appears on top of the button's child and quickly spreads to fill
|
||||
/// the button, and then fades out.
|
||||
///
|
||||
/// If [textTheme] is [ButtonTextTheme.primary], the default highlight color is
|
||||
/// transparent (in other words the highlight doesn't appear). Otherwise it's
|
||||
/// the current theme's highlight color, [ThemeData.highlightColor].
|
||||
final Color highlightColor;
|
||||
|
||||
/// The elevation of the button when it's [enabled] and has been pressed.
|
||||
///
|
||||
/// If null, this value defaults to 2.0.
|
||||
///
|
||||
/// The elevation of an outline button is always 0.0 unless its enabled
|
||||
/// and has been pressed.
|
||||
final double highlightElevation;
|
||||
|
||||
/// Defines the color of the border when the button is enabled but not
|
||||
/// pressed, and the border outline's width and style in general.
|
||||
///
|
||||
/// If the border side's [BorderSide.style] is [BorderStyle.none], then
|
||||
/// an outline is not drawn.
|
||||
///
|
||||
/// If null the default border's style is [BorderStyle.solid], its
|
||||
/// [BorderSide.width] is 2.0, and its color is a light shade of grey.
|
||||
final BorderSide borderSide;
|
||||
}) = _OutlineButtonWithIcon;
|
||||
|
||||
/// The outline border's color when the button is [enabled] and pressed.
|
||||
///
|
||||
@ -215,36 +129,38 @@ class OutlineButton extends StatefulWidget {
|
||||
/// dark themes.
|
||||
final Color disabledBorderColor;
|
||||
|
||||
/// The internal padding for the button's [child].
|
||||
/// Defines the color of the border when the button is enabled but not
|
||||
/// pressed, and the border outline's width and style in general.
|
||||
///
|
||||
/// Defaults to the value from the current [ButtonTheme],
|
||||
/// [ButtonThemeData.padding].
|
||||
final EdgeInsetsGeometry padding;
|
||||
|
||||
/// The shape of the button's [Material] and its outline.
|
||||
/// If the border side's [BorderSide.style] is [BorderStyle.none], then
|
||||
/// an outline is not drawn.
|
||||
///
|
||||
/// The button's highlight and splash are clipped to this shape. If the
|
||||
/// button has a [highlightElevation], then its drop shadow is defined by this
|
||||
/// shape as well.
|
||||
final ShapeBorder shape;
|
||||
|
||||
/// {@macro flutter.widgets.Clip}
|
||||
final Clip clipBehavior;
|
||||
|
||||
/// The button's label.
|
||||
///
|
||||
/// Often a [Text] widget in all caps.
|
||||
final Widget child;
|
||||
|
||||
/// Whether the button is enabled or disabled.
|
||||
///
|
||||
/// Buttons are disabled by default. To enable a button, set its [onPressed]
|
||||
/// property to a non-null value.
|
||||
bool get enabled => onPressed != null;
|
||||
/// If null the default border's style is [BorderStyle.solid], its
|
||||
/// [BorderSide.width] is 2.0, and its color is a light shade of grey.
|
||||
final BorderSide borderSide;
|
||||
|
||||
@override
|
||||
_OutlineButtonState createState() => _OutlineButtonState();
|
||||
|
||||
Widget build(BuildContext context) {
|
||||
final ButtonThemeData buttonTheme = ButtonTheme.of(context);
|
||||
return _OutlineButton(
|
||||
onPressed: onPressed,
|
||||
brightness: buttonTheme.getBrightness(this),
|
||||
textTheme: textTheme,
|
||||
textColor: buttonTheme.getTextColor(this),
|
||||
disabledTextColor: buttonTheme.getDisabledTextColor(this),
|
||||
color: color,
|
||||
highlightColor: buttonTheme.getHighlightColor(this),
|
||||
splashColor: buttonTheme.getSplashColor(this),
|
||||
highlightElevation: buttonTheme.getHighlightElevation(this),
|
||||
borderSide: borderSide,
|
||||
disabledBorderColor: disabledBorderColor,
|
||||
highlightedBorderColor: highlightedBorderColor ?? buttonTheme.colorScheme.primary,
|
||||
padding: buttonTheme.getPadding(this),
|
||||
shape: buttonTheme.getShape(this),
|
||||
clipBehavior: clipBehavior,
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
@ -256,7 +172,7 @@ class OutlineButton extends StatefulWidget {
|
||||
properties.add(DiagnosticsProperty<Color>('color', color, defaultValue: null));
|
||||
properties.add(DiagnosticsProperty<Color>('highlightColor', highlightColor, defaultValue: null));
|
||||
properties.add(DiagnosticsProperty<Color>('splashColor', splashColor, defaultValue: null));
|
||||
properties.add(DiagnosticsProperty<double>('highlightElevation', highlightElevation, defaultValue: 2.0));
|
||||
properties.add(DiagnosticsProperty<double>('highlightElevation', highlightElevation, defaultValue: null));
|
||||
properties.add(DiagnosticsProperty<BorderSide>('borderSide', borderSide, defaultValue: null));
|
||||
properties.add(DiagnosticsProperty<Color>('disabledBorderColor', disabledBorderColor, defaultValue: null));
|
||||
properties.add(DiagnosticsProperty<Color>('highlightedBorderColor', highlightedBorderColor, defaultValue: null));
|
||||
@ -265,7 +181,107 @@ class OutlineButton extends StatefulWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class _OutlineButtonState extends State<OutlineButton> with SingleTickerProviderStateMixin {
|
||||
// The type of of OutlineButtons created with [OutlineButton.icon].
|
||||
//
|
||||
// This class only exists to give RaisedButtons created with [RaisedButton.icon]
|
||||
// a distinct class for the sake of [ButtonTheme]. It can not be instantiated.
|
||||
class _OutlineButtonWithIcon extends OutlineButton implements MaterialButtonWithIconMixin {
|
||||
_OutlineButtonWithIcon({
|
||||
Key key,
|
||||
@required VoidCallback onPressed,
|
||||
ButtonTextTheme textTheme,
|
||||
Color textColor,
|
||||
Color disabledTextColor,
|
||||
Color color,
|
||||
Color highlightColor,
|
||||
Color splashColor,
|
||||
double highlightElevation,
|
||||
Color highlightedBorderColor,
|
||||
Color disabledBorderColor,
|
||||
BorderSide borderSide,
|
||||
EdgeInsetsGeometry padding,
|
||||
ShapeBorder shape,
|
||||
Clip clipBehavior,
|
||||
@required Widget icon,
|
||||
@required Widget label,
|
||||
}) : assert(highlightElevation == null || highlightElevation >= 0.0),
|
||||
assert(icon != null),
|
||||
assert(label != null),
|
||||
super(
|
||||
key: key,
|
||||
onPressed: onPressed,
|
||||
textTheme: textTheme,
|
||||
textColor: textColor,
|
||||
disabledTextColor: disabledTextColor,
|
||||
color: color,
|
||||
highlightColor: highlightColor,
|
||||
splashColor: splashColor,
|
||||
highlightElevation: highlightElevation,
|
||||
disabledBorderColor: disabledBorderColor,
|
||||
highlightedBorderColor: highlightedBorderColor,
|
||||
borderSide: borderSide,
|
||||
padding: padding,
|
||||
shape: shape,
|
||||
clipBehavior: clipBehavior,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
icon,
|
||||
const SizedBox(width: 8.0),
|
||||
label,
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
class _OutlineButton extends StatefulWidget {
|
||||
const _OutlineButton({
|
||||
Key key,
|
||||
@required this.onPressed,
|
||||
this.brightness,
|
||||
this.textTheme,
|
||||
this.textColor,
|
||||
this.disabledTextColor,
|
||||
this.color,
|
||||
this.highlightColor,
|
||||
this.splashColor,
|
||||
@required this.highlightElevation,
|
||||
this.borderSide,
|
||||
this.disabledBorderColor,
|
||||
@required this.highlightedBorderColor,
|
||||
this.padding,
|
||||
this.shape,
|
||||
this.clipBehavior,
|
||||
this.child,
|
||||
}) : assert(highlightElevation != null && highlightElevation >= 0.0),
|
||||
assert(highlightedBorderColor != null),
|
||||
super(key: key);
|
||||
|
||||
final VoidCallback onPressed;
|
||||
final Brightness brightness;
|
||||
final ButtonTextTheme textTheme;
|
||||
final Color textColor;
|
||||
final Color disabledTextColor;
|
||||
final Color color;
|
||||
final Color splashColor;
|
||||
final Color highlightColor;
|
||||
final double highlightElevation;
|
||||
final BorderSide borderSide;
|
||||
final Color disabledBorderColor;
|
||||
final Color highlightedBorderColor;
|
||||
final EdgeInsetsGeometry padding;
|
||||
final ShapeBorder shape;
|
||||
final Clip clipBehavior;
|
||||
final Widget child;
|
||||
|
||||
bool get enabled => onPressed != null;
|
||||
|
||||
@override
|
||||
_OutlineButtonState createState() => _OutlineButtonState();
|
||||
}
|
||||
|
||||
|
||||
class _OutlineButtonState extends State<_OutlineButton> with SingleTickerProviderStateMixin {
|
||||
AnimationController _controller;
|
||||
Animation<double> _fillAnimation;
|
||||
Animation<double> _elevationAnimation;
|
||||
@ -305,36 +321,8 @@ class _OutlineButtonState extends State<OutlineButton> with SingleTickerProvider
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
ButtonTextTheme _getTextTheme(ButtonThemeData buttonTheme) {
|
||||
return widget.textTheme ?? buttonTheme.textTheme;
|
||||
}
|
||||
|
||||
// TODO(hmuller): this method is the same as FlatButton
|
||||
Color _getTextColor(ThemeData theme, ButtonThemeData buttonTheme) {
|
||||
final Color color = widget.enabled ? widget.textColor : widget.disabledTextColor;
|
||||
if (color != null)
|
||||
return color;
|
||||
|
||||
final bool themeIsDark = theme.brightness == Brightness.dark;
|
||||
switch (_getTextTheme(buttonTheme)) {
|
||||
case ButtonTextTheme.normal:
|
||||
return widget.enabled
|
||||
? (themeIsDark ? Colors.white : Colors.black87)
|
||||
: theme.disabledColor;
|
||||
case ButtonTextTheme.accent:
|
||||
return widget.enabled
|
||||
? theme.accentColor
|
||||
: theme.disabledColor;
|
||||
case ButtonTextTheme.primary:
|
||||
return widget.enabled
|
||||
? theme.buttonColor
|
||||
: (themeIsDark ? Colors.white30 : Colors.black38);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Color _getFillColor(ThemeData theme) {
|
||||
final bool themeIsDark = theme.brightness == Brightness.dark;
|
||||
Color _getFillColor() {
|
||||
final bool themeIsDark = widget.brightness == Brightness.dark;
|
||||
final Color color = widget.color ?? (themeIsDark
|
||||
? const Color(0x00000000)
|
||||
: const Color(0x00FFFFFF));
|
||||
@ -345,35 +333,18 @@ class _OutlineButtonState extends State<OutlineButton> with SingleTickerProvider
|
||||
return colorTween.evaluate(_fillAnimation);
|
||||
}
|
||||
|
||||
// TODO(hmuller): this method is the same as FlatButton
|
||||
Color _getSplashColor(ThemeData theme, ButtonThemeData buttonTheme) {
|
||||
if (widget.splashColor != null)
|
||||
return widget.splashColor;
|
||||
|
||||
switch (_getTextTheme(buttonTheme)) {
|
||||
case ButtonTextTheme.normal:
|
||||
case ButtonTextTheme.accent:
|
||||
return theme.splashColor;
|
||||
case ButtonTextTheme.primary:
|
||||
return theme.brightness == Brightness.dark
|
||||
? Colors.white12
|
||||
: theme.primaryColor.withOpacity(0.12);
|
||||
}
|
||||
return Colors.transparent;
|
||||
}
|
||||
|
||||
BorderSide _getOutline(ThemeData theme, ButtonThemeData buttonTheme) {
|
||||
final bool themeIsDark = theme.brightness == Brightness.dark;
|
||||
BorderSide _getOutline() {
|
||||
final bool isDark = widget.brightness == Brightness.dark;
|
||||
if (widget.borderSide?.style == BorderStyle.none)
|
||||
return widget.borderSide;
|
||||
|
||||
final Color color = widget.enabled
|
||||
? (_pressed
|
||||
? widget.highlightedBorderColor ?? theme.primaryColor
|
||||
? widget.highlightedBorderColor
|
||||
: (widget.borderSide?.color ??
|
||||
(themeIsDark ? Colors.grey[600] : Colors.grey[200])))
|
||||
(isDark ? Colors.grey[600] : Colors.grey[200])))
|
||||
: (widget.disabledBorderColor ??
|
||||
(themeIsDark ? Colors.grey[800] : Colors.grey[100]));
|
||||
(isDark ? Colors.grey[800] : Colors.grey[100]));
|
||||
|
||||
return BorderSide(
|
||||
color: color,
|
||||
@ -390,19 +361,14 @@ class _OutlineButtonState extends State<OutlineButton> with SingleTickerProvider
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final ThemeData theme = Theme.of(context);
|
||||
final ButtonThemeData buttonTheme = ButtonTheme.of(context);
|
||||
final Color textColor = _getTextColor(theme, buttonTheme);
|
||||
final Color splashColor = _getSplashColor(theme, buttonTheme);
|
||||
|
||||
return AnimatedBuilder(
|
||||
animation: _controller,
|
||||
builder: (BuildContext context, Widget child) {
|
||||
return RaisedButton(
|
||||
textColor: textColor,
|
||||
textColor: widget.textColor,
|
||||
disabledTextColor: widget.disabledTextColor,
|
||||
color: _getFillColor(theme),
|
||||
splashColor: splashColor,
|
||||
color: _getFillColor(),
|
||||
splashColor: widget.splashColor,
|
||||
highlightColor: widget.highlightColor,
|
||||
disabledColor: Colors.transparent,
|
||||
onPressed: widget.onPressed,
|
||||
@ -420,8 +386,8 @@ class _OutlineButtonState extends State<OutlineButton> with SingleTickerProvider
|
||||
},
|
||||
padding: widget.padding,
|
||||
shape: _OutlineBorder(
|
||||
shape: widget.shape ?? buttonTheme.shape,
|
||||
side: _getOutline(theme, buttonTheme),
|
||||
shape: widget.shape,
|
||||
side: _getOutline(),
|
||||
),
|
||||
clipBehavior: widget.clipBehavior,
|
||||
animationDuration: _kElevationDuration,
|
||||
|
@ -7,8 +7,7 @@ import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'button.dart';
|
||||
import 'button_theme.dart';
|
||||
import 'colors.dart';
|
||||
import 'constants.dart';
|
||||
import 'material_button.dart';
|
||||
import 'theme.dart';
|
||||
import 'theme_data.dart';
|
||||
|
||||
@ -41,38 +40,57 @@ import 'theme_data.dart';
|
||||
/// * [InkWell], which implements the ink splash part of a flat button.
|
||||
/// * [RawMaterialButton], the widget this widget is based on.
|
||||
/// * <https://material.google.com/components/buttons.html>
|
||||
class RaisedButton extends StatelessWidget {
|
||||
class RaisedButton extends MaterialButton {
|
||||
/// Create a filled button.
|
||||
///
|
||||
/// The [elevation], [highlightElevation], [disabledElevation], and
|
||||
/// [clipBehavior] arguments must not be null.
|
||||
const RaisedButton({
|
||||
Key key,
|
||||
@required this.onPressed,
|
||||
this.onHighlightChanged,
|
||||
this.textTheme,
|
||||
this.textColor,
|
||||
this.disabledTextColor,
|
||||
this.color,
|
||||
this.disabledColor,
|
||||
this.highlightColor,
|
||||
this.splashColor,
|
||||
this.colorBrightness,
|
||||
this.elevation = 2.0,
|
||||
this.highlightElevation = 8.0,
|
||||
this.disabledElevation = 0.0,
|
||||
this.padding,
|
||||
this.shape,
|
||||
this.clipBehavior = Clip.none,
|
||||
this.materialTapTargetSize,
|
||||
this.animationDuration = kThemeChangeDuration,
|
||||
this.child,
|
||||
}) : assert(elevation != null),
|
||||
assert(highlightElevation != null),
|
||||
assert(disabledElevation != null),
|
||||
assert(animationDuration != null),
|
||||
assert(clipBehavior != null),
|
||||
super(key: key);
|
||||
@required VoidCallback onPressed,
|
||||
ValueChanged<bool> onHighlightChanged,
|
||||
ButtonTextTheme textTheme,
|
||||
Color textColor,
|
||||
Color disabledTextColor,
|
||||
Color color,
|
||||
Color disabledColor,
|
||||
Color highlightColor,
|
||||
Color splashColor,
|
||||
Brightness colorBrightness,
|
||||
double elevation,
|
||||
double highlightElevation,
|
||||
double disabledElevation,
|
||||
EdgeInsetsGeometry padding,
|
||||
ShapeBorder shape,
|
||||
Clip clipBehavior = Clip.none,
|
||||
MaterialTapTargetSize materialTapTargetSize,
|
||||
Duration animationDuration,
|
||||
Widget child,
|
||||
}) : assert(elevation == null || elevation >= 0.0),
|
||||
assert(highlightElevation == null || highlightElevation >= 0.0),
|
||||
assert(disabledElevation == null || disabledElevation >= 0.0),
|
||||
super(
|
||||
key: key,
|
||||
onPressed: onPressed,
|
||||
onHighlightChanged: onHighlightChanged,
|
||||
textTheme: textTheme,
|
||||
textColor: textColor,
|
||||
disabledTextColor: disabledTextColor,
|
||||
color: color,
|
||||
disabledColor: disabledColor,
|
||||
highlightColor: highlightColor,
|
||||
splashColor: splashColor,
|
||||
colorBrightness: colorBrightness,
|
||||
elevation: elevation,
|
||||
highlightElevation: highlightElevation,
|
||||
disabledElevation: disabledElevation,
|
||||
padding: padding,
|
||||
shape: shape,
|
||||
clipBehavior: clipBehavior,
|
||||
materialTapTargetSize: materialTapTargetSize,
|
||||
animationDuration: animationDuration,
|
||||
child: child,
|
||||
);
|
||||
|
||||
/// Create a filled button from a pair of widgets that serve as the button's
|
||||
/// [icon] and [label].
|
||||
@ -82,325 +100,51 @@ class RaisedButton extends StatelessWidget {
|
||||
///
|
||||
/// The [elevation], [highlightElevation], [disabledElevation], [icon],
|
||||
/// [label], and [clipBehavior] arguments must not be null.
|
||||
RaisedButton.icon({
|
||||
factory RaisedButton.icon({
|
||||
Key key,
|
||||
@required this.onPressed,
|
||||
this.onHighlightChanged,
|
||||
this.textTheme,
|
||||
this.textColor,
|
||||
this.disabledTextColor,
|
||||
this.color,
|
||||
this.disabledColor,
|
||||
this.highlightColor,
|
||||
this.splashColor,
|
||||
this.colorBrightness,
|
||||
this.elevation = 2.0,
|
||||
this.highlightElevation = 8.0,
|
||||
this.disabledElevation = 0.0,
|
||||
this.shape,
|
||||
this.clipBehavior = Clip.none,
|
||||
this.materialTapTargetSize,
|
||||
this.animationDuration = kThemeChangeDuration,
|
||||
@required VoidCallback onPressed,
|
||||
ValueChanged<bool> onHighlightChanged,
|
||||
ButtonTextTheme textTheme,
|
||||
Color textColor,
|
||||
Color disabledTextColor,
|
||||
Color color,
|
||||
Color disabledColor,
|
||||
Color highlightColor,
|
||||
Color splashColor,
|
||||
Brightness colorBrightness,
|
||||
double elevation,
|
||||
double highlightElevation,
|
||||
double disabledElevation,
|
||||
ShapeBorder shape,
|
||||
Clip clipBehavior,
|
||||
MaterialTapTargetSize materialTapTargetSize,
|
||||
Duration animationDuration,
|
||||
@required Widget icon,
|
||||
@required Widget label,
|
||||
}) : assert(elevation != null),
|
||||
assert(highlightElevation != null),
|
||||
assert(disabledElevation != null),
|
||||
assert(icon != null),
|
||||
assert(label != null),
|
||||
assert(animationDuration != null),
|
||||
assert(clipBehavior != null),
|
||||
padding = const EdgeInsetsDirectional.only(start: 12.0, end: 16.0),
|
||||
child = Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
icon,
|
||||
const SizedBox(width: 8.0),
|
||||
label,
|
||||
],
|
||||
),
|
||||
super(key: key);
|
||||
}) = _RaisedButtonWithIcon;
|
||||
|
||||
/// Called when the button is tapped or otherwise activated.
|
||||
///
|
||||
/// If this is set to null, the button will be disabled, see [enabled].
|
||||
final VoidCallback onPressed;
|
||||
|
||||
/// Called by the underlying [InkWell] widget's [InkWell.onHighlightChanged]
|
||||
/// callback.
|
||||
final ValueChanged<bool> onHighlightChanged;
|
||||
|
||||
/// Defines the button's base colors, and the defaults for the button's minimum
|
||||
/// size, internal padding, and shape.
|
||||
///
|
||||
/// Defaults to `ButtonTheme.of(context).textTheme`.
|
||||
final ButtonTextTheme textTheme;
|
||||
|
||||
/// The color to use for this button's text.
|
||||
///
|
||||
/// The button's [Material.textStyle] will be the current theme's button
|
||||
/// text style, [ThemeData.textTheme.button], configured with this color.
|
||||
///
|
||||
/// The default text color depends on the button theme's text theme,
|
||||
/// [ButtonThemeData.textTheme].
|
||||
///
|
||||
/// See also:
|
||||
/// * [disabledTextColor], the text color to use when the button has been
|
||||
/// disabled.
|
||||
final Color textColor;
|
||||
|
||||
/// The color to use for this button's text when the button is disabled.
|
||||
///
|
||||
/// The button's [Material.textStyle] will be the current theme's button
|
||||
/// text style, [ThemeData.textTheme.button], configured with this color.
|
||||
///
|
||||
/// The default value is the theme's disabled color,
|
||||
/// [ThemeData.disabledColor].
|
||||
///
|
||||
/// See also:
|
||||
/// * [textColor] - The color to use for this button's text when the button is [enabled].
|
||||
final Color disabledTextColor;
|
||||
|
||||
/// The button's fill color, displayed by its [Material], while it
|
||||
/// is in its default (unpressed, [enabled]) state.
|
||||
///
|
||||
/// The default fill color is the theme's button color, [ThemeData.buttonColor].
|
||||
///
|
||||
/// Typically the default color will be overidden with a Material color,
|
||||
/// for example:
|
||||
///
|
||||
/// ```dart
|
||||
/// RaisedButton(
|
||||
/// color: Colors.blue,
|
||||
/// onPressed: _handleTap,
|
||||
/// child: Text('DEMO'),
|
||||
/// ),
|
||||
/// ```
|
||||
///
|
||||
/// See also:
|
||||
/// * [disabledColor] - the fill color of the button when the button is disabled.
|
||||
final Color color;
|
||||
|
||||
/// The fill color of the button when the button is disabled.
|
||||
///
|
||||
/// The default value of this color is the theme's disabled color,
|
||||
/// [ThemeData.disabledColor].
|
||||
///
|
||||
/// See also:
|
||||
/// * [color] - the fill color of the button when the button is [enabled].
|
||||
final Color disabledColor;
|
||||
|
||||
/// The splash color of the button's [InkWell].
|
||||
///
|
||||
/// The ink splash indicates that the button has been touched. It
|
||||
/// appears on top of the button's child and spreads in an expanding
|
||||
/// circle beginning where the touch occurred.
|
||||
///
|
||||
/// The default splash color is the current theme's splash color,
|
||||
/// [ThemeData.splashColor].
|
||||
///
|
||||
/// The appearance of the splash can be configured with the theme's splash
|
||||
/// factory, [ThemeData.splashFactory].
|
||||
final Color splashColor;
|
||||
|
||||
/// The highlight color of the button's [InkWell].
|
||||
///
|
||||
/// The highlight indicates that the button is actively being pressed. It
|
||||
/// appears on top of the button's child and quickly spreads to fill
|
||||
/// the button, and then fades out.
|
||||
///
|
||||
/// If [textTheme] is [ButtonTextTheme.primary], the default highlight color is
|
||||
/// transparent (in other words the highlight doesn't appear). Otherwise it's
|
||||
/// the current theme's highlight color, [ThemeData.highlightColor].
|
||||
final Color highlightColor;
|
||||
|
||||
/// The z-coordinate at which to place this button. This controls the size of
|
||||
/// the shadow below the raised button.
|
||||
///
|
||||
/// Defaults to 2, the appropriate elevation for raised buttons.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [FlatButton], a button with no elevation or fill color.
|
||||
/// * [disabledElevation], the elevation when the button is disabled.
|
||||
/// * [highlightElevation], the elevation when the button is pressed.
|
||||
final double elevation;
|
||||
|
||||
/// The elevation for the button's [Material] when the button
|
||||
/// is [enabled] but not pressed.
|
||||
///
|
||||
/// Defaults to 2.0.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [highlightElevation], the default elevation.
|
||||
/// * [disabledElevation], the elevation when the button is disabled.
|
||||
|
||||
/// The elevation for the button's [Material] when the button
|
||||
/// is [enabled] and pressed.
|
||||
///
|
||||
/// This controls the size of the shadow below the button. When a tap
|
||||
/// down gesture occurs within the button, its [InkWell] displays a
|
||||
/// [highlightColor] "highlight".
|
||||
///
|
||||
/// Defaults to 8.0.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [elevation], the default elevation.
|
||||
/// * [disabledElevation], the elevation when the button is disabled.
|
||||
final double highlightElevation;
|
||||
|
||||
/// The elevation for the button's [Material] when the button
|
||||
/// is not [enabled].
|
||||
///
|
||||
/// Defaults to 0.0.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [elevation], the default elevation.
|
||||
/// * [highlightElevation], the elevation when the button is pressed.
|
||||
final double disabledElevation;
|
||||
|
||||
/// The theme brightness to use for this button.
|
||||
///
|
||||
/// Defaults to the theme's brightness, [ThemeData.brightness].
|
||||
final Brightness colorBrightness;
|
||||
|
||||
/// The button's label.
|
||||
///
|
||||
/// Often a [Text] widget in all caps.
|
||||
final Widget child;
|
||||
|
||||
/// Whether the button is enabled or disabled.
|
||||
///
|
||||
/// Buttons are disabled by default. To enable a button, set its [onPressed]
|
||||
/// property to a non-null value.
|
||||
bool get enabled => onPressed != null;
|
||||
|
||||
/// The internal padding for the button's [child].
|
||||
///
|
||||
/// Defaults to the value from the current [ButtonTheme],
|
||||
/// [ButtonThemeData.padding].
|
||||
final EdgeInsetsGeometry padding;
|
||||
|
||||
/// The shape of the button's [Material].
|
||||
///
|
||||
/// The button's highlight and splash are clipped to this shape. If the
|
||||
/// button has an elevation, then its drop shadow is defined by this
|
||||
/// shape as well.
|
||||
final ShapeBorder shape;
|
||||
|
||||
/// {@macro flutter.widgets.Clip}
|
||||
final Clip clipBehavior;
|
||||
|
||||
/// Defines the duration of animated changes for [shape] and [elevation].
|
||||
///
|
||||
/// The default value is [kThemeChangeDuration].
|
||||
final Duration animationDuration;
|
||||
|
||||
/// Configures the minimum size of the tap target.
|
||||
///
|
||||
/// Defaults to [ThemeData.materialTapTargetSize].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [MaterialTapTargetSize], for a description of how this affects tap targets.
|
||||
final MaterialTapTargetSize materialTapTargetSize;
|
||||
|
||||
Brightness _getBrightness(ThemeData theme) {
|
||||
return colorBrightness ?? theme.brightness;
|
||||
}
|
||||
|
||||
ButtonTextTheme _getTextTheme(ButtonThemeData buttonTheme) {
|
||||
return textTheme ?? buttonTheme.textTheme;
|
||||
}
|
||||
|
||||
Color _getFillColor(ThemeData theme, ButtonThemeData buttonTheme) {
|
||||
final Color fillColor = enabled ? color : disabledColor;
|
||||
if (fillColor != null)
|
||||
return fillColor;
|
||||
|
||||
final bool themeIsDark = _getBrightness(theme) == Brightness.dark;
|
||||
switch (_getTextTheme(buttonTheme)) {
|
||||
case ButtonTextTheme.normal:
|
||||
case ButtonTextTheme.accent:
|
||||
return enabled
|
||||
? theme.buttonColor
|
||||
: theme.disabledColor;
|
||||
case ButtonTextTheme.primary:
|
||||
return enabled
|
||||
? theme.buttonColor
|
||||
: (themeIsDark ? Colors.white12 : Colors.black12);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Color _getTextColor(ThemeData theme, ButtonThemeData buttonTheme, Color fillColor) {
|
||||
final Color color = enabled ? textColor : disabledTextColor;
|
||||
if (color != null)
|
||||
return color;
|
||||
|
||||
final bool themeIsDark = _getBrightness(theme) == Brightness.dark;
|
||||
final bool fillIsDark = fillColor != null
|
||||
? ThemeData.estimateBrightnessForColor(fillColor) == Brightness.dark
|
||||
: themeIsDark;
|
||||
|
||||
switch (_getTextTheme(buttonTheme)) {
|
||||
case ButtonTextTheme.normal:
|
||||
return enabled
|
||||
? (themeIsDark ? Colors.white : Colors.black87)
|
||||
: theme.disabledColor;
|
||||
case ButtonTextTheme.accent:
|
||||
return enabled
|
||||
? theme.accentColor
|
||||
: theme.disabledColor;
|
||||
case ButtonTextTheme.primary:
|
||||
return enabled
|
||||
? (fillIsDark ? Colors.white : Colors.black)
|
||||
: (themeIsDark ? Colors.white30 : Colors.black38);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Color _getHighlightColor(ThemeData theme, ButtonThemeData buttonTheme) {
|
||||
if (highlightColor != null)
|
||||
return highlightColor;
|
||||
|
||||
switch (_getTextTheme(buttonTheme)) {
|
||||
case ButtonTextTheme.normal:
|
||||
case ButtonTextTheme.accent:
|
||||
return theme.highlightColor;
|
||||
case ButtonTextTheme.primary:
|
||||
return Colors.transparent;
|
||||
}
|
||||
return Colors.transparent;
|
||||
}
|
||||
|
||||
@override
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final ThemeData theme = Theme.of(context);
|
||||
final ButtonThemeData buttonTheme = ButtonTheme.of(context);
|
||||
final Color fillColor = _getFillColor(theme, buttonTheme);
|
||||
final Color textColor = _getTextColor(theme, buttonTheme, fillColor);
|
||||
|
||||
return RawMaterialButton(
|
||||
onPressed: onPressed,
|
||||
onHighlightChanged: onHighlightChanged,
|
||||
fillColor: fillColor,
|
||||
textStyle: theme.textTheme.button.copyWith(color: textColor),
|
||||
highlightColor: _getHighlightColor(theme, buttonTheme),
|
||||
splashColor: splashColor ?? theme.splashColor,
|
||||
elevation: elevation,
|
||||
highlightElevation: highlightElevation,
|
||||
disabledElevation: disabledElevation,
|
||||
padding: padding ?? buttonTheme.padding,
|
||||
constraints: buttonTheme.constraints,
|
||||
shape: shape ?? buttonTheme.shape,
|
||||
clipBehavior: clipBehavior,
|
||||
animationDuration: animationDuration,
|
||||
clipBehavior: clipBehavior ?? Clip.none,
|
||||
fillColor: buttonTheme.getFillColor(this),
|
||||
textStyle: theme.textTheme.button.copyWith(color: buttonTheme.getTextColor(this)),
|
||||
highlightColor: buttonTheme.getHighlightColor(this),
|
||||
splashColor: buttonTheme.getSplashColor(this),
|
||||
elevation: buttonTheme.getElevation(this),
|
||||
highlightElevation: buttonTheme.getHighlightElevation(this),
|
||||
disabledElevation: buttonTheme.getDisabledElevation(this),
|
||||
padding: buttonTheme.getPadding(this),
|
||||
constraints: buttonTheme.getConstraints(this),
|
||||
shape: buttonTheme.getShape(this),
|
||||
animationDuration: buttonTheme.getAnimationDuration(this),
|
||||
materialTapTargetSize: buttonTheme.getMaterialTapTargetSize(this),
|
||||
child: child,
|
||||
materialTapTargetSize: materialTapTargetSize ?? theme.materialTapTargetSize,
|
||||
);
|
||||
}
|
||||
|
||||
@ -422,3 +166,64 @@ class RaisedButton extends StatelessWidget {
|
||||
properties.add(DiagnosticsProperty<ShapeBorder>('shape', shape, defaultValue: null));
|
||||
}
|
||||
}
|
||||
|
||||
/// The type of of RaisedButtons created with [RaisedButton.icon].
|
||||
///
|
||||
/// This class only exists to give RaisedButtons created with [RaisedButton.icon]
|
||||
/// a distinct class for the sake of [ButtonTheme]. It can not be instantiated.
|
||||
class _RaisedButtonWithIcon extends RaisedButton implements MaterialButtonWithIconMixin {
|
||||
_RaisedButtonWithIcon({
|
||||
Key key,
|
||||
@required VoidCallback onPressed,
|
||||
ValueChanged<bool> onHighlightChanged,
|
||||
ButtonTextTheme textTheme,
|
||||
Color textColor,
|
||||
Color disabledTextColor,
|
||||
Color color,
|
||||
Color disabledColor,
|
||||
Color highlightColor,
|
||||
Color splashColor,
|
||||
Brightness colorBrightness,
|
||||
double elevation,
|
||||
double highlightElevation,
|
||||
double disabledElevation,
|
||||
ShapeBorder shape,
|
||||
Clip clipBehavior = Clip.none,
|
||||
MaterialTapTargetSize materialTapTargetSize,
|
||||
Duration animationDuration,
|
||||
@required Widget icon,
|
||||
@required Widget label,
|
||||
}) : assert(elevation == null || elevation >= 0.0),
|
||||
assert(highlightElevation == null || highlightElevation >= 0.0),
|
||||
assert(disabledElevation == null || disabledElevation >= 0.0),
|
||||
assert(icon != null),
|
||||
assert(label != null),
|
||||
super(
|
||||
key: key,
|
||||
onPressed: onPressed,
|
||||
onHighlightChanged: onHighlightChanged,
|
||||
textTheme: textTheme,
|
||||
textColor: textColor,
|
||||
disabledTextColor: disabledTextColor,
|
||||
color: color,
|
||||
disabledColor: disabledColor,
|
||||
highlightColor: highlightColor,
|
||||
splashColor: splashColor,
|
||||
colorBrightness: colorBrightness,
|
||||
elevation: elevation,
|
||||
highlightElevation: highlightElevation,
|
||||
disabledElevation: disabledElevation,
|
||||
shape: shape,
|
||||
clipBehavior: clipBehavior,
|
||||
materialTapTargetSize: materialTapTargetSize,
|
||||
animationDuration: animationDuration,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
icon,
|
||||
const SizedBox(width: 8.0),
|
||||
label,
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -12,8 +12,8 @@ import 'icons.dart';
|
||||
import 'ink_well.dart';
|
||||
import 'material.dart';
|
||||
import 'material_localizations.dart';
|
||||
import 'text_theme.dart';
|
||||
import 'theme.dart';
|
||||
import 'typography.dart';
|
||||
|
||||
// TODO(dragostis): Missing functionality:
|
||||
// * mobile horizontal mode with adding/removing steps
|
||||
|
540
packages/flutter/lib/src/material/text_theme.dart
Normal file
540
packages/flutter/lib/src/material/text_theme.dart
Normal file
@ -0,0 +1,540 @@
|
||||
// Copyright 2018 The Chromium 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/foundation.dart';
|
||||
import 'package:flutter/painting.dart';
|
||||
|
||||
import 'typography.dart';
|
||||
|
||||
/// Material design text theme.
|
||||
///
|
||||
/// Definitions for the various typographical styles found in material design
|
||||
/// (e.g., button, caption). Rather than creating a [TextTheme] directly,
|
||||
/// you can obtain an instance as [Typography.black] or [Typography.white].
|
||||
///
|
||||
/// To obtain the current text theme, call [Theme.of] with the current
|
||||
/// [BuildContext] and read the [ThemeData.textTheme] property.
|
||||
///
|
||||
/// The Material Design typography scheme was signficantly changed in the
|
||||
/// current (2018) version of the specification
|
||||
/// (https://material.io/design/typography).
|
||||
///
|
||||
/// The 2018 spec has thirteen text styles:
|
||||
/// ```
|
||||
/// NAME SIZE WEIGHT SPACING
|
||||
/// headline1 96.0 light -1.5
|
||||
/// headline2 60.0 light -0.5
|
||||
/// headline3 48.0 normal 0.0
|
||||
/// headline4 34.0 normal 0.25
|
||||
/// headline5 24.0 normal 0.0
|
||||
/// headline6 20.0 medium 0.15
|
||||
/// subtitle1 16.0 normal 0.15
|
||||
/// subtitle2 14.0 medium 0.1
|
||||
/// body1 16.0 normal 0.5
|
||||
/// body2 14.0 normal 0.25
|
||||
/// button 14.0 medium 0.75
|
||||
/// caption 12.0 normal 0.4
|
||||
/// overline 10.0 normal 1.5
|
||||
///
|
||||
/// ```
|
||||
/// Where "light" is `FontWeight.w300`, "normal" is `FontWeight.w400` and
|
||||
/// "medium" is `FontWeight.w500`.
|
||||
///
|
||||
/// The [TextTheme] API is based on the original material (2014)
|
||||
/// design spec, which used different text style names. For backwards
|
||||
/// compatability's sake, this API continues to use the original
|
||||
/// names. The table below should help with understanding the API in
|
||||
/// terms of the 2018 material spec.
|
||||
///
|
||||
/// Each of the [TextTheme] text styles corresponds to one of the
|
||||
/// styles from 2018 spec. By default, the font sizes, font weights
|
||||
/// and letter spacings have not changed from their original,
|
||||
/// 2014, values.
|
||||
/// ```
|
||||
/// NAME SIZE WEIGHT SPACING 2018 NAME
|
||||
/// display4 112.0 thin 0.0 headline1
|
||||
/// display3 56.0 normal 0.0 headline2
|
||||
/// display2 45.0 normal 0.0 headline3
|
||||
/// display1 34.0 normal 0.0 headline4
|
||||
/// headline 24.0 normal 0.0 headline5
|
||||
/// title 20.0 medium 0.0 headline6
|
||||
/// subhead 16.0 normal 0.0 subtitle1
|
||||
/// body2 14.0 medium 0.0 body1
|
||||
/// body1 14.0 normal 0.0 body2
|
||||
/// caption 12.0 normal 0.0 caption
|
||||
/// button 14.0 medium 0.0 button
|
||||
/// subtitle 14.0 medium 0.0 subtitle2
|
||||
/// overline 10.0 normal 0.0 overline
|
||||
/// ```
|
||||
///
|
||||
/// Where "thin" is `FontWeight.w100`, "normal" is `FontWeight.w400` and
|
||||
/// "medium" is `FontWeight.w500`. Letter spacing for all of the original
|
||||
/// text styles was 0.0.
|
||||
///
|
||||
/// To configure a [Theme] for the new sizes, weights, and letter spacings,
|
||||
/// initialize its [ThemeData.typography] value with a [Typography] that
|
||||
/// object that specifies the 2018 versions of the geometry themes:
|
||||
/// [Typography.englishLike2018], [Typography.dense2018],
|
||||
/// and [Typography.tall2018].
|
||||
///
|
||||
/// The following image [from the material design
|
||||
/// specification](https://material.io/go/design-typography#typography-styles)
|
||||
/// shows the recommended styles for each of the properties of a [TextTheme].
|
||||
/// This image uses the `Roboto` font, which is the font used on Android. On
|
||||
/// iOS, the [San Francisco
|
||||
/// font](https://developer.apple.com/ios/human-interface-guidelines/visual-design/typography/)
|
||||
/// is automatically used instead.
|
||||
///
|
||||
/// 
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [Typography], the class that generates [TextTheme]s appropriate for a platform.
|
||||
/// * [Theme], for other aspects of a material design application that can be
|
||||
/// globally adjusted, such as the color scheme.
|
||||
/// * <http://material.google.com/style/typography.html>
|
||||
@immutable
|
||||
class TextTheme extends Diagnosticable {
|
||||
/// Creates a text theme that uses the given values.
|
||||
///
|
||||
/// Rather than creating a new text theme, consider using [Typography.black]
|
||||
/// or [Typography.white], which implement the typography styles in the
|
||||
/// material design specification:
|
||||
///
|
||||
/// <https://material.google.com/style/typography.html#typography-styles>
|
||||
///
|
||||
/// If you do decide to create your own text theme, consider using one of
|
||||
/// those predefined themes as a starting point for [copyWith] or [apply].
|
||||
const TextTheme({
|
||||
this.display4,
|
||||
this.display3,
|
||||
this.display2,
|
||||
this.display1,
|
||||
this.headline,
|
||||
this.title,
|
||||
this.subhead,
|
||||
this.body2,
|
||||
this.body1,
|
||||
this.caption,
|
||||
this.button,
|
||||
this.subtitle,
|
||||
this.overline,
|
||||
});
|
||||
|
||||
/// Extremely large text.
|
||||
///
|
||||
/// The font size is 112 pixels.
|
||||
final TextStyle display4;
|
||||
|
||||
/// Very, very large text.
|
||||
///
|
||||
/// Used for the date in the dialog shown by [showDatePicker].
|
||||
final TextStyle display3;
|
||||
|
||||
/// Very large text.
|
||||
final TextStyle display2;
|
||||
|
||||
/// Large text.
|
||||
final TextStyle display1;
|
||||
|
||||
/// Used for large text in dialogs (e.g., the month and year in the dialog
|
||||
/// shown by [showDatePicker]).
|
||||
final TextStyle headline;
|
||||
|
||||
/// Used for the primary text in app bars and dialogs (e.g., [AppBar.title]
|
||||
/// and [AlertDialog.title]).
|
||||
final TextStyle title;
|
||||
|
||||
/// Used for the primary text in lists (e.g., [ListTile.title]).
|
||||
final TextStyle subhead;
|
||||
|
||||
/// Used for emphasizing text that would otherwise be [body1].
|
||||
final TextStyle body2;
|
||||
|
||||
/// Used for the default text style for [Material].
|
||||
final TextStyle body1;
|
||||
|
||||
/// Used for auxiliary text associated with images.
|
||||
final TextStyle caption;
|
||||
|
||||
/// Used for text on [RaisedButton] and [FlatButton].
|
||||
final TextStyle button;
|
||||
|
||||
/// For medium emphasis text that's a little smaller than [subhead].
|
||||
final TextStyle subtitle;
|
||||
|
||||
/// The smallest style,
|
||||
///
|
||||
/// Typically used for captions or to introduce a (larger) headline.
|
||||
final TextStyle overline;
|
||||
|
||||
/// Creates a copy of this text theme but with the given fields replaced with
|
||||
/// the new values.
|
||||
///
|
||||
/// Consider using [Typography.black] or [Typography.white], which implement
|
||||
/// the typography styles in the material design specification, as a starting
|
||||
/// point.
|
||||
///
|
||||
/// ## Sample code
|
||||
///
|
||||
/// ```dart
|
||||
/// /// A Widget that sets the ambient theme's title text color for its
|
||||
/// /// descendants, while leaving other ambient theme attributes alone.
|
||||
/// class TitleColorThemeCopy extends StatelessWidget {
|
||||
/// TitleColorThemeCopy({Key key, this.child, this.titleColor}) : super(key: key);
|
||||
///
|
||||
/// final Color titleColor;
|
||||
/// final Widget child;
|
||||
///
|
||||
/// @override
|
||||
/// Widget build(BuildContext context) {
|
||||
/// final ThemeData theme = Theme.of(context);
|
||||
/// return Theme(
|
||||
/// data: theme.copyWith(
|
||||
/// textTheme: theme.textTheme.copyWith(
|
||||
/// title: theme.textTheme.title.copyWith(
|
||||
/// color: titleColor,
|
||||
/// ),
|
||||
/// ),
|
||||
/// ),
|
||||
/// child: child,
|
||||
/// );
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [merge] is used instead of [copyWith] when you want to merge all
|
||||
/// of the fields of a TextTheme instead of individual fields.
|
||||
TextTheme copyWith({
|
||||
TextStyle display4,
|
||||
TextStyle display3,
|
||||
TextStyle display2,
|
||||
TextStyle display1,
|
||||
TextStyle headline,
|
||||
TextStyle title,
|
||||
TextStyle subhead,
|
||||
TextStyle body2,
|
||||
TextStyle body1,
|
||||
TextStyle caption,
|
||||
TextStyle button,
|
||||
TextStyle subtitle,
|
||||
TextStyle overline,
|
||||
}) {
|
||||
return TextTheme(
|
||||
display4: display4 ?? this.display4,
|
||||
display3: display3 ?? this.display3,
|
||||
display2: display2 ?? this.display2,
|
||||
display1: display1 ?? this.display1,
|
||||
headline: headline ?? this.headline,
|
||||
title: title ?? this.title,
|
||||
subhead: subhead ?? this.subhead,
|
||||
body2: body2 ?? this.body2,
|
||||
body1: body1 ?? this.body1,
|
||||
caption: caption ?? this.caption,
|
||||
button: button ?? this.button,
|
||||
subtitle: subtitle ?? this.subtitle,
|
||||
overline: overline ?? this.overline,
|
||||
);
|
||||
}
|
||||
|
||||
/// Creates a new [TextTheme] where each text style from this object has been
|
||||
/// merged with the matching text style from the `other` object.
|
||||
///
|
||||
/// The merging is done by calling [TextStyle.merge] on each respective pair
|
||||
/// of text styles from this and the [other] text themes and is subject to
|
||||
/// the value of [TextStyle.inherit] flag. For more details, see the
|
||||
/// documentation on [TextStyle.merge] and [TextStyle.inherit].
|
||||
///
|
||||
/// If this theme, or the `other` theme has members that are null, then the
|
||||
/// non-null one (if any) is used. If the `other` theme is itself null, then
|
||||
/// this [TextTheme] is returned unchanged. If values in both are set, then
|
||||
/// the values are merged using [TextStyle.merge].
|
||||
///
|
||||
/// This is particularly useful if one [TextTheme] defines one set of
|
||||
/// properties and another defines a different set, e.g. having colors
|
||||
/// defined in one text theme and font sizes in another, or when one
|
||||
/// [TextTheme] has only some fields defined, and you want to define the rest
|
||||
/// by merging it with a default theme.
|
||||
///
|
||||
/// ## Sample code
|
||||
///
|
||||
/// ```dart
|
||||
/// /// A Widget that sets the ambient theme's title text color for its
|
||||
/// /// descendants, while leaving other ambient theme attributes alone.
|
||||
/// class TitleColorTheme extends StatelessWidget {
|
||||
/// TitleColorTheme({Key key, this.child, this.titleColor}) : super(key: key);
|
||||
///
|
||||
/// final Color titleColor;
|
||||
/// final Widget child;
|
||||
///
|
||||
/// @override
|
||||
/// Widget build(BuildContext context) {
|
||||
/// ThemeData theme = Theme.of(context);
|
||||
/// // This partialTheme is incomplete: it only has the title style
|
||||
/// // defined. Just replacing theme.textTheme with partialTheme would
|
||||
/// // set the title, but everything else would be null. This isn't very
|
||||
/// // useful, so merge it with the existing theme to keep all of the
|
||||
/// // preexisting definitions for the other styles.
|
||||
/// TextTheme partialTheme = TextTheme(title: TextStyle(color: titleColor));
|
||||
/// theme = theme.copyWith(textTheme: theme.textTheme.merge(partialTheme));
|
||||
/// return Theme(data: theme, child: child);
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [copyWith] is used instead of [merge] when you wish to override
|
||||
/// individual fields in the [TextTheme] instead of merging all of the
|
||||
/// fields of two [TextTheme]s.
|
||||
TextTheme merge(TextTheme other) {
|
||||
if (other == null)
|
||||
return this;
|
||||
return copyWith(
|
||||
display4: display4?.merge(other.display4) ?? other.display4,
|
||||
display3: display3?.merge(other.display3) ?? other.display3,
|
||||
display2: display2?.merge(other.display2) ?? other.display2,
|
||||
display1: display1?.merge(other.display1) ?? other.display1,
|
||||
headline: headline?.merge(other.headline) ?? other.headline,
|
||||
title: title?.merge(other.title) ?? other.title,
|
||||
subhead: subhead?.merge(other.subhead) ?? other.subhead,
|
||||
body2: body2?.merge(other.body2) ?? other.body2,
|
||||
body1: body1?.merge(other.body1) ?? other.body1,
|
||||
caption: caption?.merge(other.caption) ?? other.caption,
|
||||
button: button?.merge(other.button) ?? other.button,
|
||||
subtitle: subtitle?.merge(other.subtitle) ?? other.subtitle,
|
||||
overline: overline?.merge(other.overline) ?? other.overline,
|
||||
);
|
||||
}
|
||||
|
||||
/// Creates a copy of this text theme but with the given field replaced in
|
||||
/// each of the individual text styles.
|
||||
///
|
||||
/// The `displayColor` is applied to [display4], [display3], [display2],
|
||||
/// [display1], and [caption]. The `bodyColor` is applied to the remaining
|
||||
/// text styles.
|
||||
///
|
||||
/// Consider using [Typography.black] or [Typography.white], which implement
|
||||
/// the typography styles in the material design specification, as a starting
|
||||
/// point.
|
||||
TextTheme apply({
|
||||
String fontFamily,
|
||||
double fontSizeFactor = 1.0,
|
||||
double fontSizeDelta = 0.0,
|
||||
Color displayColor,
|
||||
Color bodyColor,
|
||||
TextDecoration decoration,
|
||||
Color decorationColor,
|
||||
TextDecorationStyle decorationStyle,
|
||||
}) {
|
||||
return TextTheme(
|
||||
display4: display4.apply(
|
||||
color: displayColor,
|
||||
decoration: decoration,
|
||||
decorationColor: decorationColor,
|
||||
decorationStyle: decorationStyle,
|
||||
fontFamily: fontFamily,
|
||||
fontSizeFactor: fontSizeFactor,
|
||||
fontSizeDelta: fontSizeDelta,
|
||||
),
|
||||
display3: display3.apply(
|
||||
color: displayColor,
|
||||
decoration: decoration,
|
||||
decorationColor: decorationColor,
|
||||
decorationStyle: decorationStyle,
|
||||
fontFamily: fontFamily,
|
||||
fontSizeFactor: fontSizeFactor,
|
||||
fontSizeDelta: fontSizeDelta,
|
||||
),
|
||||
display2: display2.apply(
|
||||
color: displayColor,
|
||||
decoration: decoration,
|
||||
decorationColor: decorationColor,
|
||||
decorationStyle: decorationStyle,
|
||||
fontFamily: fontFamily,
|
||||
fontSizeFactor: fontSizeFactor,
|
||||
fontSizeDelta: fontSizeDelta,
|
||||
),
|
||||
display1: display1.apply(
|
||||
color: displayColor,
|
||||
decoration: decoration,
|
||||
decorationColor: decorationColor,
|
||||
decorationStyle: decorationStyle,
|
||||
fontFamily: fontFamily,
|
||||
fontSizeFactor: fontSizeFactor,
|
||||
fontSizeDelta: fontSizeDelta,
|
||||
),
|
||||
headline: headline.apply(
|
||||
color: displayColor,
|
||||
decoration: decoration,
|
||||
decorationColor: decorationColor,
|
||||
decorationStyle: decorationStyle,
|
||||
fontFamily: fontFamily,
|
||||
fontSizeFactor: fontSizeFactor,
|
||||
fontSizeDelta: fontSizeDelta,
|
||||
),
|
||||
title: title.apply(
|
||||
color: displayColor,
|
||||
decoration: decoration,
|
||||
decorationColor: decorationColor,
|
||||
decorationStyle: decorationStyle,
|
||||
fontFamily: fontFamily,
|
||||
fontSizeFactor: fontSizeFactor,
|
||||
fontSizeDelta: fontSizeDelta,
|
||||
),
|
||||
subhead: subhead.apply(
|
||||
color: displayColor,
|
||||
decoration: decoration,
|
||||
decorationColor: decorationColor,
|
||||
decorationStyle: decorationStyle,
|
||||
fontFamily: fontFamily,
|
||||
fontSizeFactor: fontSizeFactor,
|
||||
fontSizeDelta: fontSizeDelta,
|
||||
),
|
||||
body2: body2.apply(
|
||||
color: displayColor,
|
||||
decoration: decoration,
|
||||
decorationColor: decorationColor,
|
||||
decorationStyle: decorationStyle,
|
||||
fontFamily: fontFamily,
|
||||
fontSizeFactor: fontSizeFactor,
|
||||
fontSizeDelta: fontSizeDelta,
|
||||
),
|
||||
body1: body1.apply(
|
||||
color: displayColor,
|
||||
decoration: decoration,
|
||||
decorationColor: decorationColor,
|
||||
decorationStyle: decorationStyle,
|
||||
fontFamily: fontFamily,
|
||||
fontSizeFactor: fontSizeFactor,
|
||||
fontSizeDelta: fontSizeDelta,
|
||||
),
|
||||
caption: caption.apply(
|
||||
color: displayColor,
|
||||
decoration: decoration,
|
||||
decorationColor: decorationColor,
|
||||
decorationStyle: decorationStyle,
|
||||
fontFamily: fontFamily,
|
||||
fontSizeFactor: fontSizeFactor,
|
||||
fontSizeDelta: fontSizeDelta,
|
||||
),
|
||||
button: button.apply(
|
||||
color: bodyColor,
|
||||
decoration: decoration,
|
||||
decorationColor: decorationColor,
|
||||
decorationStyle: decorationStyle,
|
||||
fontFamily: fontFamily,
|
||||
fontSizeFactor: fontSizeFactor,
|
||||
fontSizeDelta: fontSizeDelta,
|
||||
),
|
||||
subtitle: subtitle.apply(
|
||||
color: bodyColor,
|
||||
decoration: decoration,
|
||||
decorationColor: decorationColor,
|
||||
decorationStyle: decorationStyle,
|
||||
fontFamily: fontFamily,
|
||||
fontSizeFactor: fontSizeFactor,
|
||||
fontSizeDelta: fontSizeDelta,
|
||||
),
|
||||
overline: overline.apply(
|
||||
color: bodyColor,
|
||||
decoration: decoration,
|
||||
decorationColor: decorationColor,
|
||||
decorationStyle: decorationStyle,
|
||||
fontFamily: fontFamily,
|
||||
fontSizeFactor: fontSizeFactor,
|
||||
fontSizeDelta: fontSizeDelta,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Linearly interpolate between two text themes.
|
||||
///
|
||||
/// The arguments must not be null.
|
||||
///
|
||||
/// {@macro flutter.material.themeData.lerp}
|
||||
static TextTheme lerp(TextTheme a, TextTheme b, double t) {
|
||||
assert(a != null);
|
||||
assert(b != null);
|
||||
assert(t != null);
|
||||
return TextTheme(
|
||||
display4: TextStyle.lerp(a.display4, b.display4, t),
|
||||
display3: TextStyle.lerp(a.display3, b.display3, t),
|
||||
display2: TextStyle.lerp(a.display2, b.display2, t),
|
||||
display1: TextStyle.lerp(a.display1, b.display1, t),
|
||||
headline: TextStyle.lerp(a.headline, b.headline, t),
|
||||
title: TextStyle.lerp(a.title, b.title, t),
|
||||
subhead: TextStyle.lerp(a.subhead, b.subhead, t),
|
||||
body2: TextStyle.lerp(a.body2, b.body2, t),
|
||||
body1: TextStyle.lerp(a.body1, b.body1, t),
|
||||
caption: TextStyle.lerp(a.caption, b.caption, t),
|
||||
button: TextStyle.lerp(a.button, b.button, t),
|
||||
subtitle: TextStyle.lerp(a.subtitle, b.subtitle, t),
|
||||
overline: TextStyle.lerp(a.overline, b.overline, t),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(dynamic other) {
|
||||
if (identical(this, other))
|
||||
return true;
|
||||
if (other.runtimeType != runtimeType)
|
||||
return false;
|
||||
final TextTheme typedOther = other;
|
||||
return display4 == typedOther.display4
|
||||
&& display3 == typedOther.display3
|
||||
&& display2 == typedOther.display2
|
||||
&& display1 == typedOther.display1
|
||||
&& headline == typedOther.headline
|
||||
&& title == typedOther.title
|
||||
&& subhead == typedOther.subhead
|
||||
&& body2 == typedOther.body2
|
||||
&& body1 == typedOther.body1
|
||||
&& caption == typedOther.caption
|
||||
&& button == typedOther.button
|
||||
&& subtitle == typedOther.subtitle
|
||||
&& overline == typedOther.overline;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
// The hashValues() function supports up to 20 arguments.
|
||||
return hashValues(
|
||||
display4,
|
||||
display3,
|
||||
display2,
|
||||
display1,
|
||||
headline,
|
||||
title,
|
||||
subhead,
|
||||
body2,
|
||||
body1,
|
||||
caption,
|
||||
button,
|
||||
subtitle,
|
||||
overline,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
super.debugFillProperties(properties);
|
||||
final TextTheme defaultTheme = Typography(platform: defaultTargetPlatform).black;
|
||||
properties.add(DiagnosticsProperty<TextStyle>('display4', display4, defaultValue: defaultTheme.display4));
|
||||
properties.add(DiagnosticsProperty<TextStyle>('display3', display3, defaultValue: defaultTheme.display3));
|
||||
properties.add(DiagnosticsProperty<TextStyle>('display2', display2, defaultValue: defaultTheme.display2));
|
||||
properties.add(DiagnosticsProperty<TextStyle>('display1', display1, defaultValue: defaultTheme.display1));
|
||||
properties.add(DiagnosticsProperty<TextStyle>('headline', headline, defaultValue: defaultTheme.headline));
|
||||
properties.add(DiagnosticsProperty<TextStyle>('title', title, defaultValue: defaultTheme.title));
|
||||
properties.add(DiagnosticsProperty<TextStyle>('subhead', subhead, defaultValue: defaultTheme.subhead));
|
||||
properties.add(DiagnosticsProperty<TextStyle>('body2', body2, defaultValue: defaultTheme.body2));
|
||||
properties.add(DiagnosticsProperty<TextStyle>('body1', body1, defaultValue: defaultTheme.body1));
|
||||
properties.add(DiagnosticsProperty<TextStyle>('caption', caption, defaultValue: defaultTheme.caption));
|
||||
properties.add(DiagnosticsProperty<TextStyle>('button', button, defaultValue: defaultTheme.button));
|
||||
properties.add(DiagnosticsProperty<TextStyle>('subtitle)', subtitle, defaultValue: defaultTheme.subtitle));
|
||||
properties.add(DiagnosticsProperty<TextStyle>('overline', overline, defaultValue: defaultTheme.overline));
|
||||
}
|
||||
}
|
@ -124,18 +124,17 @@ class Theme extends StatelessWidget {
|
||||
/// }
|
||||
/// ```
|
||||
static ThemeData of(BuildContext context, { bool shadowThemeOnly = false }) {
|
||||
final _InheritedTheme inheritedTheme =
|
||||
context.inheritFromWidgetOfExactType(_InheritedTheme);
|
||||
final _InheritedTheme inheritedTheme = context.inheritFromWidgetOfExactType(_InheritedTheme);
|
||||
if (shadowThemeOnly) {
|
||||
if (inheritedTheme == null || inheritedTheme.theme.isMaterialAppTheme)
|
||||
return null;
|
||||
return inheritedTheme.theme.data;
|
||||
}
|
||||
|
||||
final ThemeData colorTheme = (inheritedTheme != null) ? inheritedTheme.theme.data : _kFallbackTheme;
|
||||
final MaterialLocalizations localizations = MaterialLocalizations.of(context);
|
||||
final TextTheme geometryTheme = localizations?.localTextGeometry ?? MaterialTextGeometry.englishLike;
|
||||
return ThemeData.localize(colorTheme, geometryTheme);
|
||||
final ScriptCategory category = localizations?.scriptCategory ?? ScriptCategory.englishLike;
|
||||
final ThemeData theme = inheritedTheme?.theme?.data ?? _kFallbackTheme;
|
||||
return ThemeData.localize(theme, theme.typography.geometryThemeFor(category));
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -10,6 +10,7 @@ import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'button_theme.dart';
|
||||
import 'chip_theme.dart';
|
||||
import 'color_scheme.dart';
|
||||
import 'colors.dart';
|
||||
import 'ink_splash.dart';
|
||||
import 'ink_well.dart' show InteractiveInkFeatureFactory;
|
||||
@ -17,6 +18,7 @@ import 'input_decorator.dart';
|
||||
import 'page_transitions_theme.dart';
|
||||
import 'slider_theme.dart';
|
||||
import 'tab_bar_theme.dart';
|
||||
import 'text_theme.dart';
|
||||
import 'typography.dart';
|
||||
|
||||
export 'package:flutter/services.dart' show Brightness;
|
||||
@ -147,8 +149,9 @@ class ThemeData extends Diagnosticable {
|
||||
TargetPlatform platform,
|
||||
MaterialTapTargetSize materialTapTargetSize,
|
||||
PageTransitionsTheme pageTransitionsTheme,
|
||||
ColorScheme colorScheme,
|
||||
Typography typography,
|
||||
}) {
|
||||
materialTapTargetSize ??= MaterialTapTargetSize.padded;
|
||||
brightness ??= Brightness.light;
|
||||
final bool isDark = brightness == Brightness.dark;
|
||||
primarySwatch ??= Colors.blue;
|
||||
@ -166,14 +169,22 @@ class ThemeData extends Diagnosticable {
|
||||
bottomAppBarColor ??= isDark ? Colors.grey[800] : Colors.white;
|
||||
cardColor ??= isDark ? Colors.grey[800] : Colors.white;
|
||||
dividerColor ??= isDark ? const Color(0x1FFFFFFF) : const Color(0x1F000000);
|
||||
highlightColor ??= isDark ? _kDarkThemeHighlightColor : _kLightThemeHighlightColor;
|
||||
splashColor ??= isDark ? _kDarkThemeSplashColor : _kLightThemeSplashColor;
|
||||
|
||||
// Create a ColorScheme that is backwards compatible as possible
|
||||
// with the existing default ThemeData color values.
|
||||
colorScheme ??= ColorScheme.fromSwatch(
|
||||
primarySwatch: primarySwatch,
|
||||
primaryColorDark: primaryColorDark,
|
||||
accentColor: accentColor,
|
||||
cardColor: cardColor,
|
||||
backgroundColor: backgroundColor,
|
||||
errorColor: errorColor,
|
||||
brightness: brightness,
|
||||
);
|
||||
|
||||
splashFactory ??= InkSplash.splashFactory;
|
||||
selectedRowColor ??= Colors.grey[100];
|
||||
unselectedWidgetColor ??= isDark ? Colors.white70 : Colors.black54;
|
||||
disabledColor ??= isDark ? Colors.white30 : Colors.black38;
|
||||
buttonColor ??= isDark ? primarySwatch[600] : Colors.grey[300];
|
||||
buttonTheme ??= const ButtonThemeData();
|
||||
// Spec doesn't specify a dark theme secondaryHeaderColor, this is a guess.
|
||||
secondaryHeaderColor ??= isDark ? Colors.grey[700] : primarySwatch[50];
|
||||
textSelectionColor ??= isDark ? accentColor : primarySwatch[200];
|
||||
@ -191,18 +202,35 @@ class ThemeData extends Diagnosticable {
|
||||
accentIconTheme ??= accentIsDark ? const IconThemeData(color: Colors.white) : const IconThemeData(color: Colors.black);
|
||||
iconTheme ??= isDark ? const IconThemeData(color: Colors.white) : const IconThemeData(color: Colors.black87);
|
||||
platform ??= defaultTargetPlatform;
|
||||
final Typography typography = Typography(platform: platform);
|
||||
typography ??= Typography(platform: platform);
|
||||
final TextTheme defaultTextTheme = isDark ? typography.white : typography.black;
|
||||
textTheme = defaultTextTheme.merge(textTheme);
|
||||
final TextTheme defaultPrimaryTextTheme = primaryIsDark ? typography.white : typography.black;
|
||||
primaryTextTheme = defaultPrimaryTextTheme.merge(primaryTextTheme);
|
||||
final TextTheme defaultAccentTextTheme = accentIsDark ? typography.white : typography.black;
|
||||
accentTextTheme = defaultAccentTextTheme.merge(accentTextTheme);
|
||||
materialTapTargetSize ??= MaterialTapTargetSize.padded;
|
||||
if (fontFamily != null) {
|
||||
textTheme = textTheme.apply(fontFamily: fontFamily);
|
||||
primaryTextTheme = primaryTextTheme.apply(fontFamily: fontFamily);
|
||||
accentTextTheme = accentTextTheme.apply(fontFamily: fontFamily);
|
||||
}
|
||||
|
||||
// Used as the default color (fill color) for RaisedButtons. Computing the
|
||||
// default for ButtonThemeData for the sake of backwards compatibility.
|
||||
buttonColor ??= isDark ? primarySwatch[600] : Colors.grey[300];
|
||||
buttonTheme ??= ButtonThemeData(
|
||||
colorScheme: colorScheme,
|
||||
buttonColor: buttonColor,
|
||||
disabledColor: disabledColor,
|
||||
highlightColor: highlightColor,
|
||||
splashColor: splashColor,
|
||||
materialTapTargetSize: materialTapTargetSize,
|
||||
);
|
||||
disabledColor ??= isDark ? Colors.white30 : Colors.black38;
|
||||
highlightColor ??= isDark ? _kDarkThemeHighlightColor : _kLightThemeHighlightColor;
|
||||
splashColor ??= isDark ? _kDarkThemeSplashColor : _kLightThemeSplashColor;
|
||||
|
||||
sliderTheme ??= SliderThemeData.fromPrimaryColors(
|
||||
primaryColor: primaryColor,
|
||||
primaryColorLight: primaryColorLight,
|
||||
@ -235,9 +263,9 @@ class ThemeData extends Diagnosticable {
|
||||
selectedRowColor: selectedRowColor,
|
||||
unselectedWidgetColor: unselectedWidgetColor,
|
||||
disabledColor: disabledColor,
|
||||
buttonTheme: buttonTheme,
|
||||
buttonColor: buttonColor,
|
||||
toggleableActiveColor: toggleableActiveColor,
|
||||
buttonTheme: buttonTheme,
|
||||
secondaryHeaderColor: secondaryHeaderColor,
|
||||
textSelectionColor: textSelectionColor,
|
||||
cursorColor: cursorColor,
|
||||
@ -260,6 +288,8 @@ class ThemeData extends Diagnosticable {
|
||||
platform: platform,
|
||||
materialTapTargetSize: materialTapTargetSize,
|
||||
pageTransitionsTheme: pageTransitionsTheme,
|
||||
colorScheme: colorScheme,
|
||||
typography: typography,
|
||||
);
|
||||
}
|
||||
|
||||
@ -278,9 +308,9 @@ class ThemeData extends Diagnosticable {
|
||||
@required this.primaryColorBrightness,
|
||||
@required this.primaryColorLight,
|
||||
@required this.primaryColorDark,
|
||||
@required this.canvasColor,
|
||||
@required this.accentColor,
|
||||
@required this.accentColorBrightness,
|
||||
@required this.canvasColor,
|
||||
@required this.scaffoldBackgroundColor,
|
||||
@required this.bottomAppBarColor,
|
||||
@required this.cardColor,
|
||||
@ -291,8 +321,8 @@ class ThemeData extends Diagnosticable {
|
||||
@required this.selectedRowColor,
|
||||
@required this.unselectedWidgetColor,
|
||||
@required this.disabledColor,
|
||||
@required this.buttonColor,
|
||||
@required this.buttonTheme,
|
||||
@required this.buttonColor,
|
||||
@required this.secondaryHeaderColor,
|
||||
@required this.textSelectionColor,
|
||||
@required this.cursorColor,
|
||||
@ -316,6 +346,8 @@ class ThemeData extends Diagnosticable {
|
||||
@required this.platform,
|
||||
@required this.materialTapTargetSize,
|
||||
@required this.pageTransitionsTheme,
|
||||
@required this.colorScheme,
|
||||
@required this.typography,
|
||||
}) : assert(brightness != null),
|
||||
assert(primaryColor != null),
|
||||
assert(primaryColorBrightness != null),
|
||||
@ -357,7 +389,13 @@ class ThemeData extends Diagnosticable {
|
||||
assert(chipTheme != null),
|
||||
assert(platform != null),
|
||||
assert(materialTapTargetSize != null),
|
||||
assert(pageTransitionsTheme != null);
|
||||
assert(pageTransitionsTheme != null),
|
||||
assert(colorScheme != null),
|
||||
assert(typography != null);
|
||||
|
||||
// Warning: make sure these properties are in the exact same order as in
|
||||
// hashValues() and in the raw constructor and in the order of fields in
|
||||
// the class and in the lerp() method.
|
||||
|
||||
/// A default light blue theme.
|
||||
///
|
||||
@ -407,6 +445,9 @@ class ThemeData extends Diagnosticable {
|
||||
/// A darker version of the [primaryColor].
|
||||
final Color primaryColorDark;
|
||||
|
||||
/// The default color of [MaterialType.canvas] [Material].
|
||||
final Color canvasColor;
|
||||
|
||||
/// The foreground color for widgets (knobs, text, overscroll edge effect, etc).
|
||||
final Color accentColor;
|
||||
|
||||
@ -415,9 +456,6 @@ class ThemeData extends Diagnosticable {
|
||||
/// action button).
|
||||
final Brightness accentColorBrightness;
|
||||
|
||||
/// The default color of [MaterialType.canvas] [Material].
|
||||
final Color canvasColor;
|
||||
|
||||
/// The default color of the [Material] that underlies the [Scaffold]. The
|
||||
/// background color for a typical material app or a page within the app.
|
||||
final Color scaffoldBackgroundColor;
|
||||
@ -467,17 +505,13 @@ class ThemeData extends Diagnosticable {
|
||||
/// checked or unchecked).
|
||||
final Color disabledColor;
|
||||
|
||||
/// The default fill color of the [Material] used in [RaisedButton]s.
|
||||
final Color buttonColor;
|
||||
|
||||
/// The color used to highlight the active states of toggleable widgets like
|
||||
/// [Switch], [Radio], and [Checkbox].
|
||||
final Color toggleableActiveColor;
|
||||
|
||||
/// Defines the default configuration of button widgets, like [RaisedButton]
|
||||
/// and [FlatButton].
|
||||
final ButtonThemeData buttonTheme;
|
||||
|
||||
/// The default fill color of the [Material] used in [RaisedButton]s.
|
||||
final Color buttonColor;
|
||||
|
||||
/// The color of the header of a [PaginatedDataTable] when there are selected rows.
|
||||
// According to the spec for data tables:
|
||||
// https://material.google.com/components/data-tables.html#data-tables-tables-within-cards
|
||||
@ -510,6 +544,10 @@ class ThemeData extends Diagnosticable {
|
||||
/// The color to use for input validation errors, e.g. in [TextField] fields.
|
||||
final Color errorColor;
|
||||
|
||||
/// The color used to highlight the active states of toggleable widgets like
|
||||
/// [Switch], [Radio], and [Checkbox].
|
||||
final Color toggleableActiveColor;
|
||||
|
||||
/// Text with a color that contrasts with the card and canvas colors.
|
||||
final TextTheme textTheme;
|
||||
|
||||
@ -569,6 +607,20 @@ class ThemeData extends Diagnosticable {
|
||||
/// builder is not found, a builder whose platform is null is used.
|
||||
final PageTransitionsTheme pageTransitionsTheme;
|
||||
|
||||
/// A set of thirteen colors that can be used to configure the
|
||||
/// color properties of most components.
|
||||
///
|
||||
/// This property was added much later than the theme's set of highly
|
||||
/// specific colors, like [cardColor], [buttonColor], [canvasColor] etc.
|
||||
/// New components can be defined exclusively in terms of [colorScheme].
|
||||
/// Existing components will gradually migrate to it, to the extent
|
||||
/// that is possible without significant backwards compatibility breaks.
|
||||
final ColorScheme colorScheme;
|
||||
|
||||
/// The color and geometry [TextTheme] values used to configure [textTheme],
|
||||
/// [primaryTextTheme], and [accentTextTheme].
|
||||
final Typography typography;
|
||||
|
||||
/// Creates a copy of this theme but with the given fields replaced with the new values.
|
||||
ThemeData copyWith({
|
||||
Brightness brightness,
|
||||
@ -589,8 +641,8 @@ class ThemeData extends Diagnosticable {
|
||||
Color selectedRowColor,
|
||||
Color unselectedWidgetColor,
|
||||
Color disabledColor,
|
||||
Color buttonColor,
|
||||
ButtonThemeData buttonTheme,
|
||||
Color buttonColor,
|
||||
Color secondaryHeaderColor,
|
||||
Color textSelectionColor,
|
||||
Color cursorColor,
|
||||
@ -614,6 +666,8 @@ class ThemeData extends Diagnosticable {
|
||||
TargetPlatform platform,
|
||||
MaterialTapTargetSize materialTapTargetSize,
|
||||
PageTransitionsTheme pageTransitionsTheme,
|
||||
ColorScheme colorScheme,
|
||||
Typography typography,
|
||||
}) {
|
||||
return ThemeData.raw(
|
||||
brightness: brightness ?? this.brightness,
|
||||
@ -659,6 +713,8 @@ class ThemeData extends Diagnosticable {
|
||||
platform: platform ?? this.platform,
|
||||
materialTapTargetSize: materialTapTargetSize ?? this.materialTapTargetSize,
|
||||
pageTransitionsTheme: pageTransitionsTheme ?? this.pageTransitionsTheme,
|
||||
colorScheme: colorScheme ?? this.colorScheme,
|
||||
typography: typography ?? this.typography,
|
||||
);
|
||||
}
|
||||
|
||||
@ -736,6 +792,9 @@ class ThemeData extends Diagnosticable {
|
||||
assert(a != null);
|
||||
assert(b != null);
|
||||
assert(t != null);
|
||||
// Warning: make sure these properties are in the exact same order as in
|
||||
// hashValues() and in the raw constructor and in the order of fields in
|
||||
// the class and in the lerp() method.
|
||||
return ThemeData.raw(
|
||||
brightness: t < 0.5 ? a.brightness : b.brightness,
|
||||
primaryColor: Color.lerp(a.primaryColor, b.primaryColor, t),
|
||||
@ -755,9 +814,8 @@ class ThemeData extends Diagnosticable {
|
||||
selectedRowColor: Color.lerp(a.selectedRowColor, b.selectedRowColor, t),
|
||||
unselectedWidgetColor: Color.lerp(a.unselectedWidgetColor, b.unselectedWidgetColor, t),
|
||||
disabledColor: Color.lerp(a.disabledColor, b.disabledColor, t),
|
||||
buttonColor: Color.lerp(a.buttonColor, b.buttonColor, t),
|
||||
toggleableActiveColor: Color.lerp(a.toggleableActiveColor, b.toggleableActiveColor, t),
|
||||
buttonTheme: t < 0.5 ? a.buttonTheme : b.buttonTheme,
|
||||
buttonColor: Color.lerp(a.buttonColor, b.buttonColor, t),
|
||||
secondaryHeaderColor: Color.lerp(a.secondaryHeaderColor, b.secondaryHeaderColor, t),
|
||||
textSelectionColor: Color.lerp(a.textSelectionColor, b.textSelectionColor, t),
|
||||
cursorColor: Color.lerp(a.cursorColor, b.cursorColor, t),
|
||||
@ -767,6 +825,7 @@ class ThemeData extends Diagnosticable {
|
||||
indicatorColor: Color.lerp(a.indicatorColor, b.indicatorColor, t),
|
||||
hintColor: Color.lerp(a.hintColor, b.hintColor, t),
|
||||
errorColor: Color.lerp(a.errorColor, b.errorColor, t),
|
||||
toggleableActiveColor: Color.lerp(a.toggleableActiveColor, b.toggleableActiveColor, t),
|
||||
textTheme: TextTheme.lerp(a.textTheme, b.textTheme, t),
|
||||
primaryTextTheme: TextTheme.lerp(a.primaryTextTheme, b.primaryTextTheme, t),
|
||||
accentTextTheme: TextTheme.lerp(a.accentTextTheme, b.accentTextTheme, t),
|
||||
@ -780,6 +839,8 @@ class ThemeData extends Diagnosticable {
|
||||
platform: t < 0.5 ? a.platform : b.platform,
|
||||
materialTapTargetSize: t < 0.5 ? a.materialTapTargetSize : b.materialTapTargetSize,
|
||||
pageTransitionsTheme: t < 0.5 ? a.pageTransitionsTheme : b.pageTransitionsTheme,
|
||||
colorScheme: ColorScheme.lerp(a.colorScheme, b.colorScheme, t),
|
||||
typography: Typography.lerp(a.typography, b.typography, t),
|
||||
);
|
||||
}
|
||||
|
||||
@ -809,9 +870,8 @@ class ThemeData extends Diagnosticable {
|
||||
(otherData.selectedRowColor == selectedRowColor) &&
|
||||
(otherData.unselectedWidgetColor == unselectedWidgetColor) &&
|
||||
(otherData.disabledColor == disabledColor) &&
|
||||
(otherData.buttonColor == buttonColor) &&
|
||||
(otherData.toggleableActiveColor == toggleableActiveColor) &&
|
||||
(otherData.buttonTheme == buttonTheme) &&
|
||||
(otherData.buttonColor == buttonColor) &&
|
||||
(otherData.secondaryHeaderColor == secondaryHeaderColor) &&
|
||||
(otherData.textSelectionColor == textSelectionColor) &&
|
||||
(otherData.cursorColor == cursorColor) &&
|
||||
@ -821,6 +881,7 @@ class ThemeData extends Diagnosticable {
|
||||
(otherData.indicatorColor == indicatorColor) &&
|
||||
(otherData.hintColor == hintColor) &&
|
||||
(otherData.errorColor == errorColor) &&
|
||||
(otherData.toggleableActiveColor == toggleableActiveColor) &&
|
||||
(otherData.textTheme == textTheme) &&
|
||||
(otherData.primaryTextTheme == primaryTextTheme) &&
|
||||
(otherData.accentTextTheme == accentTextTheme) &&
|
||||
@ -833,7 +894,9 @@ class ThemeData extends Diagnosticable {
|
||||
(otherData.chipTheme == chipTheme) &&
|
||||
(otherData.platform == platform) &&
|
||||
(otherData.materialTapTargetSize == materialTapTargetSize) &&
|
||||
(otherData.pageTransitionsTheme == pageTransitionsTheme);
|
||||
(otherData.pageTransitionsTheme == pageTransitionsTheme) &&
|
||||
(otherData.colorScheme == colorScheme) &&
|
||||
(otherData.typography == typography);
|
||||
}
|
||||
|
||||
@override
|
||||
@ -860,9 +923,11 @@ class ThemeData extends Diagnosticable {
|
||||
splashFactory,
|
||||
selectedRowColor,
|
||||
unselectedWidgetColor,
|
||||
buttonColor,
|
||||
disabledColor,
|
||||
buttonTheme,
|
||||
hashValues(
|
||||
buttonColor,
|
||||
toggleableActiveColor,
|
||||
secondaryHeaderColor,
|
||||
textSelectionColor,
|
||||
cursorColor,
|
||||
@ -872,7 +937,6 @@ class ThemeData extends Diagnosticable {
|
||||
indicatorColor,
|
||||
hintColor,
|
||||
errorColor,
|
||||
toggleableActiveColor,
|
||||
textTheme,
|
||||
primaryTextTheme,
|
||||
accentTextTheme,
|
||||
@ -881,12 +945,14 @@ class ThemeData extends Diagnosticable {
|
||||
primaryIconTheme,
|
||||
accentIconTheme,
|
||||
sliderTheme,
|
||||
tabBarTheme,
|
||||
hashValues(
|
||||
tabBarTheme,
|
||||
chipTheme,
|
||||
platform,
|
||||
materialTapTargetSize,
|
||||
pageTransitionsTheme,
|
||||
colorScheme,
|
||||
typography,
|
||||
),
|
||||
),
|
||||
);
|
||||
@ -936,6 +1002,8 @@ class ThemeData extends Diagnosticable {
|
||||
properties.add(DiagnosticsProperty<ChipThemeData>('chipTheme', chipTheme));
|
||||
properties.add(DiagnosticsProperty<MaterialTapTargetSize>('materialTapTargetSize', materialTapTargetSize));
|
||||
properties.add(DiagnosticsProperty<PageTransitionsTheme>('pageTransitionsTheme', pageTransitionsTheme));
|
||||
properties.add(DiagnosticsProperty<ColorScheme>('colorScheme', colorScheme, defaultValue: defaultData.colorScheme));
|
||||
properties.add(DiagnosticsProperty<Typography>('typography', typography, defaultValue: defaultData.typography));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,10 +16,10 @@ import 'dialog.dart';
|
||||
import 'feedback.dart';
|
||||
import 'flat_button.dart';
|
||||
import 'material_localizations.dart';
|
||||
import 'text_theme.dart';
|
||||
import 'theme.dart';
|
||||
import 'theme_data.dart';
|
||||
import 'time.dart';
|
||||
import 'typography.dart';
|
||||
|
||||
const Duration _kDialAnimateDuration = Duration(milliseconds: 200);
|
||||
const double _kTwoPi = 2 * math.pi;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -64,4 +64,56 @@ void main() {
|
||||
final Finder buttonBar = find.byType(ButtonBar);
|
||||
expect(tester.getBottomRight(buttonBar).dy - tester.getTopRight(buttonBar).dy, 26.0);
|
||||
});
|
||||
|
||||
testWidgets('ButtonBar FlatButton inherits Theme accentColor', (WidgetTester tester) async {
|
||||
// Regression test for https://github.com/flutter/flutter/issues/22789
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeData(accentColor: const Color(1)),
|
||||
home: Builder(
|
||||
builder: (BuildContext context) {
|
||||
return Center(
|
||||
child: ButtonTheme.bar(
|
||||
child: ButtonBar(
|
||||
children: <Widget>[
|
||||
FlatButton(
|
||||
child: const Text('button'),
|
||||
onPressed: () {
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog( // puts its actions in a ButtonBar
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
onPressed: () { },
|
||||
child: const Text('enabled'),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(tester.widget<RawMaterialButton>(find.byType(RawMaterialButton)).textStyle.color, const Color(1));
|
||||
|
||||
// Show the dialog
|
||||
await tester.tap(find.text('button'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final Finder dialogButton = find.ancestor(
|
||||
of: find.text('enabled'),
|
||||
matching: find.byType(RawMaterialButton),
|
||||
);
|
||||
expect(tester.widget<RawMaterialButton>(dialogButton).textStyle.color, const Color(1));
|
||||
});
|
||||
}
|
||||
|
@ -36,9 +36,12 @@ void main() {
|
||||
|
||||
testWidgets('ButtonTheme defaults', (WidgetTester tester) async {
|
||||
ButtonTextTheme textTheme;
|
||||
ButtonBarLayoutBehavior layoutBehavior;
|
||||
BoxConstraints constraints;
|
||||
EdgeInsets padding;
|
||||
ShapeBorder shape;
|
||||
bool alignedDropdown;
|
||||
ColorScheme colorScheme;
|
||||
|
||||
await tester.pumpWidget(
|
||||
ButtonTheme(
|
||||
@ -49,13 +52,16 @@ void main() {
|
||||
constraints = theme.constraints;
|
||||
padding = theme.padding;
|
||||
shape = theme.shape;
|
||||
layoutBehavior = theme.layoutBehavior;
|
||||
colorScheme = theme.colorScheme;
|
||||
alignedDropdown = theme.alignedDropdown;
|
||||
return Container(
|
||||
alignment: Alignment.topLeft,
|
||||
child: const Directionality(
|
||||
child: Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: FlatButton(
|
||||
onPressed: null,
|
||||
child: Text('b'), // intrinsic width < minimum width
|
||||
onPressed: () { },
|
||||
child: const Text('b'), // intrinsic width < minimum width
|
||||
),
|
||||
),
|
||||
);
|
||||
@ -65,12 +71,14 @@ void main() {
|
||||
);
|
||||
|
||||
expect(textTheme, ButtonTextTheme.normal);
|
||||
expect(layoutBehavior, ButtonBarLayoutBehavior.padded);
|
||||
expect(constraints, const BoxConstraints(minWidth: 88.0, minHeight: 36.0));
|
||||
expect(padding, const EdgeInsets.symmetric(horizontal: 16.0));
|
||||
expect(shape, const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(2.0)),
|
||||
));
|
||||
|
||||
expect(alignedDropdown, false);
|
||||
expect(colorScheme, ThemeData.light().colorScheme);
|
||||
expect(tester.widget<Material>(find.byType(Material)).shape, shape);
|
||||
expect(tester.getSize(find.byType(Material)), const Size(88.0, 36.0));
|
||||
});
|
||||
@ -78,26 +86,33 @@ void main() {
|
||||
test('ButtonThemeData.copyWith', () {
|
||||
ButtonThemeData theme = const ButtonThemeData().copyWith();
|
||||
expect(theme.textTheme, ButtonTextTheme.normal);
|
||||
expect(theme.layoutBehavior, ButtonBarLayoutBehavior.padded);
|
||||
expect(theme.constraints, const BoxConstraints(minWidth: 88.0, minHeight: 36.0));
|
||||
expect(theme.padding, const EdgeInsets.symmetric(horizontal: 16.0));
|
||||
expect(theme.shape, const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(2.0)),
|
||||
));
|
||||
expect(theme.alignedDropdown, false);
|
||||
expect(theme.colorScheme, null);
|
||||
|
||||
theme = const ButtonThemeData().copyWith(
|
||||
textTheme: ButtonTextTheme.primary,
|
||||
layoutBehavior: ButtonBarLayoutBehavior.constrained,
|
||||
minWidth: 100.0,
|
||||
height: 200.0,
|
||||
padding: EdgeInsets.zero,
|
||||
shape: const StadiumBorder(),
|
||||
alignedDropdown: true,
|
||||
colorScheme: const ColorScheme.dark(),
|
||||
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
);
|
||||
expect(theme.textTheme, ButtonTextTheme.primary);
|
||||
expect(theme.layoutBehavior, ButtonBarLayoutBehavior.constrained);
|
||||
expect(theme.constraints, const BoxConstraints(minWidth: 100.0, minHeight: 200.0));
|
||||
expect(theme.padding, EdgeInsets.zero);
|
||||
expect(theme.shape, const StadiumBorder());
|
||||
expect(theme.alignedDropdown, true);
|
||||
expect(theme.colorScheme, const ColorScheme.dark());
|
||||
});
|
||||
|
||||
testWidgets('Theme buttonTheme defaults', (WidgetTester tester) async {
|
||||
@ -107,10 +122,12 @@ void main() {
|
||||
EdgeInsets padding;
|
||||
ShapeBorder shape;
|
||||
|
||||
const Color disabledColor = Color(0xFF00FF00);
|
||||
await tester.pumpWidget(
|
||||
Theme(
|
||||
data: lightTheme.copyWith(
|
||||
disabledColor: const Color(0xFF00FF00), // disabled RaisedButton fill color
|
||||
disabledColor: disabledColor, // disabled RaisedButton fill color
|
||||
buttonTheme: const ButtonThemeData(disabledColor: disabledColor),
|
||||
textTheme: lightTheme.textTheme.copyWith(
|
||||
button: lightTheme.textTheme.button.copyWith(
|
||||
// The button's height will match because there's no
|
||||
@ -149,7 +166,7 @@ void main() {
|
||||
));
|
||||
|
||||
expect(tester.widget<Material>(find.byType(Material)).shape, shape);
|
||||
expect(tester.widget<Material>(find.byType(Material)).color, const Color(0xFF00FF00));
|
||||
expect(tester.widget<Material>(find.byType(Material)).color, disabledColor);
|
||||
expect(tester.getSize(find.byType(Material)), const Size(88.0, 48.0));
|
||||
});
|
||||
|
||||
@ -169,6 +186,7 @@ void main() {
|
||||
minWidth: 100.0,
|
||||
height: 200.0,
|
||||
padding: EdgeInsets.zero,
|
||||
buttonColor: const Color(0xFF00FF00), // enabled RaisedButton fill color
|
||||
shape: const RoundedRectangleBorder(),
|
||||
child: Builder(
|
||||
builder: (BuildContext context) {
|
||||
|
@ -330,7 +330,7 @@ void main() {
|
||||
expect(text.text.style.color, Colors.black38);
|
||||
});
|
||||
|
||||
testWidgets('Disabled MaterialButton has same semantic size as enabled and exposes disabled semantics', (WidgetTester tester) async {
|
||||
testWidgets('Disabled MaterialButton has same semantic size as enabled and exposes disabled semantics', (WidgetTester tester) async {
|
||||
final SemanticsTester semantics = SemanticsTester(tester);
|
||||
|
||||
final Rect expectedButtonSize = Rect.fromLTRB(0.0, 0.0, 116.0, 48.0);
|
||||
@ -409,6 +409,73 @@ void main() {
|
||||
semantics.dispose();
|
||||
});
|
||||
|
||||
testWidgets('MaterialButton minWidth and height parameters', (WidgetTester tester) async {
|
||||
Widget buildFrame({ double minWidth, double height, EdgeInsets padding = EdgeInsets.zero, Widget child }) {
|
||||
return Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: Center(
|
||||
child: MaterialButton(
|
||||
padding: padding,
|
||||
minWidth: minWidth,
|
||||
height: height,
|
||||
onPressed: null,
|
||||
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
await tester.pumpWidget(buildFrame(minWidth: 8.0, height: 24.0));
|
||||
expect(tester.getSize(find.byType(MaterialButton)), const Size(8.0, 24.0));
|
||||
|
||||
await tester.pumpWidget(buildFrame(minWidth: 8.0));
|
||||
// Default minHeight constraint is 36, see RawMaterialButton.
|
||||
expect(tester.getSize(find.byType(MaterialButton)), const Size(8.0, 36.0));
|
||||
|
||||
await tester.pumpWidget(buildFrame(height: 8.0));
|
||||
// Default minWidth constraint is 88, see RawMaterialButton.
|
||||
expect(tester.getSize(find.byType(MaterialButton)), const Size(88.0, 8.0));
|
||||
|
||||
await tester.pumpWidget(buildFrame());
|
||||
expect(tester.getSize(find.byType(MaterialButton)), const Size(88.0, 36.0));
|
||||
|
||||
await tester.pumpWidget(buildFrame(padding: const EdgeInsets.all(4.0)));
|
||||
expect(tester.getSize(find.byType(MaterialButton)), const Size(88.0, 36.0));
|
||||
|
||||
// Size is defined by the padding.
|
||||
await tester.pumpWidget(
|
||||
buildFrame(
|
||||
minWidth: 0.0,
|
||||
height: 0.0,
|
||||
padding: const EdgeInsets.all(4.0),
|
||||
),
|
||||
);
|
||||
expect(tester.getSize(find.byType(MaterialButton)), const Size(8.0, 8.0));
|
||||
|
||||
// Size is defined by the padded child.
|
||||
await tester.pumpWidget(
|
||||
buildFrame(
|
||||
minWidth: 0.0,
|
||||
height: 0.0,
|
||||
padding: const EdgeInsets.all(4.0),
|
||||
child: const SizedBox(width: 8.0, height: 8.0),
|
||||
),
|
||||
);
|
||||
expect(tester.getSize(find.byType(MaterialButton)), const Size(16.0, 16.0));
|
||||
|
||||
// Size is defined by the minWidth, height constraints.
|
||||
await tester.pumpWidget(
|
||||
buildFrame(
|
||||
minWidth: 18.0,
|
||||
height: 18.0,
|
||||
padding: const EdgeInsets.all(4.0),
|
||||
child: const SizedBox(width: 8.0, height: 8.0),
|
||||
),
|
||||
);
|
||||
expect(tester.getSize(find.byType(MaterialButton)), const Size(18.0, 18.0));
|
||||
});
|
||||
|
||||
testWidgets('MaterialButton size is configurable by ThemeData.materialTapTargetSize', (WidgetTester tester) async {
|
||||
final Key key1 = UniqueKey();
|
||||
await tester.pumpWidget(
|
||||
|
@ -89,7 +89,7 @@ void main() {
|
||||
// Expect that the button is disabled and painted with the disabled border color.
|
||||
expect(tester.widget<OutlineButton>(outlineButton).enabled, false);
|
||||
expect(
|
||||
outlineButton,
|
||||
outlineButton, //find.byType(OutlineButton),
|
||||
paints
|
||||
..clipPath(pathMatcher: coversSameAreaAs(clipPath, areaToCompare: clipRect.inflate(10.0)))
|
||||
..path(color: disabledBorderColor, strokeWidth: borderWidth));
|
||||
|
@ -915,7 +915,7 @@ void main() {
|
||||
);
|
||||
final Text helperText = tester.widget(find.text('helper text'));
|
||||
expect(helperText.style.color, themeData.hintColor);
|
||||
expect(helperText.style.fontSize, MaterialTextGeometry.englishLike.caption.fontSize);
|
||||
expect(helperText.style.fontSize, Typography.englishLike2014.caption.fontSize);
|
||||
});
|
||||
|
||||
testWidgets('TextField with specified helperStyle', (WidgetTester tester) async {
|
||||
|
186
packages/flutter/test/material/theme_defaults_test.dart
Normal file
186
packages/flutter/test/material/theme_defaults_test.dart
Normal file
@ -0,0 +1,186 @@
|
||||
// Copyright 2018 The Chromium 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_test/flutter_test.dart';
|
||||
|
||||
const ShapeBorder defaultButtonShape = RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(2.0)));
|
||||
const EdgeInsets defaultButtonPadding = EdgeInsets.only(left: 16.0, right: 16.0);
|
||||
const BoxConstraints defaultButtonConstraints = BoxConstraints(minWidth: 88.0, minHeight: 36.0);
|
||||
const Duration defaultButtonDuration = Duration(milliseconds: 200);
|
||||
|
||||
void main() {
|
||||
group('RaisedButton', () {
|
||||
testWidgets('theme: ThemeData.light(), enabled: true', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeData.light(),
|
||||
home: Center(
|
||||
child: RaisedButton(
|
||||
onPressed: () { }, // button.enabled == true
|
||||
child: const Text('button'),
|
||||
)
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final RawMaterialButton raw = tester.widget<RawMaterialButton>(find.byType(RawMaterialButton));
|
||||
expect(raw.textStyle.color, const Color(0xdd000000));
|
||||
expect(raw.fillColor, const Color(0xffe0e0e0));
|
||||
expect(raw.highlightColor, const Color(0x29000000)); // Was Color(0x66bcbcbc)
|
||||
expect(raw.splashColor, const Color(0x1f000000)); // Was Color(0x66c8c8c8)
|
||||
expect(raw.elevation, 2.0);
|
||||
expect(raw.highlightElevation, 8.0);
|
||||
expect(raw.disabledElevation, 0.0);
|
||||
expect(raw.constraints, defaultButtonConstraints);
|
||||
expect(raw.padding, defaultButtonPadding);
|
||||
expect(raw.shape, defaultButtonShape);
|
||||
expect(raw.animationDuration, defaultButtonDuration);
|
||||
expect(raw.materialTapTargetSize, MaterialTapTargetSize.padded);
|
||||
});
|
||||
|
||||
testWidgets('theme: ThemeData.light(), enabled: false', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeData.light(),
|
||||
home: const Center(
|
||||
child: RaisedButton(
|
||||
onPressed: null, // button.enabled == false
|
||||
child: Text('button'),
|
||||
)
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final RawMaterialButton raw = tester.widget<RawMaterialButton>(find.byType(RawMaterialButton));
|
||||
expect(raw.textStyle.color, const Color(0x61000000));
|
||||
expect(raw.fillColor, const Color(0x61000000));
|
||||
// highlightColor, disabled button can't be pressed
|
||||
// splashColor, disabled button doesn't splash
|
||||
expect(raw.elevation, 2.0);
|
||||
expect(raw.highlightElevation, 8.0);
|
||||
expect(raw.disabledElevation, 0.0);
|
||||
expect(raw.constraints, defaultButtonConstraints);
|
||||
expect(raw.padding, defaultButtonPadding);
|
||||
expect(raw.shape, defaultButtonShape);
|
||||
expect(raw.animationDuration, defaultButtonDuration);
|
||||
expect(raw.materialTapTargetSize, MaterialTapTargetSize.padded);
|
||||
});
|
||||
});
|
||||
|
||||
group('FlatButton', () {
|
||||
testWidgets('theme: ThemeData.light(), enabled: true', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeData.light(),
|
||||
home: Center(
|
||||
child: FlatButton(
|
||||
onPressed: () { }, // button.enabled == true
|
||||
child: const Text('button'),
|
||||
)
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final RawMaterialButton raw = tester.widget<RawMaterialButton>(find.byType(RawMaterialButton));
|
||||
expect(raw.textStyle.color, const Color(0xdd000000));
|
||||
expect(raw.fillColor, null);
|
||||
expect(raw.highlightColor, const Color(0x29000000)); // Was Color(0x66bcbcbc)
|
||||
expect(raw.splashColor, const Color(0x1f000000)); // Was Color(0x66c8c8c8)
|
||||
expect(raw.elevation, 0.0);
|
||||
expect(raw.highlightElevation, 0.0);
|
||||
expect(raw.disabledElevation, 0.0);
|
||||
expect(raw.constraints, defaultButtonConstraints);
|
||||
expect(raw.padding, defaultButtonPadding);
|
||||
expect(raw.shape, defaultButtonShape);
|
||||
expect(raw.animationDuration, defaultButtonDuration);
|
||||
expect(raw.materialTapTargetSize, MaterialTapTargetSize.padded);
|
||||
});
|
||||
|
||||
testWidgets('theme: ThemeData.light(), enabled: false', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeData.light(),
|
||||
home: const Center(
|
||||
child: FlatButton(
|
||||
onPressed: null, // button.enabled == false
|
||||
child: Text('button'),
|
||||
)
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final RawMaterialButton raw = tester.widget<RawMaterialButton>(find.byType(RawMaterialButton));
|
||||
expect(raw.textStyle.color, const Color(0x61000000));
|
||||
expect(raw.fillColor, null);
|
||||
// highlightColor, disabled button can't be pressed
|
||||
// splashColor, disabled button doesn't splash
|
||||
expect(raw.elevation, 0.0);
|
||||
expect(raw.highlightElevation, 0.0);
|
||||
expect(raw.disabledElevation, 0.0);
|
||||
expect(raw.constraints, defaultButtonConstraints);
|
||||
expect(raw.padding, defaultButtonPadding);
|
||||
expect(raw.shape, defaultButtonShape);
|
||||
expect(raw.animationDuration, const Duration(milliseconds: 200));
|
||||
expect(raw.materialTapTargetSize, MaterialTapTargetSize.padded);
|
||||
});
|
||||
});
|
||||
|
||||
group('OutlineButton', () {
|
||||
testWidgets('theme: ThemeData.light(), enabled: true', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeData.light(),
|
||||
home: Center(
|
||||
child: OutlineButton(
|
||||
onPressed: () { }, // button.enabled == true
|
||||
child: const Text('button'),
|
||||
)
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final RawMaterialButton raw = tester.widget<RawMaterialButton>(find.byType(RawMaterialButton));
|
||||
expect(raw.textStyle.color, const Color(0xdd000000));
|
||||
expect(raw.fillColor, const Color(0x00ffffff));
|
||||
expect(raw.highlightColor, const Color(0x29000000)); // Was Color(0x66bcbcbc)
|
||||
expect(raw.splashColor, const Color(0x1f000000)); // Was Color(0x66c8c8c8)
|
||||
expect(raw.elevation, 0.0);
|
||||
expect(raw.highlightElevation, 0.0);
|
||||
expect(raw.disabledElevation, 0.0);
|
||||
expect(raw.constraints, defaultButtonConstraints);
|
||||
expect(raw.padding, defaultButtonPadding);
|
||||
// animationDuration can't be configed by the theme/constructor
|
||||
expect(raw.materialTapTargetSize, MaterialTapTargetSize.padded);
|
||||
});
|
||||
|
||||
testWidgets('theme: ThemeData.light(), enabled: false', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeData.light(),
|
||||
home: const Center(
|
||||
child: OutlineButton(
|
||||
onPressed: null, // button.enabled == false
|
||||
child: Text('button'),
|
||||
)
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final RawMaterialButton raw = tester.widget<RawMaterialButton>(find.byType(RawMaterialButton));
|
||||
expect(raw.textStyle.color, const Color(0x61000000));
|
||||
expect(raw.fillColor, const Color(0x00000000));
|
||||
// highlightColor, disabled button can't be pressed
|
||||
// splashColor, disabled button doesn't splash
|
||||
expect(raw.elevation, 0.0);
|
||||
expect(raw.highlightElevation, 0.0);
|
||||
expect(raw.disabledElevation, 0.0);
|
||||
expect(raw.constraints, defaultButtonConstraints);
|
||||
expect(raw.padding, defaultButtonPadding);
|
||||
// animationDuration can't be configed by the theme/constructor
|
||||
expect(raw.materialTapTargetSize, MaterialTapTargetSize.padded);
|
||||
});
|
||||
});
|
||||
|
||||
}
|
@ -9,6 +9,8 @@ import 'package:flutter/src/foundation/diagnostics.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
const TextTheme defaultGeometryTheme = Typography.englishLike2014;
|
||||
|
||||
test('ThemeDataTween control test', () {
|
||||
final ThemeData light = ThemeData.light();
|
||||
final ThemeData dark = ThemeData.dark();
|
||||
@ -55,7 +57,7 @@ void main() {
|
||||
)
|
||||
);
|
||||
|
||||
expect(Theme.of(capturedContext), equals(ThemeData.localize(ThemeData.fallback(), MaterialTextGeometry.englishLike)));
|
||||
expect(Theme.of(capturedContext), equals(ThemeData.localize(ThemeData.fallback(), defaultGeometryTheme)));
|
||||
expect(Theme.of(capturedContext, shadowThemeOnly: true), isNull);
|
||||
});
|
||||
|
||||
@ -65,20 +67,20 @@ void main() {
|
||||
|
||||
// Same input, same output.
|
||||
expect(
|
||||
ThemeData.localize(light, MaterialTextGeometry.englishLike),
|
||||
same(ThemeData.localize(light, MaterialTextGeometry.englishLike)),
|
||||
ThemeData.localize(light, defaultGeometryTheme),
|
||||
same(ThemeData.localize(light, defaultGeometryTheme)),
|
||||
);
|
||||
|
||||
// Different text geometry, different output.
|
||||
expect(
|
||||
ThemeData.localize(light, MaterialTextGeometry.englishLike),
|
||||
isNot(same(ThemeData.localize(light, MaterialTextGeometry.tall))),
|
||||
ThemeData.localize(light, defaultGeometryTheme),
|
||||
isNot(same(ThemeData.localize(light, Typography.tall2014))),
|
||||
);
|
||||
|
||||
// Different base theme, different output.
|
||||
expect(
|
||||
ThemeData.localize(light, MaterialTextGeometry.englishLike),
|
||||
isNot(same(ThemeData.localize(dark, MaterialTextGeometry.englishLike))),
|
||||
ThemeData.localize(light, defaultGeometryTheme),
|
||||
isNot(same(ThemeData.localize(dark, defaultGeometryTheme))),
|
||||
);
|
||||
});
|
||||
|
||||
@ -408,7 +410,7 @@ void main() {
|
||||
}
|
||||
}
|
||||
|
||||
expect(theme.textTheme.display4.debugLabel, '(englishLike display4).merge(blackMountainView display4)');
|
||||
expect(theme.textTheme.display4.debugLabel, '(englishLike display4 2014).merge(blackMountainView display4)');
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -74,6 +74,8 @@ void main() {
|
||||
expect(textTheme.body1, isTextFont);
|
||||
expect(textTheme.caption, isTextFont);
|
||||
expect(textTheme.button, isTextFont);
|
||||
expect(textTheme.subtitle, isTextFont);
|
||||
expect(textTheme.overline, isTextFont);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -138,11 +138,11 @@ It is converted to an enum value because the `material_en.arb` file
|
||||
has this value labeled as `"x-flutter-type": "icuShortTimePattern"`.
|
||||
|
||||
The value of `scriptCategory` is based on the
|
||||
[Language categories reference](https://material.io/go/design-typography#typography-language-categories-reference)
|
||||
[Language categories reference](https://material.io/design/typography/language-support.html#language-categories-reference)
|
||||
section in the Material spec. The `scriptCategory` value is used when looking up
|
||||
the `TextTheme`, see the
|
||||
[MaterialTextGeometry](https://docs.flutter.io/flutter/material/MaterialTextGeometry/forScriptCategory.html)
|
||||
class.
|
||||
[MaterialTextGeometry](https://docs.flutter.io/flutter/material/MaterialTextGeometry/localizedFor.html)
|
||||
method.
|
||||
|
||||
|
||||
### Generated file localizations.dart: all of the localizations as a Map
|
||||
|
@ -171,7 +171,7 @@ class MaterialLocalizationAr extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'عدد الصفوف في الصفحة:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'tall';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.tall;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'بحث';
|
||||
@ -372,7 +372,7 @@ class MaterialLocalizationBg extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'Редове на страница:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'English-like';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.englishLike;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'Търсене';
|
||||
@ -573,7 +573,7 @@ class MaterialLocalizationBs extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'Redaka po stranici:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'English-like';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.englishLike;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'Pretražite';
|
||||
@ -774,7 +774,7 @@ class MaterialLocalizationCa extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'Files per pàgina:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'English-like';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.englishLike;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'Cerca';
|
||||
@ -975,7 +975,7 @@ class MaterialLocalizationCs extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'Počet řádků na stránku:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'English-like';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.englishLike;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'Hledat';
|
||||
@ -1176,7 +1176,7 @@ class MaterialLocalizationDa extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'Rækker pr. side:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'English-like';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.englishLike;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'Søg';
|
||||
@ -1377,7 +1377,7 @@ class MaterialLocalizationDe extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'Zeilen pro Seite:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'English-like';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.englishLike;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'Suchen';
|
||||
@ -1608,7 +1608,7 @@ class MaterialLocalizationEl extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'Σειρές ανά σελίδα:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'English-like';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.englishLike;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'Αναζήτηση';
|
||||
@ -1809,7 +1809,7 @@ class MaterialLocalizationEn extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'Rows per page:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'English-like';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.englishLike;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'Search';
|
||||
@ -2313,7 +2313,7 @@ class MaterialLocalizationEs extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'Filas por página:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'English-like';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.englishLike;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'Buscar';
|
||||
@ -4137,7 +4137,7 @@ class MaterialLocalizationEt extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'Ridu lehe kohta:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'English-like';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.englishLike;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'Otsing';
|
||||
@ -4338,7 +4338,7 @@ class MaterialLocalizationFa extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'ردیف در هر صفحه:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'tall';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.tall;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'جستجو';
|
||||
@ -4539,7 +4539,7 @@ class MaterialLocalizationFi extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'Riviä/sivu:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'English-like';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.englishLike;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'Haku';
|
||||
@ -4740,7 +4740,7 @@ class MaterialLocalizationFil extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'Mga row bawat page:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'English-like';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.englishLike;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'Maghanap';
|
||||
@ -4941,7 +4941,7 @@ class MaterialLocalizationFr extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'Lignes par page :';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'English-like';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.englishLike;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'Rechercher';
|
||||
@ -5169,7 +5169,7 @@ class MaterialLocalizationGsw extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'Zeilen pro Seite:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'English-like';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.englishLike;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'Suchen';
|
||||
@ -5370,7 +5370,7 @@ class MaterialLocalizationHe extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'שורות בכל דף:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'English-like';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.englishLike;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'חיפוש';
|
||||
@ -5571,7 +5571,7 @@ class MaterialLocalizationHi extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'हर पेज में पंक्तियों की संख्या:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'dense';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.dense;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'खोजें';
|
||||
@ -5772,7 +5772,7 @@ class MaterialLocalizationHr extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'Redaka po stranici:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'English-like';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.englishLike;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'Pretražite';
|
||||
@ -5973,7 +5973,7 @@ class MaterialLocalizationHu extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'Oldalankénti sorszám:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'English-like';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.englishLike;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'Keresés';
|
||||
@ -6174,7 +6174,7 @@ class MaterialLocalizationId extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'Baris per halaman:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'English-like';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.englishLike;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'Telusuri';
|
||||
@ -6375,7 +6375,7 @@ class MaterialLocalizationIt extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'Righe per pagina:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'English-like';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.englishLike;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'Cerca';
|
||||
@ -6576,7 +6576,7 @@ class MaterialLocalizationJa extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'ページあたりの行数:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'dense';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.dense;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'検索';
|
||||
@ -6777,7 +6777,7 @@ class MaterialLocalizationKm extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'ជួរមុខ:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'dense';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.dense;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'ស្វែងរក';
|
||||
@ -6978,7 +6978,7 @@ class MaterialLocalizationKo extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'페이지당 행 수:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'dense';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.dense;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'검색';
|
||||
@ -7179,7 +7179,7 @@ class MaterialLocalizationLt extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'Eilučių puslapyje:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'English-like';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.englishLike;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'Paieška';
|
||||
@ -7380,7 +7380,7 @@ class MaterialLocalizationLv extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'Rindas lapā:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'English-like';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.englishLike;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'Meklēt';
|
||||
@ -7581,7 +7581,7 @@ class MaterialLocalizationMs extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'Baris setiap halaman:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'English-like';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.englishLike;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'Cari';
|
||||
@ -7782,7 +7782,7 @@ class MaterialLocalizationNb extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'Rader per side:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'English-like';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.englishLike;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'Søk';
|
||||
@ -7983,7 +7983,7 @@ class MaterialLocalizationNl extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'Rijen per pagina:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'English-like';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.englishLike;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'Zoeken';
|
||||
@ -8184,7 +8184,7 @@ class MaterialLocalizationPl extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'Wiersze na stronie:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'English-like';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.englishLike;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'Szukaj';
|
||||
@ -8385,7 +8385,7 @@ class MaterialLocalizationPs extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'د هرې پاڼې پاڼې:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'tall';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.tall;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'لټون';
|
||||
@ -8586,7 +8586,7 @@ class MaterialLocalizationPt extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'Linhas por página:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'English-like';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.englishLike;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'Pesquisa';
|
||||
@ -8871,7 +8871,7 @@ class MaterialLocalizationRo extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'Rânduri pe pagină:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'English-like';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.englishLike;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'Căutați';
|
||||
@ -9072,7 +9072,7 @@ class MaterialLocalizationRu extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'Строк на странице:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'English-like';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.englishLike;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'Поиск';
|
||||
@ -9273,7 +9273,7 @@ class MaterialLocalizationSk extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'Počet riadkov na stránku:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'English-like';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.englishLike;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'Hľadať';
|
||||
@ -9474,7 +9474,7 @@ class MaterialLocalizationSl extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'Vrstice na stran:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'English-like';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.englishLike;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'Iskanje';
|
||||
@ -9675,7 +9675,7 @@ class MaterialLocalizationSr extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'Редова по страници:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'English-like';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.englishLike;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'Претражите';
|
||||
@ -10053,7 +10053,7 @@ class MaterialLocalizationSv extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'Rader per sida:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'English-like';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.englishLike;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'Sök';
|
||||
@ -10254,7 +10254,7 @@ class MaterialLocalizationTh extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'แถวต่อหน้า:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'tall';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.tall;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'ค้นหา';
|
||||
@ -10455,7 +10455,7 @@ class MaterialLocalizationTl extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'Mga row bawat page:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'English-like';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.englishLike;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'Maghanap';
|
||||
@ -10656,7 +10656,7 @@ class MaterialLocalizationTr extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'Sayfa başına satır sayısı:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'English-like';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.englishLike;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'Ara';
|
||||
@ -10857,7 +10857,7 @@ class MaterialLocalizationUk extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'Рядків на сторінці:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'English-like';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.englishLike;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'Пошук';
|
||||
@ -11058,7 +11058,7 @@ class MaterialLocalizationUr extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'قطاریں فی صفحہ:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'tall';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.tall;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'تلاش';
|
||||
@ -11259,7 +11259,7 @@ class MaterialLocalizationVi extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'Số hàng mỗi trang:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'English-like';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.englishLike;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'Tìm kiếm';
|
||||
@ -11460,7 +11460,7 @@ class MaterialLocalizationZh extends GlobalMaterialLocalizations {
|
||||
String get rowsPerPageTitle => r'每页行数:';
|
||||
|
||||
@override
|
||||
String get scriptCategory => r'dense';
|
||||
ScriptCategory get scriptCategory => ScriptCategory.dense;
|
||||
|
||||
@override
|
||||
String get searchFieldLabel => r'搜索';
|
||||
|
@ -1,7 +1,8 @@
|
||||
{
|
||||
"scriptCategory": "English-like",
|
||||
"@scriptCategory": {
|
||||
"description": "The name of the language's script category (see https://material.io/go/design-typography#typography-language-categories-reference)."
|
||||
"description": "The name of the language's script category (see https://material.io/design/typography/language-support.html#language-categories-reference).",
|
||||
"x-flutter-type": "scriptCategory"
|
||||
},
|
||||
|
||||
"timeOfDayFormat": "h:mm a",
|
||||
|
@ -502,18 +502,8 @@ abstract class GlobalMaterialLocalizations implements MaterialLocalizations {
|
||||
).replaceFirst(r'$remainingCount', formatDecimal(remainingCount));
|
||||
}
|
||||
|
||||
/// The script category used by [localTextGeometry]. Must be one of the strings
|
||||
/// declared in [MaterialTextGeometry].
|
||||
//
|
||||
// TODO(ianh): make this return a TextTheme from MaterialTextGeometry.
|
||||
// TODO(ianh): drop the constructor on MaterialTextGeometry.
|
||||
// TODO(ianh): drop the strings on MaterialTextGeometry.
|
||||
@protected
|
||||
String get scriptCategory;
|
||||
|
||||
/// Looks up text geometry defined in [MaterialTextGeometry].
|
||||
@override
|
||||
TextTheme get localTextGeometry => MaterialTextGeometry.forScriptCategory(scriptCategory);
|
||||
ScriptCategory get scriptCategory;
|
||||
|
||||
/// A [LocalizationsDelegate] that uses [GlobalMaterialLocalizations.load]
|
||||
/// to create an instance of this class.
|
||||
|
Loading…
x
Reference in New Issue
Block a user