| // Copyright 2015 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/widgets.dart'; |
| |
| import 'button_bar_theme.dart'; |
| import 'button_theme.dart'; |
| import 'dialog.dart'; |
| import 'flat_button.dart'; |
| import 'raised_button.dart'; |
| |
| /// An end-aligned row of buttons. |
| /// |
| /// 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. |
| /// |
| /// See also: |
| /// |
| /// * [RaisedButton], a kind of button. |
| /// * [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. |
| /// * [ButtonBarTheme], which configures the [ButtonBar]. |
| class ButtonBar extends StatelessWidget { |
| /// Creates a button bar. |
| /// |
| /// Both [buttonMinWidth] and [buttonHeight] must be non-negative if they |
| /// are not null. |
| const ButtonBar({ |
| Key key, |
| this.alignment, |
| this.mainAxisSize, |
| this.buttonTextTheme, |
| this.buttonMinWidth, |
| this.buttonHeight, |
| this.buttonPadding, |
| this.buttonAlignedDropdown, |
| this.layoutBehavior, |
| this.children = const <Widget>[], |
| }) : 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. |
| final List<Widget> children; |
| |
| @override |
| Widget build(BuildContext 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 = 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: |
| return Padding( |
| padding: EdgeInsets.symmetric( |
| vertical: 2.0 * paddingUnit, |
| horizontal: paddingUnit, |
| ), |
| child: child, |
| ); |
| case ButtonBarLayoutBehavior.constrained: |
| return Container( |
| padding: EdgeInsets.symmetric(horizontal: paddingUnit), |
| constraints: const BoxConstraints(minHeight: 52.0), |
| alignment: Alignment.center, |
| child: child, |
| ); |
| } |
| assert(false); |
| return null; |
| } |
| } |