Unverified Commit 1a098ae8 authored by Hans Muller's avatar Hans Muller Committed by GitHub

Revised Floating Action Button examples (#128058)

Of the original 4 examples, the first 3 mostly covered the same API features and occupied quite a bit of real-estate at the top of https://api.flutter.dev/flutter/material/FloatingActionButton-class.html.  Additionally the illustrations and the code samples didn't match in some cases.

Replaced examples 0,1,2 with one example that changes attributes of the FAB when it's pushed. 

Fixes https://github.com/flutter/flutter/issues/128048
parent ff33555b
...@@ -6,21 +6,38 @@ import 'package:flutter/material.dart'; ...@@ -6,21 +6,38 @@ import 'package:flutter/material.dart';
/// Flutter code sample for [FloatingActionButton]. /// Flutter code sample for [FloatingActionButton].
void main() => runApp(const FloatingActionButtonExampleApp()); void main() {
runApp(const FloatingActionButtonExampleApp());
}
class FloatingActionButtonExampleApp extends StatelessWidget { class FloatingActionButtonExampleApp extends StatelessWidget {
const FloatingActionButtonExampleApp({super.key}); const FloatingActionButtonExampleApp({ super.key });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return const MaterialApp( return MaterialApp(
home: FabExample(), theme: ThemeData(useMaterial3: true),
home: const FloatingActionButtonExample(),
); );
} }
} }
class FabExample extends StatelessWidget { class FloatingActionButtonExample extends StatefulWidget {
const FabExample({super.key}); const FloatingActionButtonExample({ super.key });
@override
State<FloatingActionButtonExample> createState() => _FloatingActionButtonExampleState();
}
class _FloatingActionButtonExampleState extends State<FloatingActionButtonExample> {
// The FAB's foregroundColor, backgroundColor, and shape
static const List<(Color?, Color? background, ShapeBorder?)> customizations = <(Color?, Color?, ShapeBorder?)>[
(null, null, null), // The FAB uses its default for null parameters.
(null, Colors.green, null),
(Colors.white, Colors.green, null),
(Colors.white, Colors.green, CircleBorder()),
];
int index = 0; // Selects the customization.
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
...@@ -31,9 +48,13 @@ class FabExample extends StatelessWidget { ...@@ -31,9 +48,13 @@ class FabExample extends StatelessWidget {
body: const Center(child: Text('Press the button below!')), body: const Center(child: Text('Press the button below!')),
floatingActionButton: FloatingActionButton( floatingActionButton: FloatingActionButton(
onPressed: () { onPressed: () {
// Add your onPressed code here! setState(() {
index = (index + 1) % customizations.length;
});
}, },
backgroundColor: Colors.green, foregroundColor: customizations[index].$1,
backgroundColor: customizations[index].$2,
shape: customizations[index].$3,
child: const Icon(Icons.navigation), child: const Icon(Icons.navigation),
), ),
); );
......
...@@ -13,8 +13,9 @@ class FloatingActionButtonExampleApp extends StatelessWidget { ...@@ -13,8 +13,9 @@ class FloatingActionButtonExampleApp extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return const MaterialApp( return MaterialApp(
home: FabExample(), theme: ThemeData(colorSchemeSeed: const Color(0xff6750a4), useMaterial3: true),
home: const FabExample(),
); );
} }
} }
...@@ -28,16 +29,77 @@ class FabExample extends StatelessWidget { ...@@ -28,16 +29,77 @@ class FabExample extends StatelessWidget {
appBar: AppBar( appBar: AppBar(
title: const Text('FloatingActionButton Sample'), title: const Text('FloatingActionButton Sample'),
), ),
body: const Center( body: Center(
child: Text('Press the button with a label below!'), child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('Small'),
const SizedBox(width: 16),
// An example of the small floating action button.
//
// https://m3.material.io/components/floating-action-button/specs#669a1be8-7271-48cb-a74d-dd502d73bda4
FloatingActionButton.small(
onPressed: () {
// Add your onPressed code here!
},
child: const Icon(Icons.add),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('Regular'),
const SizedBox(width: 16),
// An example of the regular floating action button.
//
// https://m3.material.io/components/floating-action-button/specs#71504201-7bd1-423d-8bb7-07e0291743e5
FloatingActionButton(
onPressed: () {
// Add your onPressed code here!
},
child: const Icon(Icons.add),
),
],
), ),
floatingActionButton: FloatingActionButton.extended( Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('Large'),
const SizedBox(width: 16),
// An example of the large floating action button.
//
// https://m3.material.io/components/floating-action-button/specs#9d7d3d6a-bab7-47cb-be32-5596fbd660fe
FloatingActionButton.large(
onPressed: () { onPressed: () {
// Add your onPressed code here! // Add your onPressed code here!
}, },
label: const Text('Approve'), child: const Icon(Icons.add),
icon: const Icon(Icons.thumb_up), ),
backgroundColor: Colors.pink, ],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('Extended'),
const SizedBox(width: 16),
// An example of the extended floating action button.
//
// https://m3.material.io/components/extended-fab/specs#686cb8af-87c9-48e8-a3e1-db9da6f6c69b
FloatingActionButton.extended(
onPressed: () {
// Add your onPressed code here!
},
label: const Text('Add'),
icon: const Icon(Icons.add),
),
],
),
],
),
), ),
); );
} }
......
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/material.dart';
/// Flutter code sample for [FloatingActionButton].
void main() => runApp(const FloatingActionButtonExampleApp());
class FloatingActionButtonExampleApp extends StatelessWidget {
const FloatingActionButtonExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(colorSchemeSeed: const Color(0xff6750a4), useMaterial3: true),
home: const FabExample(),
);
}
}
class FabExample extends StatelessWidget {
const FabExample({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('FloatingActionButton Sample'),
),
body: const Center(child: Text('Press the button below!')),
// An example of the floating action button.
//
// https://m3.material.io/components/floating-action-button/specs
floatingActionButton: FloatingActionButton(
onPressed: () {
// Add your onPressed code here!
},
child: const Icon(Icons.add),
),
);
}
}
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/material.dart';
/// Flutter code sample for [FloatingActionButton].
void main() => runApp(const FloatingActionButtonExampleApp());
class FloatingActionButtonExampleApp extends StatelessWidget {
const FloatingActionButtonExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(colorSchemeSeed: const Color(0xff6750a4), useMaterial3: true),
home: const FabExample(),
);
}
}
class FabExample extends StatelessWidget {
const FabExample({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('FloatingActionButton Sample'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('Small'),
const SizedBox(width: 16),
// An example of the small floating action button.
//
// https://m3.material.io/components/floating-action-button/specs#669a1be8-7271-48cb-a74d-dd502d73bda4
FloatingActionButton.small(
onPressed: () {
// Add your onPressed code here!
},
child: const Icon(Icons.add),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('Regular'),
const SizedBox(width: 16),
// An example of the regular floating action button.
//
// https://m3.material.io/components/floating-action-button/specs#71504201-7bd1-423d-8bb7-07e0291743e5
FloatingActionButton(
onPressed: () {
// Add your onPressed code here!
},
child: const Icon(Icons.add),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('Large'),
const SizedBox(width: 16),
// An example of the large floating action button.
//
// https://m3.material.io/components/floating-action-button/specs#9d7d3d6a-bab7-47cb-be32-5596fbd660fe
FloatingActionButton.large(
onPressed: () {
// Add your onPressed code here!
},
child: const Icon(Icons.add),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('Extended'),
const SizedBox(width: 16),
// An example of the extended floating action button.
//
// https://m3.material.io/components/extended-fab/specs#686cb8af-87c9-48e8-a3e1-db9da6f6c69b
FloatingActionButton.extended(
onPressed: () {
// Add your onPressed code here!
},
label: const Text('Add'),
icon: const Icon(Icons.add),
),
],
),
],
),
),
);
}
}
...@@ -16,11 +16,30 @@ void main() { ...@@ -16,11 +16,30 @@ void main() {
expect(find.byType(FloatingActionButton), findsOneWidget); expect(find.byType(FloatingActionButton), findsOneWidget);
expect(find.byIcon(Icons.navigation), findsOneWidget); expect(find.byIcon(Icons.navigation), findsOneWidget);
final Finder materialButtonFinder = find.byType(RawMaterialButton);
RawMaterialButton getRawMaterialButtonWidget() { RawMaterialButton getRawMaterialButtonWidget() {
return tester.widget<RawMaterialButton>(materialButtonFinder); return tester.widget<RawMaterialButton>(find.byType(RawMaterialButton));
} }
Color? getIconColor() {
final RichText iconRichText = tester.widget<RichText>(
find.descendant(of: find.byIcon(Icons.navigation), matching: find.byType(RichText)),
);
return iconRichText.text.style?.color;
}
await tester.tap(find.byType(FloatingActionButton));
await tester.pumpAndSettle(); // Wait for the animation to finish.
expect(getRawMaterialButtonWidget().fillColor, Colors.green);
await tester.tap(find.byType(FloatingActionButton));
await tester.pumpAndSettle(); // Wait for the animation to finish.
expect(getRawMaterialButtonWidget().fillColor, Colors.green);
expect(getIconColor(), Colors.white);
await tester.tap(find.byType(FloatingActionButton));
await tester.pumpAndSettle(); // Wait for the animation to finish.
expect(getRawMaterialButtonWidget().fillColor, Colors.green); expect(getRawMaterialButtonWidget().fillColor, Colors.green);
expect(getIconColor(), Colors.white);
expect(getRawMaterialButtonWidget().shape, const CircleBorder()); expect(getRawMaterialButtonWidget().shape, const CircleBorder());
}); });
} }
...@@ -8,20 +8,42 @@ import 'package:flutter_api_samples/material/floating_action_button/floating_act ...@@ -8,20 +8,42 @@ import 'package:flutter_api_samples/material/floating_action_button/floating_act
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
void main() { void main() {
testWidgets('FloatingActionButton.extended', (WidgetTester tester) async { testWidgets('FloatingActionButton variants', (WidgetTester tester) async {
RawMaterialButton getRawMaterialButtonWidget(Finder finder) {
return tester.widget<RawMaterialButton>(finder);
}
await tester.pumpWidget( await tester.pumpWidget(
const example.FloatingActionButtonExampleApp(), const example.FloatingActionButtonExampleApp(),
); );
expect(find.byType(FloatingActionButton), findsOneWidget); final ThemeData theme = ThemeData(colorSchemeSeed: const Color(0xff6750a4), useMaterial3: true);
expect(find.text('Approve'), findsOneWidget);
expect(find.byIcon(Icons.thumb_up), findsOneWidget);
final Finder materialButtonFinder = find.byType(RawMaterialButton); expect(find.byType(FloatingActionButton), findsNWidgets(4));
RawMaterialButton getRawMaterialButtonWidget() { expect(find.byIcon(Icons.add), findsNWidgets(4));
return tester.widget<RawMaterialButton>(materialButtonFinder);
} final Finder smallFabMaterialButton = find.byType(RawMaterialButton).at(0);
expect(getRawMaterialButtonWidget().fillColor, Colors.pink); final RenderBox smallFabRenderBox = tester.renderObject(smallFabMaterialButton);
expect(getRawMaterialButtonWidget().shape, const StadiumBorder()); expect(smallFabRenderBox.size, const Size(48.0, 48.0));
expect(getRawMaterialButtonWidget(smallFabMaterialButton).fillColor, theme.colorScheme.primaryContainer);
expect(getRawMaterialButtonWidget(smallFabMaterialButton).shape, RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.0)));
final Finder regularFABMaterialButton = find.byType(RawMaterialButton).at(1);
final RenderBox regularFABRenderBox = tester.renderObject(regularFABMaterialButton);
expect(regularFABRenderBox.size, const Size(56.0, 56.0));
expect(getRawMaterialButtonWidget(regularFABMaterialButton).fillColor, theme.colorScheme.primaryContainer);
expect(getRawMaterialButtonWidget(regularFABMaterialButton).shape, RoundedRectangleBorder(borderRadius: BorderRadius.circular(16.0)));
final Finder largeFABMaterialButton = find.byType(RawMaterialButton).at(2);
final RenderBox largeFABRenderBox = tester.renderObject(largeFABMaterialButton);
expect(largeFABRenderBox.size, const Size(96.0, 96.0));
expect(getRawMaterialButtonWidget(largeFABMaterialButton).fillColor, theme.colorScheme.primaryContainer);
expect(getRawMaterialButtonWidget(largeFABMaterialButton).shape, RoundedRectangleBorder(borderRadius: BorderRadius.circular(28.0)));
final Finder extendedFABMaterialButton = find.byType(RawMaterialButton).at(3);
final RenderBox extendedFABRenderBox = tester.renderObject(extendedFABMaterialButton);
expect(extendedFABRenderBox.size, const Size(111.0, 56.0));
expect(getRawMaterialButtonWidget(extendedFABMaterialButton).fillColor, theme.colorScheme.primaryContainer);
expect(getRawMaterialButtonWidget(extendedFABMaterialButton).shape, RoundedRectangleBorder(borderRadius: BorderRadius.circular(16.0)));
}); });
} }
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/material.dart';
import 'package:flutter_api_samples/material/floating_action_button/floating_action_button.2.dart'
as example;
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('FloatingActionButton - Material 3', (WidgetTester tester) async {
RawMaterialButton getRawMaterialButtonWidget(Finder finder) {
return tester.widget<RawMaterialButton>(finder);
}
await tester.pumpWidget(
const example.FloatingActionButtonExampleApp(),
);
expect(find.byType(FloatingActionButton), findsOneWidget);
expect(find.byIcon(Icons.add), findsOneWidget);
final ThemeData theme = ThemeData(colorSchemeSeed: const Color(0xff6750a4), useMaterial3: true);
final Finder materialButtonFinder = find.byType(RawMaterialButton);
expect(getRawMaterialButtonWidget(materialButtonFinder).fillColor, theme.colorScheme.primaryContainer);
expect(getRawMaterialButtonWidget(materialButtonFinder).shape, RoundedRectangleBorder(borderRadius: BorderRadius.circular(16.0)));
});
}
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/material.dart';
import 'package:flutter_api_samples/material/floating_action_button/floating_action_button.3.dart'
as example;
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('FloatingActionButton variants', (WidgetTester tester) async {
RawMaterialButton getRawMaterialButtonWidget(Finder finder) {
return tester.widget<RawMaterialButton>(finder);
}
await tester.pumpWidget(
const example.FloatingActionButtonExampleApp(),
);
final ThemeData theme = ThemeData(colorSchemeSeed: const Color(0xff6750a4), useMaterial3: true);
expect(find.byType(FloatingActionButton), findsNWidgets(4));
expect(find.byIcon(Icons.add), findsNWidgets(4));
final Finder smallFabMaterialButton = find.byType(RawMaterialButton).at(0);
final RenderBox smallFabRenderBox = tester.renderObject(smallFabMaterialButton);
expect(smallFabRenderBox.size, const Size(48.0, 48.0));
expect(getRawMaterialButtonWidget(smallFabMaterialButton).fillColor, theme.colorScheme.primaryContainer);
expect(getRawMaterialButtonWidget(smallFabMaterialButton).shape, RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.0)));
final Finder regularFABMaterialButton = find.byType(RawMaterialButton).at(1);
final RenderBox regularFABRenderBox = tester.renderObject(regularFABMaterialButton);
expect(regularFABRenderBox.size, const Size(56.0, 56.0));
expect(getRawMaterialButtonWidget(regularFABMaterialButton).fillColor, theme.colorScheme.primaryContainer);
expect(getRawMaterialButtonWidget(regularFABMaterialButton).shape, RoundedRectangleBorder(borderRadius: BorderRadius.circular(16.0)));
final Finder largeFABMaterialButton = find.byType(RawMaterialButton).at(2);
final RenderBox largeFABRenderBox = tester.renderObject(largeFABMaterialButton);
expect(largeFABRenderBox.size, const Size(96.0, 96.0));
expect(getRawMaterialButtonWidget(largeFABMaterialButton).fillColor, theme.colorScheme.primaryContainer);
expect(getRawMaterialButtonWidget(largeFABMaterialButton).shape, RoundedRectangleBorder(borderRadius: BorderRadius.circular(28.0)));
final Finder extendedFABMaterialButton = find.byType(RawMaterialButton).at(3);
final RenderBox extendedFABRenderBox = tester.renderObject(extendedFABMaterialButton);
expect(extendedFABRenderBox.size, const Size(111.0, 56.0));
expect(getRawMaterialButtonWidget(extendedFABMaterialButton).fillColor, theme.colorScheme.primaryContainer);
expect(getRawMaterialButtonWidget(extendedFABMaterialButton).shape, RoundedRectangleBorder(borderRadius: BorderRadius.circular(16.0)));
});
}
...@@ -52,39 +52,21 @@ enum _FloatingActionButtonType { ...@@ -52,39 +52,21 @@ enum _FloatingActionButtonType {
/// action button. /// action button.
/// ///
/// {@tool dartpad} /// {@tool dartpad}
/// This example shows how to display a [FloatingActionButton] in a /// This example shows a [FloatingActionButton] in its usual position within a
/// [Scaffold], with a pink [backgroundColor] and a thumbs up [Icon]. /// [Scaffold]. Pressing the button cycles it through a few variations in its
/// /// [foregroundColor], [backgroundColor], and [shape]. The button automatically
/// ![](https://flutter.github.io/assets-for-api-docs/assets/material/floating_action_button.png) /// animates its segue from one set of visual parameters to another.
/// ///
/// ** See code in examples/api/lib/material/floating_action_button/floating_action_button.0.dart ** /// ** See code in examples/api/lib/material/floating_action_button/floating_action_button.0.dart **
/// {@end-tool} /// {@end-tool}
/// ///
/// {@tool dartpad} /// {@tool dartpad}
/// This example shows how to make an extended [FloatingActionButton] in a /// This sample shows all the variants of [FloatingActionButton] widget as
/// [Scaffold], with a pink [backgroundColor], a thumbs up [Icon] and a /// described in: https://m3.material.io/components/floating-action-button/overview.
/// [Text] label that reads "Approve".
///
/// ![](https://flutter.github.io/assets-for-api-docs/assets/material/floating_action_button_label.png)
/// ///
/// ** See code in examples/api/lib/material/floating_action_button/floating_action_button.1.dart ** /// ** See code in examples/api/lib/material/floating_action_button/floating_action_button.1.dart **
/// {@end-tool} /// {@end-tool}
/// ///
/// Material Design 3 introduced new types of floating action buttons.
/// {@tool dartpad}
/// This sample shows the creation of [FloatingActionButton] widget in the typical location in a Scaffold,
/// as described in: https://m3.material.io/components/floating-action-button/overview
///
/// ** See code in examples/api/lib/material/floating_action_button/floating_action_button.2.dart **
/// {@end-tool}
///
/// {@tool dartpad}
/// This sample shows the creation of all the variants of [FloatingActionButton] widget as
/// described in: https://m3.material.io/components/floating-action-button/overview
///
/// ** See code in examples/api/lib/material/floating_action_button/floating_action_button.3.dart **
/// {@end-tool}
///
/// See also: /// See also:
/// ///
/// * [Scaffold], in which floating action buttons typically live. /// * [Scaffold], in which floating action buttons typically live.
......
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