Unverified Commit 9dce19e9 authored by Darren Austin's avatar Darren Austin Committed by GitHub

Replace ButtonBar.bar method with ButtonBarTheme (#37544)

* Added new ButtonBarTheme to replace the deprecated ButtonTheme.bar method.

* Responding to PR feedback.

* [Material] Create material Banner component (#36880)

This PR creates a new material widget for the Banner component. This includes a theme as well. This widget can be dropped into any application, ideally at the top of a listview or scrollview.

(cherry picked from commit 35b6d668)

Removed the use of ButtonTheme.bar in the Banner implementation.

* Updated documentation from PR review comments.
parent ae291745
......@@ -324,22 +324,20 @@ class TravelDestinationContent extends StatelessWidget {
if (destination.type == CardDemoType.standard) {
children.add(
// share, explore buttons
ButtonTheme.bar(
child: ButtonBar(
alignment: MainAxisAlignment.start,
children: <Widget>[
FlatButton(
child: Text('SHARE', semanticsLabel: 'Share ${destination.title}'),
textColor: Colors.amber.shade500,
onPressed: () { print('pressed'); },
),
FlatButton(
child: Text('EXPLORE', semanticsLabel: 'Explore ${destination.title}'),
textColor: Colors.amber.shade500,
onPressed: () { print('pressed'); },
),
],
),
ButtonBar(
alignment: MainAxisAlignment.start,
children: <Widget>[
FlatButton(
child: Text('SHARE', semanticsLabel: 'Share ${destination.title}'),
textColor: Colors.amber.shade500,
onPressed: () { print('pressed'); },
),
FlatButton(
child: Text('EXPLORE', semanticsLabel: 'Explore ${destination.title}'),
textColor: Colors.amber.shade500,
onPressed: () { print('pressed'); },
),
],
),
);
}
......
......@@ -32,6 +32,7 @@ export 'src/material/bottom_sheet.dart';
export 'src/material/bottom_sheet_theme.dart';
export 'src/material/button.dart';
export 'src/material/button_bar.dart';
export 'src/material/button_bar_theme.dart';
export 'src/material/button_theme.dart';
export 'src/material/card.dart';
export 'src/material/card_theme.dart';
......
......@@ -118,11 +118,9 @@ class MaterialBanner extends StatelessWidget {
?? bannerTheme.padding
?? const EdgeInsetsDirectional.only(end: 16.0);
final Widget buttonBar = ButtonTheme.bar(
final Widget buttonBar = ButtonBar(
layoutBehavior: ButtonBarLayoutBehavior.constrained,
child: ButtonBar(
children: actions,
),
children: actions,
);
final Color backgroundColor = this.backgroundColor
......
......@@ -4,6 +4,7 @@
import 'package:flutter/widgets.dart';
import 'button_bar_theme.dart';
import 'button_theme.dart';
import 'dialog.dart';
import 'flat_button.dart';
......@@ -11,12 +12,24 @@ import 'raised_button.dart';
/// An end-aligned row of buttons.
///
/// Places the buttons horizontally according to the padding in the current
/// [ButtonTheme]. The children are laid out in a [Row] with
/// [MainAxisAlignment.end]. When the [Directionality] is [TextDirection.ltr],
/// the button bar's children are right justified and the last child becomes
/// the rightmost child. When the [Directionality] [TextDirection.rtl] the
/// children are left justified and the last child becomes the leftmost child.
/// Places the buttons horizontally according to the [buttonPadding]. The
/// children are laid out in a [Row] with [MainAxisAlignment.end]. When the
/// [Directionality] is [TextDirection.ltr], the button bar's children are
/// right justified and the last child becomes the rightmost child. When the
/// [Directionality] [TextDirection.rtl] the children are left justified and
/// the last child becomes the leftmost child.
///
/// The [ButtonBar] can be configured with a [ButtonBarTheme]. For any null
/// property on the ButtonBar, the surrounding ButtonBarTheme's property
/// will be used instead. If the ButtonBarTheme's property is null
/// as well, the property will default to a value described in the field
/// documentation below.
///
/// The [children] are wrapped in a [ButtonTheme] that is a copy of the
/// surrounding ButtonTheme with the button properties overridden by the
/// properties of the ButtonBar as described above. These properties include
/// [buttonTextTheme], [buttonMinWidth], [buttonHeight], [buttonPadding],
/// and [buttonAlignedDropdown].
///
/// Used by [Dialog] to arrange the actions at the bottom of the dialog.
///
......@@ -26,24 +39,84 @@ import 'raised_button.dart';
/// * [FlatButton], another kind of button.
/// * [Card], at the bottom of which it is common to place a [ButtonBar].
/// * [Dialog], which uses a [ButtonBar] for its actions.
/// * [ButtonTheme], which configures the [ButtonBar].
/// * [ButtonBarTheme], which configures the [ButtonBar].
class ButtonBar extends StatelessWidget {
/// Creates a button bar.
///
/// The alignment argument defaults to [MainAxisAlignment.end].
/// Both [buttonMinWidth] and [buttonHeight] must be non-negative if they
/// are not null.
const ButtonBar({
Key key,
this.alignment = MainAxisAlignment.end,
this.mainAxisSize = MainAxisSize.max,
this.alignment,
this.mainAxisSize,
this.buttonTextTheme,
this.buttonMinWidth,
this.buttonHeight,
this.buttonPadding,
this.buttonAlignedDropdown,
this.layoutBehavior,
this.children = const <Widget>[],
}) : super(key: key);
}) : assert(buttonMinWidth == null || buttonMinWidth >= 0.0),
assert(buttonHeight == null || buttonHeight >= 0.0),
super(key: key);
/// How the children should be placed along the horizontal axis.
///
/// If null then it will use [ButtonBarTheme.alignment]. If that is null,
/// it will default to [MainAxisAlignment.end].
final MainAxisAlignment alignment;
/// How much horizontal space is available. See [Row.mainAxisSize].
///
/// If null then it will use the surrounding [ButtonBarTheme.mainAxisSize].
/// If that is null, it will default to [MainAxisSize.max].
final MainAxisSize mainAxisSize;
/// Overrides the surrounding [ButtonTheme.textTheme] to define a button's
/// base colors, size, internal padding and shape.
///
/// If null then it will use the surrounding [ButtonBarTheme.buttonTextTheme].
/// If that is null, it will default to [ButtonTextTheme.primary].
final ButtonTextTheme buttonTextTheme;
/// Overrides the surrounding [ButtonThemeData.minWidth] to define a button's
/// minimum width.
///
/// If null then it will use the surrounding [ButtonBarTheme.buttonMinWidth].
/// If that is null, it will default to 64.0 logical pixels.
final double buttonMinWidth;
/// Overrides the surrounding [ButtonThemeData.height] to define a button's
/// minimum height.
///
/// If null then it will use the surrounding [ButtonBarTheme.buttonHeight].
/// If that is null, it will default to 36.0 logical pixels.
final double buttonHeight;
/// Overrides the surrounding [ButtonThemeData.padding] to define the padding
/// for a button's child (typically the button's label).
///
/// If null then it will use the surrounding [ButtonBarTheme.buttonPadding].
/// If that is null, it will default to 8.0 logical pixels on the left
/// and right.
final EdgeInsetsGeometry buttonPadding;
/// Overrides the surrounding [ButtonThemeData.alignedDropdown] to define whether
/// a [DropdownButton] menu's width will match the button's width.
///
/// If null then it will use the surrounding [ButtonBarTheme.buttonAlignedDropdown].
/// If that is null, it will default to false.
final bool buttonAlignedDropdown;
/// Defines whether a [ButtonBar] should size itself with a minimum size
/// constraint or with padding.
///
/// Overrides the surrounding [ButtonThemeData.layoutBehavior].
///
/// If null then it will use the surrounding [ButtonBarTheme.layoutBehavior].
/// If that is null, it will default [ButtonBarLayoutBehavior.padded].
final ButtonBarLayoutBehavior layoutBehavior;
/// The buttons to arrange horizontally.
///
/// Typically [RaisedButton] or [FlatButton] widgets.
......@@ -51,18 +124,32 @@ class ButtonBar extends StatelessWidget {
@override
Widget build(BuildContext context) {
final ButtonThemeData buttonTheme = ButtonTheme.of(context);
final ButtonThemeData parentButtonTheme = ButtonTheme.of(context);
final ButtonBarThemeData barTheme = ButtonBarTheme.of(context);
final ButtonThemeData buttonTheme = parentButtonTheme.copyWith(
textTheme: buttonTextTheme ?? barTheme.buttonTextTheme ?? ButtonTextTheme.primary,
minWidth: buttonMinWidth ?? barTheme.buttonMinWidth ?? 64.0,
height: buttonHeight ?? barTheme.buttonHeight ?? 36.0,
padding: buttonPadding ?? barTheme.buttonPadding ?? const EdgeInsets.symmetric(horizontal: 8.0),
alignedDropdown: buttonAlignedDropdown ?? barTheme.buttonAlignedDropdown ?? false,
layoutBehavior: layoutBehavior ?? barTheme.layoutBehavior ?? ButtonBarLayoutBehavior.padded,
);
// We divide by 4.0 because we want half of the average of the left and right padding.
final double paddingUnit = buttonTheme.padding.horizontal / 4.0;
final Widget child = Row(
mainAxisAlignment: alignment,
mainAxisSize: mainAxisSize,
children: children.map<Widget>((Widget child) {
return Padding(
padding: EdgeInsets.symmetric(horizontal: paddingUnit),
child: child,
);
}).toList(),
final Widget child = ButtonTheme.fromButtonThemeData(
data: buttonTheme,
child: Row(
mainAxisAlignment: alignment ?? barTheme.alignment ?? MainAxisAlignment.end,
mainAxisSize: mainAxisSize ?? barTheme.mainAxisSize ?? MainAxisSize.max,
children: children.map<Widget>((Widget child) {
return Padding(
padding: EdgeInsets.symmetric(horizontal: paddingUnit),
child: child,
);
}).toList(),
),
);
switch (buttonTheme.layoutBehavior) {
case ButtonBarLayoutBehavior.padded:
......
// Copyright 2019 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 'dart:ui' show lerpDouble;
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'button_theme.dart';
import 'theme.dart';
/// Defines the visual properties of [ButtonBar] widgets.
///
/// Used by [ButtonBarTheme] to control the visual properties of [ButtonBar]
/// instances in a widget subtree.
///
/// To obtain this configuration, use [ButtonBarTheme.of] to access the closest
/// ancestor [ButtonBarTheme] of the current [BuildContext].
///
/// See also:
///
/// * [ButtonBarTheme], an [InheritedWidget] that propagates the theme down
/// its subtree.
/// * [ButtonBar], which uses this to configure itself and its children
/// button widgets.
class ButtonBarThemeData extends Diagnosticable {
/// Constructs the set of properties used to configure [ButtonBar] widgets.
///
/// Both [buttonMinWidth] and [buttonHeight] must be non-negative if they
/// are not null.
const ButtonBarThemeData({
this.alignment,
this.mainAxisSize,
this.buttonTextTheme,
this.buttonMinWidth,
this.buttonHeight,
this.buttonPadding,
this.buttonAlignedDropdown,
this.layoutBehavior,
}) : assert(buttonMinWidth == null || buttonMinWidth >= 0.0),
assert(buttonHeight == null || buttonHeight >= 0.0);
/// How the children should be placed along the horizontal axis.
final MainAxisAlignment alignment;
/// How much horizontal space is available. See [Row.mainAxisSize].
final MainAxisSize mainAxisSize;
/// Defines a [ButtonBar] button's base colors, and the defaults for
/// the button's minimum size, internal padding, and shape.
///
/// This will override the surrounding [ButtonTheme.textTheme] setting
/// for buttons contained in the [ButtonBar].
///
/// Despite the name, this property is not a [TextTheme], its value is not a
/// collection of [TextStyle]s.
final ButtonTextTheme buttonTextTheme;
/// The minimum width for [ButtonBar] buttons.
///
/// This will override the surrounding [ButtonTheme.minWidth] setting
/// for buttons contained in the [ButtonBar].
///
/// The actual horizontal space allocated for a button's child is
/// at least this value less the theme's horizontal [padding].
final double buttonMinWidth;
/// The minimum height for [ButtonBar] buttons.
///
/// This will override the surrounding [ButtonTheme.height] setting
/// for buttons contained in the [ButtonBar].
final double buttonHeight;
/// Padding for a [ButtonBar] button's child (typically the button's label).
///
/// This will override the surrounding [ButtonTheme.padding] setting
/// for buttons contained in the [ButtonBar].
final EdgeInsetsGeometry buttonPadding;
/// If true, then a [DropdownButton] menu's width will match the [ButtonBar]
/// button's width.
///
/// If false, then the dropdown's menu will be wider than
/// its button. In either case the dropdown button will line up the leading
/// edge of the menu's value with the leading edge of the values
/// displayed by the menu items.
///
/// This will override the surrounding [ButtonTheme.alignedDropdown] setting
/// for buttons contained in the [ButtonBar].
///
/// This property only affects [DropdownButton] contained in a [ButtonBar]
/// and its menu.
final bool buttonAlignedDropdown;
/// Defines whether a [ButtonBar] should size itself with a minimum size
/// constraint or with padding.
final ButtonBarLayoutBehavior layoutBehavior;
/// Creates a copy of this object but with the given fields replaced with the
/// new values.
ButtonBarThemeData copyWith({
MainAxisAlignment alignment,
MainAxisSize mainAxisSize,
ButtonTextTheme buttonTextTheme,
double buttonMinWidth,
double buttonHeight,
EdgeInsetsGeometry buttonPadding,
bool buttonAlignedDropdown,
ButtonBarLayoutBehavior layoutBehavior,
}) {
return ButtonBarThemeData(
alignment: alignment ?? this.alignment,
mainAxisSize: mainAxisSize ?? this.mainAxisSize,
buttonTextTheme: buttonTextTheme ?? this.buttonTextTheme,
buttonMinWidth: buttonMinWidth ?? this.buttonMinWidth,
buttonHeight: buttonHeight ?? this.buttonHeight,
buttonPadding: buttonPadding ?? this.buttonPadding,
buttonAlignedDropdown: buttonAlignedDropdown ?? this.buttonAlignedDropdown,
layoutBehavior: layoutBehavior ?? this.layoutBehavior,
);
}
/// Linearly interpolate between two button bar themes.
///
/// If both arguments are null, then null is returned.
///
/// {@macro dart.ui.shadow.lerp}
static ButtonBarThemeData lerp(ButtonBarThemeData a, ButtonBarThemeData b, double t) {
assert(t != null);
if (a == null && b == null)
return null;
return ButtonBarThemeData(
alignment: t < 0.5 ? a.alignment : b.alignment,
mainAxisSize: t < 0.5 ? a.mainAxisSize : b.mainAxisSize,
buttonTextTheme: t < 0.5 ? a.buttonTextTheme : b.buttonTextTheme,
buttonMinWidth: lerpDouble(a?.buttonMinWidth, b?.buttonMinWidth, t),
buttonHeight: lerpDouble(a?.buttonHeight, b?.buttonHeight, t),
buttonPadding: EdgeInsets.lerp(a?.buttonPadding, b?.buttonPadding, t),
buttonAlignedDropdown: t < 0.5 ? a.buttonAlignedDropdown : b.buttonAlignedDropdown,
layoutBehavior: t < 0.5 ? a.layoutBehavior : b.layoutBehavior,
);
}
@override
int get hashCode {
return hashValues(
alignment,
mainAxisSize,
buttonTextTheme,
buttonMinWidth,
buttonHeight,
buttonPadding,
buttonAlignedDropdown,
layoutBehavior,
);
}
@override
bool operator ==(Object other) {
if (identical(this, other))
return true;
if (other.runtimeType != runtimeType)
return false;
final ButtonBarThemeData typedOther = other;
return typedOther.alignment == alignment
&& typedOther.mainAxisSize == mainAxisSize
&& typedOther.buttonTextTheme == buttonTextTheme
&& typedOther.buttonMinWidth == buttonMinWidth
&& typedOther.buttonHeight == buttonHeight
&& typedOther.buttonPadding == buttonPadding
&& typedOther.buttonAlignedDropdown == buttonAlignedDropdown
&& typedOther.layoutBehavior == layoutBehavior;
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(DiagnosticsProperty<MainAxisAlignment>('alignment', alignment, defaultValue: null));
properties.add(DiagnosticsProperty<MainAxisSize>('mainAxisSize', mainAxisSize, defaultValue: null));
properties.add(DiagnosticsProperty<ButtonTextTheme>('textTheme', buttonTextTheme, defaultValue: null));
properties.add(DoubleProperty('minWidth', buttonMinWidth, defaultValue: null));
properties.add(DoubleProperty('height', buttonHeight, defaultValue: null));
properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('padding', buttonPadding, defaultValue: null));
properties.add(FlagProperty(
'buttonAlignedDropdown',
value: buttonAlignedDropdown,
ifTrue: 'dropdown width matches button',
defaultValue: null));
properties.add(DiagnosticsProperty<ButtonBarLayoutBehavior>('layoutBehavior', layoutBehavior, defaultValue: null));
}
}
/// Applies a button bar theme to descendant [ButtonBar] widgets.
///
/// A button bar theme describes the layout and properties for the buttons
/// contained in a [ButtonBar].
///
/// Descendant widgets obtain the current theme's [ButtonBarTheme] object using
/// [ButtonBarTheme.of]. When a widget uses [ButtonBarTheme.of], it is automatically
/// rebuilt if the theme later changes.
///
/// A button bar theme can be specified as part of the overall Material theme
/// using [ThemeData.buttonBarTheme].
///
/// See also:
///
/// * [ButtonBarThemeData], which describes the actual configuration of a button
/// bar theme.
class ButtonBarTheme extends InheritedWidget {
/// Constructs a button bar theme that configures all descendent [ButtonBar]
/// widgets.
///
/// The [data] must not be null.
const ButtonBarTheme({
Key key,
@required this.data,
Widget child,
}) : assert(data != null), super(key: key, child: child);
/// The properties used for all descendant [ButtonBar] widgets.
final ButtonBarThemeData data;
/// Returns the configuration [data] from the closest [ButtonBarTheme]
/// ancestor. If there is no ancestor, it returns [ThemeData.buttonBarTheme].
/// Applications can assume that the returned value will not be null.
///
/// Typical usage is as follows:
///
/// ```dart
/// ButtonBarThemeData theme = ButtonBarTheme.of(context);
/// ```
static ButtonBarThemeData of(BuildContext context) {
final ButtonBarTheme buttonBarTheme = context.inheritFromWidgetOfExactType(ButtonBarTheme);
return buttonBarTheme?.data ?? Theme.of(context).buttonBarTheme;
}
@override
bool updateShouldNotify(ButtonBarTheme oldWidget) => data != oldWidget.data;
}
......@@ -120,20 +120,51 @@ class ButtonTheme extends InheritedWidget {
}) : assert(data != null),
super(key: key, child: child);
// TODO(darrenaustin): remove after this deprecation warning has been on
// stable for a couple of releases.
// See https://github.com/flutter/flutter/issues/37333
//
/// Creates a button theme that is appropriate for button bars, as used in
/// dialog footers and in the headers of data tables.
///
/// This theme is denser, with a smaller [minWidth] and [padding], than the
/// default theme. Also, this theme uses [ButtonTextTheme.accent] rather than
/// [ButtonTextTheme.normal].
/// Deprecated. Please use [ButtonBarTheme] instead which offers more
/// flexibility to configure [ButtonBar] widgets.
///
/// To migrate instances of code that were just wrapping a [ButtonBar]:
///
/// ```dart
/// ButtonTheme.bar(
/// child: ButtonBar(...)
/// );
/// ```
///
/// you can just remove the `ButtonTheme.bar` as the defaults are now handled
/// by [ButtonBar] directly.
///
/// If you have more complicated usages of `ButtonTheme.bar` like:
///
/// For best effect, the label of the button at the edge of the container
/// should have text that ends up wider than 64.0 pixels. This ensures that
/// the alignment of the text matches the alignment of the edge of the
/// container.
/// ```dart
/// ButtonTheme.bar(
/// padding: EdgeInsets.symmetric(horizontal: 10.0),
/// textTheme: ButtonTextTheme.accent,
/// child: ButtonBar(...),
/// );
/// ```
///
/// you can remove the `ButtonTheme.bar` and move the parameters to the
/// [ButtonBar] instance directly:
///
/// ```dart
/// ButtonBar(
/// padding: EdgeInsets.symmetric(horizontal: 10.0),
/// textTheme: ButtonTextTheme.accent,
/// ...
/// );
/// ```
///
/// For example, buttons at the bottom of [Dialog] or [Card] widgets use this
/// button theme.
/// You can also replace the defaults for all [ButtonBar] widgets by updating
/// [ThemeData.buttonBarTheme] for your app.
@Deprecated('use ButtonBarTheme instead')
ButtonTheme.bar({
Key key,
ButtonTextTheme textTheme = ButtonTextTheme.accent,
......
......@@ -36,19 +36,17 @@ import 'theme.dart';
/// title: Text('The Enchanted Nightingale'),
/// subtitle: Text('Music by Julie Gable. Lyrics by Sidney Stein.'),
/// ),
/// ButtonTheme.bar( // make buttons use the appropriate styles for cards
/// child: ButtonBar(
/// children: <Widget>[
/// FlatButton(
/// child: const Text('BUY TICKETS'),
/// onPressed: () { /* ... */ },
/// ),
/// FlatButton(
/// child: const Text('LISTEN'),
/// onPressed: () { /* ... */ },
/// ),
/// ],
/// ),
/// ButtonBar(
/// children: <Widget>[
/// FlatButton(
/// child: const Text('BUY TICKETS'),
/// onPressed: () { /* ... */ },
/// ),
/// FlatButton(
/// child: const Text('LISTEN'),
/// onPressed: () { /* ... */ },
/// ),
/// ],
/// ),
/// ],
/// ),
......@@ -92,8 +90,7 @@ import 'theme.dart';
/// See also:
///
/// * [ListTile], to display icons and text in a card.
/// * [ButtonBar], to display buttons at the bottom of a card. Typically these
/// would be styled using a [ButtonTheme] created with [new ButtonTheme.bar].
/// * [ButtonBar], to display buttons at the bottom of a card.
/// * [showDialog], to display a modal card.
/// * <https://material.io/design/components/cards.html>
class Card extends StatelessWidget {
......
......@@ -11,7 +11,6 @@ import 'package:flutter/widgets.dart';
import 'package:flutter/gestures.dart' show DragStartBehavior;
import 'button_bar.dart';
import 'button_theme.dart';
import 'colors.dart';
import 'debug.dart';
import 'dialog.dart';
......@@ -986,19 +985,17 @@ class _DatePickerDialogState extends State<_DatePickerDialog> {
Widget build(BuildContext context) {
final ThemeData theme = Theme.of(context);
final Widget picker = _buildPicker();
final Widget actions = ButtonTheme.bar(
child: ButtonBar(
children: <Widget>[
FlatButton(
child: Text(localizations.cancelButtonLabel),
onPressed: _handleCancel,
),
FlatButton(
child: Text(localizations.okButtonLabel),
onPressed: _handleOk,
),
],
),
final Widget actions = ButtonBar(
children: <Widget>[
FlatButton(
child: Text(localizations.cancelButtonLabel),
onPressed: _handleCancel,
),
FlatButton(
child: Text(localizations.okButtonLabel),
onPressed: _handleOk,
),
],
);
final Dialog dialog = Dialog(
......
......@@ -8,7 +8,6 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'button_bar.dart';
import 'button_theme.dart';
import 'colors.dart';
import 'debug.dart';
import 'dialog_theme.dart';
......@@ -343,10 +342,8 @@ class AlertDialog extends StatelessWidget {
}
if (actions != null) {
children.add(ButtonTheme.bar(
child: ButtonBar(
children: actions,
),
children.add(ButtonBar(
children: actions,
));
}
......
......@@ -9,7 +9,6 @@ import 'package:flutter/rendering.dart';
import 'package:flutter/gestures.dart' show DragStartBehavior;
import 'button_bar.dart';
import 'button_theme.dart';
import 'card.dart';
import 'constants.dart';
import 'data_table.dart';
......@@ -439,16 +438,14 @@ class PaginatedDataTableState extends State<PaginatedDataTable> {
data: const IconThemeData(
opacity: 0.54
),
child: ButtonTheme.bar(
child: Ink(
height: 64.0,
color: _selectedRowCount > 0 ? themeData.secondaryHeaderColor : null,
child: Padding(
padding: EdgeInsetsDirectional.only(start: startPadding, end: 14.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: headerWidgets,
),
child: Ink(
height: 64.0,
color: _selectedRowCount > 0 ? themeData.secondaryHeaderColor : null,
child: Padding(
padding: EdgeInsetsDirectional.only(start: startPadding, end: 14.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: headerWidgets,
),
),
),
......
......@@ -14,7 +14,6 @@ import 'package:flutter/gestures.dart' show DragStartBehavior;
import 'app_bar.dart';
import 'bottom_sheet.dart';
import 'button_bar.dart';
import 'button_theme.dart';
import 'colors.dart';
import 'divider.dart';
import 'drawer.dart';
......@@ -2154,13 +2153,9 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin {
),
),
child: SafeArea(
child: ButtonTheme.bar(
child: SafeArea(
top: false,
child: ButtonBar(
children: widget.persistentFooterButtons,
),
),
top: false,
child: ButtonBar(
children: widget.persistentFooterButtons,
),
),
),
......
......@@ -301,9 +301,10 @@ class SnackBar extends StatelessWidget {
),
];
if (action != null) {
children.add(ButtonTheme.bar(
padding: EdgeInsets.symmetric(horizontal: snackBarPadding),
children.add(ButtonTheme(
textTheme: ButtonTextTheme.accent,
minWidth: 64.0,
padding: EdgeInsets.symmetric(horizontal: snackBarPadding),
child: action,
));
} else {
......
......@@ -13,6 +13,7 @@ import 'app_bar_theme.dart';
import 'banner_theme.dart';
import 'bottom_app_bar_theme.dart';
import 'bottom_sheet_theme.dart';
import 'button_bar_theme.dart';
import 'button_theme.dart';
import 'card_theme.dart';
import 'chip_theme.dart';
......@@ -180,6 +181,7 @@ class ThemeData extends Diagnosticable {
PopupMenuThemeData popupMenuTheme,
MaterialBannerThemeData bannerTheme,
DividerThemeData dividerTheme,
ButtonBarThemeData buttonBarTheme,
}) {
brightness ??= Brightness.light;
final bool isDark = brightness == Brightness.dark;
......@@ -285,6 +287,7 @@ class ThemeData extends Diagnosticable {
popupMenuTheme ??= const PopupMenuThemeData();
bannerTheme ??= const MaterialBannerThemeData();
dividerTheme ??= const DividerThemeData();
buttonBarTheme ??= const ButtonBarThemeData();
return ThemeData.raw(
brightness: brightness,
......@@ -348,6 +351,7 @@ class ThemeData extends Diagnosticable {
popupMenuTheme: popupMenuTheme,
bannerTheme: bannerTheme,
dividerTheme: dividerTheme,
buttonBarTheme: buttonBarTheme,
);
}
......@@ -423,6 +427,7 @@ class ThemeData extends Diagnosticable {
@required this.popupMenuTheme,
@required this.bannerTheme,
@required this.dividerTheme,
@required this.buttonBarTheme,
}) : assert(brightness != null),
assert(primaryColor != null),
assert(primaryColorBrightness != null),
......@@ -480,7 +485,8 @@ class ThemeData extends Diagnosticable {
assert(bottomSheetTheme != null),
assert(popupMenuTheme != null),
assert(bannerTheme != null),
assert(dividerTheme != null);
assert(dividerTheme != null),
assert(buttonBarTheme != null);
/// Create a [ThemeData] based on the colors in the given [colorScheme] and
/// text styles of the optional [textTheme].
......@@ -877,6 +883,9 @@ class ThemeData extends Diagnosticable {
/// [VerticalDivider]s, etc.
final DividerThemeData dividerTheme;
/// A theme for customizing the appearance and layout of [ButtonBar] widgets.
final ButtonBarThemeData buttonBarTheme;
/// Creates a copy of this theme but with the given fields replaced with the new values.
ThemeData copyWith({
Brightness brightness,
......@@ -940,6 +949,7 @@ class ThemeData extends Diagnosticable {
PopupMenuThemeData popupMenuTheme,
MaterialBannerThemeData bannerTheme,
DividerThemeData dividerTheme,
ButtonBarThemeData buttonBarTheme,
}) {
cupertinoOverrideTheme = cupertinoOverrideTheme?.noDefault();
return ThemeData.raw(
......@@ -1004,6 +1014,7 @@ class ThemeData extends Diagnosticable {
popupMenuTheme: popupMenuTheme ?? this.popupMenuTheme,
bannerTheme: bannerTheme ?? this.bannerTheme,
dividerTheme: dividerTheme ?? this.dividerTheme,
buttonBarTheme: buttonBarTheme ?? this.buttonBarTheme,
);
}
......@@ -1146,6 +1157,7 @@ class ThemeData extends Diagnosticable {
popupMenuTheme: PopupMenuThemeData.lerp(a.popupMenuTheme, b.popupMenuTheme, t),
bannerTheme: MaterialBannerThemeData.lerp(a.bannerTheme, b.bannerTheme, t),
dividerTheme: DividerThemeData.lerp(a.dividerTheme, b.dividerTheme, t),
buttonBarTheme: ButtonBarThemeData.lerp(a.buttonBarTheme, b.buttonBarTheme, t),
);
}
......@@ -1215,7 +1227,8 @@ class ThemeData extends Diagnosticable {
(otherData.bottomSheetTheme == bottomSheetTheme) &&
(otherData.popupMenuTheme == popupMenuTheme) &&
(otherData.bannerTheme == bannerTheme) &&
(otherData.dividerTheme == dividerTheme);
(otherData.dividerTheme == dividerTheme) &&
(otherData.buttonBarTheme == buttonBarTheme);
}
@override
......@@ -1285,6 +1298,7 @@ class ThemeData extends Diagnosticable {
popupMenuTheme,
bannerTheme,
dividerTheme,
buttonBarTheme,
];
return hashList(values);
}
......@@ -1351,6 +1365,7 @@ class ThemeData extends Diagnosticable {
properties.add(DiagnosticsProperty<PopupMenuThemeData>('popupMenuTheme', popupMenuTheme, defaultValue: defaultData.popupMenuTheme));
properties.add(DiagnosticsProperty<MaterialBannerThemeData>('bannerTheme', bannerTheme, defaultValue: defaultData.bannerTheme));
properties.add(DiagnosticsProperty<DividerThemeData>('dividerTheme', dividerTheme, defaultValue: defaultData.dividerTheme));
properties.add(DiagnosticsProperty<ButtonBarThemeData>('buttonBarTheme', buttonBarTheme, defaultValue: defaultData.buttonBarTheme));
}
}
......
......@@ -10,7 +10,6 @@ import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'button_bar.dart';
import 'button_theme.dart';
import 'colors.dart';
import 'debug.dart';
import 'dialog.dart';
......@@ -1613,19 +1612,17 @@ class _TimePickerDialogState extends State<_TimePickerDialog> {
),
);
final Widget actions = ButtonTheme.bar(
child: ButtonBar(
children: <Widget>[
FlatButton(
child: Text(localizations.cancelButtonLabel),
onPressed: _handleCancel,
),
FlatButton(
child: Text(localizations.okButtonLabel),
onPressed: _handleOk,
),
],
),
final Widget actions = ButtonBar(
children: <Widget>[
FlatButton(
child: Text(localizations.cancelButtonLabel),
onPressed: _handleCancel,
),
FlatButton(
child: Text(localizations.okButtonLabel),
onPressed: _handleOk,
),
],
);
final Dialog dialog = Dialog(
......
// Copyright 2019 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/rendering.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
test('ButtonBarThemeData null fields by default', () {
const ButtonBarThemeData buttonBarTheme = ButtonBarThemeData();
expect(buttonBarTheme.alignment, null);
expect(buttonBarTheme.mainAxisSize, null);
expect(buttonBarTheme.buttonTextTheme, null);
expect(buttonBarTheme.buttonMinWidth, null);
expect(buttonBarTheme.buttonHeight, null);
expect(buttonBarTheme.buttonPadding, null);
expect(buttonBarTheme.buttonAlignedDropdown, null);
expect(buttonBarTheme.layoutBehavior, null);
});
test('ThemeData uses default ButtonBarThemeData', () {
expect(ThemeData().buttonBarTheme, equals(const ButtonBarThemeData()));
});
test('ButtonBarThemeData copyWith, ==, hashCode basics', () {
expect(const ButtonBarThemeData(), const ButtonBarThemeData().copyWith());
expect(const ButtonBarThemeData().hashCode, const ButtonBarThemeData().copyWith().hashCode);
});
testWidgets('ButtonBarThemeData lerps correctly', (WidgetTester tester) async {
const ButtonBarThemeData barThemePrimary = ButtonBarThemeData(
alignment: MainAxisAlignment.end,
mainAxisSize: MainAxisSize.min,
buttonTextTheme: ButtonTextTheme.primary,
buttonMinWidth: 20.0,
buttonHeight: 20.0,
buttonPadding: EdgeInsets.symmetric(vertical: 5.0),
buttonAlignedDropdown: false,
layoutBehavior: ButtonBarLayoutBehavior.padded,
);
const ButtonBarThemeData barThemeAccent = ButtonBarThemeData(
alignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
buttonTextTheme: ButtonTextTheme.accent,
buttonMinWidth: 10.0,
buttonHeight: 40.0,
buttonPadding: EdgeInsets.symmetric(horizontal: 10.0),
buttonAlignedDropdown: true,
layoutBehavior: ButtonBarLayoutBehavior.constrained,
);
final ButtonBarThemeData lerp = ButtonBarThemeData.lerp(barThemePrimary, barThemeAccent, 0.5);
expect(lerp.alignment, equals(MainAxisAlignment.center));
expect(lerp.mainAxisSize, equals(MainAxisSize.max));
expect(lerp.buttonTextTheme, equals(ButtonTextTheme.accent));
expect(lerp.buttonMinWidth, equals(15.0));
expect(lerp.buttonHeight, equals(30.0));
expect(lerp.buttonPadding, equals(const EdgeInsets.fromLTRB(5.0, 2.5, 5.0, 2.5)));
expect(lerp.buttonAlignedDropdown, isTrue);
expect(lerp.layoutBehavior, equals(ButtonBarLayoutBehavior.constrained));
});
testWidgets('Default ButtonBarThemeData debugFillProperties', (WidgetTester tester) async {
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
const ButtonBarThemeData().debugFillProperties(builder);
final List<String> description = builder.properties
.where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
.map((DiagnosticsNode node) => node.toString())
.toList();
expect(description, <String>[]);
});
testWidgets('ButtonBarThemeData implements debugFillProperties', (WidgetTester tester) async {
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
const ButtonBarThemeData(
alignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
buttonTextTheme: ButtonTextTheme.accent,
buttonMinWidth: 10.0,
buttonHeight: 42.0,
buttonPadding: EdgeInsets.symmetric(horizontal: 7.3),
buttonAlignedDropdown: true,
layoutBehavior: ButtonBarLayoutBehavior.constrained,
).debugFillProperties(builder);
final List<String> description = builder.properties
.where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
.map((DiagnosticsNode node) => node.toString())
.toList();
expect(description, <String>[
'alignment: MainAxisAlignment.center',
'mainAxisSize: MainAxisSize.max',
'textTheme: ButtonTextTheme.accent',
'minWidth: 10.0',
'height: 42.0',
'padding: EdgeInsets(7.3, 0.0, 7.3, 0.0)',
'dropdown width matches button',
'layoutBehavior: ButtonBarLayoutBehavior.constrained',
]);
});
testWidgets('ButtonBarTheme.of falls back to ThemeData.buttonBarTheme', (WidgetTester tester) async {
const ButtonBarThemeData buttonBarTheme = ButtonBarThemeData(buttonMinWidth: 42.0);
BuildContext capturedContext;
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(buttonBarTheme: buttonBarTheme),
home: Builder(
builder: (BuildContext context) {
capturedContext = context;
return Container();
}
)
)
);
expect(ButtonBarTheme.of(capturedContext), equals(buttonBarTheme));
expect(ButtonBarTheme.of(capturedContext).buttonMinWidth, equals(42.0));
});
testWidgets('ButtonBarTheme overrides ThemeData.buttonBarTheme', (WidgetTester tester) async {
const ButtonBarThemeData defaultBarTheme = ButtonBarThemeData(buttonMinWidth: 42.0);
const ButtonBarThemeData buttonBarTheme = ButtonBarThemeData(buttonMinWidth: 84.0);
BuildContext capturedContext;
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(buttonBarTheme: defaultBarTheme),
home: Builder(
builder: (BuildContext context) {
return ButtonBarTheme(
data: buttonBarTheme,
child: Builder(
builder: (BuildContext context) {
capturedContext = context;
return Container();
},
),
);
}
)
)
);
expect(ButtonBarTheme.of(capturedContext), equals(buttonBarTheme));
expect(ButtonBarTheme.of(capturedContext).buttonMinWidth, equals(84.0));
});
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment