Extended ButtonTheme, RoundedRectangleBorder, gallery buttons demo (#15723)
diff --git a/examples/flutter_gallery/lib/demo/material/buttons_demo.dart b/examples/flutter_gallery/lib/demo/material/buttons_demo.dart
index e63ac88..d68d7f1 100644
--- a/examples/flutter_gallery/lib/demo/material/buttons_demo.dart
+++ b/examples/flutter_gallery/lib/demo/material/buttons_demo.dart
@@ -53,25 +53,40 @@
}
class _ButtonsDemoState extends State<ButtonsDemo> {
+ ShapeBorder _buttonShape;
+
@override
Widget build(BuildContext context) {
+ final ButtonThemeData buttonTheme = ButtonTheme.of(context).copyWith(
+ shape: _buttonShape
+ );
+
final List<ComponentDemoTabData> demos = <ComponentDemoTabData>[
new ComponentDemoTabData(
tabName: 'RAISED',
description: _raisedText,
- demoWidget: buildRaisedButton(),
+ demoWidget: new ButtonTheme.fromButtonThemeData(
+ data: buttonTheme,
+ child: buildRaisedButton(),
+ ),
exampleCodeTag: _raisedCode,
),
new ComponentDemoTabData(
tabName: 'FLAT',
description: _flatText,
- demoWidget: buildFlatButton(),
+ demoWidget: new ButtonTheme.fromButtonThemeData(
+ data: buttonTheme,
+ child: buildFlatButton(),
+ ),
exampleCodeTag: _flatCode,
),
new ComponentDemoTabData(
tabName: 'OUTLINE',
description: _outlineText,
- demoWidget: buildOutlineButton(),
+ demoWidget: new ButtonTheme.fromButtonThemeData(
+ data: buttonTheme,
+ child: buildOutlineButton(),
+ ),
exampleCodeTag: _outlineCode,
),
new ComponentDemoTabData(
@@ -97,6 +112,16 @@
return new TabbedComponentDemoScaffold(
title: 'Buttons',
demos: demos,
+ actions: <Widget>[
+ new IconButton(
+ icon: const Icon(Icons.sentiment_very_satisfied),
+ onPressed: () {
+ setState(() {
+ _buttonShape = _buttonShape == null ? const StadiumBorder() : null;
+ });
+ },
+ ),
+ ],
);
}
diff --git a/examples/flutter_gallery/lib/demo/material/scrollable_tabs_demo.dart b/examples/flutter_gallery/lib/demo/material/scrollable_tabs_demo.dart
index 45e82ac..0c33e20 100644
--- a/examples/flutter_gallery/lib/demo/material/scrollable_tabs_demo.dart
+++ b/examples/flutter_gallery/lib/demo/material/scrollable_tabs_demo.dart
@@ -63,9 +63,9 @@
});
}
- ShapeDecoration getIndicator() {
+ Decoration getIndicator() {
if (!_customIndicator)
- return null;
+ return const UnderlineTabIndicator();
switch(_demoStyle) {
case TabsDemoStyle.iconsAndText:
diff --git a/examples/flutter_gallery/lib/gallery/demo.dart b/examples/flutter_gallery/lib/gallery/demo.dart
index ff67cc9..ed8525f 100644
--- a/examples/flutter_gallery/lib/gallery/demo.dart
+++ b/examples/flutter_gallery/lib/gallery/demo.dart
@@ -35,11 +35,13 @@
class TabbedComponentDemoScaffold extends StatelessWidget {
const TabbedComponentDemoScaffold({
this.title,
- this.demos
+ this.demos,
+ this.actions,
});
final List<ComponentDemoTabData> demos;
final String title;
+ final List<Widget> actions;
void _showExampleCode(BuildContext context) {
final String tag = demos[DefaultTabController.of(context).index].exampleCodeTag;
@@ -57,19 +59,21 @@
child: new Scaffold(
appBar: new AppBar(
title: new Text(title),
- actions: <Widget>[
- new Builder(
- builder: (BuildContext context) {
- return new IconButton(
- icon: const Icon(Icons.description),
- tooltip: 'Show example code',
- onPressed: () {
- _showExampleCode(context);
- },
- );
- },
- ),
- ],
+ actions: (actions ?? <Widget>[])..addAll(
+ <Widget>[
+ new Builder(
+ builder: (BuildContext context) {
+ return new IconButton(
+ icon: const Icon(Icons.description),
+ tooltip: 'Show example code',
+ onPressed: () {
+ _showExampleCode(context);
+ },
+ );
+ },
+ )
+ ],
+ ),
bottom: new TabBar(
isScrollable: true,
tabs: demos.map((ComponentDemoTabData data) => new Tab(text: data.tabName)).toList(),
diff --git a/packages/flutter/lib/src/material/button_theme.dart b/packages/flutter/lib/src/material/button_theme.dart
index c59e4e2..3d9d74b 100644
--- a/packages/flutter/lib/src/material/button_theme.dart
+++ b/packages/flutter/lib/src/material/button_theme.dart
@@ -80,6 +80,16 @@
),
super(key: key, child: child);
+ /// Creates a button theme from [data].
+ ///
+ /// The [data] argument must not be null.
+ const ButtonTheme.fromButtonThemeData({
+ Key key,
+ @required this.data,
+ Widget child,
+ }) : assert(data != null),
+ super(key: key, child: child);
+
/// Creates a button theme that is appropriate for button bars, as used in
/// dialog footers and in the headers of data tables.
///
@@ -248,6 +258,26 @@
/// This property only affects [DropdownButton] and its menu.
final bool alignedDropdown;
+ /// Creates a copy of this button theme data object with the matching fields
+ /// replaced with the non-null parameter values.
+ ButtonThemeData copyWith({
+ ButtonTextTheme textTheme,
+ double minWidth,
+ double height,
+ EdgeInsetsGeometry padding,
+ ShapeBorder shape,
+ bool alignedDropdown,
+ }) {
+ return new ButtonThemeData(
+ textTheme: textTheme ?? this.textTheme,
+ minWidth: minWidth ?? this.minWidth,
+ height: height ?? this.height,
+ padding: padding ?? this.padding,
+ shape: shape ?? this.shape,
+ alignedDropdown: alignedDropdown ?? this.alignedDropdown,
+ );
+ }
+
@override
bool operator ==(dynamic other) {
if (other.runtimeType != runtimeType)
diff --git a/packages/flutter/lib/src/material/outline_button.dart b/packages/flutter/lib/src/material/outline_button.dart
index 2333892..4424d1e 100644
--- a/packages/flutter/lib/src/material/outline_button.dart
+++ b/packages/flutter/lib/src/material/outline_button.dart
@@ -454,7 +454,7 @@
if (a is _OutlineBorder) {
return new _OutlineBorder(
side: BorderSide.lerp(a.side, side, t),
- shape: shape.lerpFrom(a.shape, t),
+ shape: ShapeBorder.lerp(a.shape, shape, t),
);
}
return super.lerpFrom(a, t);
@@ -466,7 +466,7 @@
if (b is _OutlineBorder) {
return new _OutlineBorder(
side: BorderSide.lerp(side, b.side, t),
- shape: shape.lerpTo(b.shape, t),
+ shape: ShapeBorder.lerp(shape, b.shape, t),
);
}
return super.lerpTo(b, t);
diff --git a/packages/flutter/test/material/button_theme_test.dart b/packages/flutter/test/material/button_theme_test.dart
index 1d5829e..4cb3f0f 100644
--- a/packages/flutter/test/material/button_theme_test.dart
+++ b/packages/flutter/test/material/button_theme_test.dart
@@ -74,6 +74,31 @@
expect(tester.getSize(find.byType(Material)), const Size(88.0, 36.0));
});
+ test('ButtonThemeData.copyWith', () {
+ ButtonThemeData theme = const ButtonThemeData().copyWith();
+ expect(theme.textTheme, ButtonTextTheme.normal);
+ 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: const BorderRadius.all(const Radius.circular(2.0)),
+ ));
+ expect(theme.alignedDropdown, false);
+
+ theme = const ButtonThemeData().copyWith(
+ textTheme: ButtonTextTheme.primary,
+ minWidth: 100.0,
+ height: 200.0,
+ padding: EdgeInsets.zero,
+ shape: const StadiumBorder(),
+ alignedDropdown: true,
+ );
+ expect(theme.textTheme, ButtonTextTheme.primary);
+ 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);
+ });
+
testWidgets('Theme buttonTheme defaults', (WidgetTester tester) async {
final ThemeData lightTheme = new ThemeData.light();
ButtonTextTheme textTheme;