mirror of
https://github.com/flutter/flutter
synced 2024-10-13 03:32:55 +00:00
This reverts commit 8143992262
.
This commit is contained in:
parent
cbf1e135c4
commit
a0a65fc604
|
@ -2,6 +2,8 @@
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
// @dart = 2.8
|
||||||
|
|
||||||
import 'dart:developer' show Timeline, Flow;
|
import 'dart:developer' show Timeline, Flow;
|
||||||
import 'dart:io' show Platform;
|
import 'dart:io' show Platform;
|
||||||
|
|
||||||
|
@ -121,7 +123,7 @@ class AboutListTile extends StatelessWidget {
|
||||||
/// derived from the nearest [Title] widget. The version, icon, and legalese
|
/// derived from the nearest [Title] widget. The version, icon, and legalese
|
||||||
/// values default to the empty string.
|
/// values default to the empty string.
|
||||||
const AboutListTile({
|
const AboutListTile({
|
||||||
Key? key,
|
Key key,
|
||||||
this.icon,
|
this.icon,
|
||||||
this.child,
|
this.child,
|
||||||
this.applicationName,
|
this.applicationName,
|
||||||
|
@ -138,13 +140,13 @@ class AboutListTile extends StatelessWidget {
|
||||||
///
|
///
|
||||||
/// This is not necessarily the same as the image shown in the dialog box
|
/// This is not necessarily the same as the image shown in the dialog box
|
||||||
/// itself; which is controlled by the [applicationIcon] property.
|
/// itself; which is controlled by the [applicationIcon] property.
|
||||||
final Widget? icon;
|
final Widget icon;
|
||||||
|
|
||||||
/// The label to show on this drawer item.
|
/// The label to show on this drawer item.
|
||||||
///
|
///
|
||||||
/// Defaults to a text widget that says "About Foo" where "Foo" is the
|
/// Defaults to a text widget that says "About Foo" where "Foo" is the
|
||||||
/// application name specified by [applicationName].
|
/// application name specified by [applicationName].
|
||||||
final Widget? child;
|
final Widget child;
|
||||||
|
|
||||||
/// The name of the application.
|
/// The name of the application.
|
||||||
///
|
///
|
||||||
|
@ -153,14 +155,14 @@ class AboutListTile extends StatelessWidget {
|
||||||
///
|
///
|
||||||
/// Defaults to the value of [Title.title], if a [Title] widget can be found.
|
/// Defaults to the value of [Title.title], if a [Title] widget can be found.
|
||||||
/// Otherwise, defaults to [Platform.resolvedExecutable].
|
/// Otherwise, defaults to [Platform.resolvedExecutable].
|
||||||
final String? applicationName;
|
final String applicationName;
|
||||||
|
|
||||||
/// The version of this build of the application.
|
/// The version of this build of the application.
|
||||||
///
|
///
|
||||||
/// This string is shown under the application name in the [AboutDialog].
|
/// This string is shown under the application name in the [AboutDialog].
|
||||||
///
|
///
|
||||||
/// Defaults to the empty string.
|
/// Defaults to the empty string.
|
||||||
final String? applicationVersion;
|
final String applicationVersion;
|
||||||
|
|
||||||
/// The icon to show next to the application name in the [AboutDialog].
|
/// The icon to show next to the application name in the [AboutDialog].
|
||||||
///
|
///
|
||||||
|
@ -171,14 +173,14 @@ class AboutListTile extends StatelessWidget {
|
||||||
///
|
///
|
||||||
/// This is not necessarily the same as the icon shown on the drawer item
|
/// This is not necessarily the same as the icon shown on the drawer item
|
||||||
/// itself, which is controlled by the [icon] property.
|
/// itself, which is controlled by the [icon] property.
|
||||||
final Widget? applicationIcon;
|
final Widget applicationIcon;
|
||||||
|
|
||||||
/// A string to show in small print in the [AboutDialog].
|
/// A string to show in small print in the [AboutDialog].
|
||||||
///
|
///
|
||||||
/// Typically this is a copyright notice.
|
/// Typically this is a copyright notice.
|
||||||
///
|
///
|
||||||
/// Defaults to the empty string.
|
/// Defaults to the empty string.
|
||||||
final String? applicationLegalese;
|
final String applicationLegalese;
|
||||||
|
|
||||||
/// Widgets to add to the [AboutDialog] after the name, version, and legalese.
|
/// Widgets to add to the [AboutDialog] after the name, version, and legalese.
|
||||||
///
|
///
|
||||||
|
@ -186,14 +188,14 @@ class AboutListTile extends StatelessWidget {
|
||||||
/// or other information to show in the about box.
|
/// or other information to show in the about box.
|
||||||
///
|
///
|
||||||
/// Defaults to nothing.
|
/// Defaults to nothing.
|
||||||
final List<Widget>? aboutBoxChildren;
|
final List<Widget> aboutBoxChildren;
|
||||||
|
|
||||||
/// Whether this list tile is part of a vertically dense list.
|
/// Whether this list tile is part of a vertically dense list.
|
||||||
///
|
///
|
||||||
/// If this property is null, then its value is based on [ListTileTheme.dense].
|
/// If this property is null, then its value is based on [ListTileTheme.dense].
|
||||||
///
|
///
|
||||||
/// Dense list tiles default to a smaller height.
|
/// Dense list tiles default to a smaller height.
|
||||||
final bool? dense;
|
final bool dense;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -201,7 +203,7 @@ class AboutListTile extends StatelessWidget {
|
||||||
assert(debugCheckHasMaterialLocalizations(context));
|
assert(debugCheckHasMaterialLocalizations(context));
|
||||||
return ListTile(
|
return ListTile(
|
||||||
leading: icon,
|
leading: icon,
|
||||||
title: child ?? Text(MaterialLocalizations.of(context)!.aboutListTileTitle(
|
title: child ?? Text(MaterialLocalizations.of(context).aboutListTileTitle(
|
||||||
applicationName ?? _defaultApplicationName(context),
|
applicationName ?? _defaultApplicationName(context),
|
||||||
)),
|
)),
|
||||||
dense: dense,
|
dense: dense,
|
||||||
|
@ -236,14 +238,14 @@ class AboutListTile extends StatelessWidget {
|
||||||
/// The [context], [useRootNavigator] and [routeSettings] arguments are passed to
|
/// The [context], [useRootNavigator] and [routeSettings] arguments are passed to
|
||||||
/// [showDialog], the documentation for which discusses how it is used.
|
/// [showDialog], the documentation for which discusses how it is used.
|
||||||
void showAboutDialog({
|
void showAboutDialog({
|
||||||
required BuildContext context,
|
@required BuildContext context,
|
||||||
String? applicationName,
|
String applicationName,
|
||||||
String? applicationVersion,
|
String applicationVersion,
|
||||||
Widget? applicationIcon,
|
Widget applicationIcon,
|
||||||
String? applicationLegalese,
|
String applicationLegalese,
|
||||||
List<Widget>? children,
|
List<Widget> children,
|
||||||
bool useRootNavigator = true,
|
bool useRootNavigator = true,
|
||||||
RouteSettings? routeSettings,
|
RouteSettings routeSettings,
|
||||||
}) {
|
}) {
|
||||||
assert(context != null);
|
assert(context != null);
|
||||||
assert(useRootNavigator != null);
|
assert(useRootNavigator != null);
|
||||||
|
@ -283,16 +285,16 @@ void showAboutDialog({
|
||||||
/// The licenses shown on the [LicensePage] are those returned by the
|
/// The licenses shown on the [LicensePage] are those returned by the
|
||||||
/// [LicenseRegistry] API, which can be used to add more licenses to the list.
|
/// [LicenseRegistry] API, which can be used to add more licenses to the list.
|
||||||
void showLicensePage({
|
void showLicensePage({
|
||||||
required BuildContext context,
|
@required BuildContext context,
|
||||||
String? applicationName,
|
String applicationName,
|
||||||
String? applicationVersion,
|
String applicationVersion,
|
||||||
Widget? applicationIcon,
|
Widget applicationIcon,
|
||||||
String? applicationLegalese,
|
String applicationLegalese,
|
||||||
bool useRootNavigator = false,
|
bool useRootNavigator = false,
|
||||||
}) {
|
}) {
|
||||||
assert(context != null);
|
assert(context != null);
|
||||||
assert(useRootNavigator != null);
|
assert(useRootNavigator != null);
|
||||||
Navigator.of(context, rootNavigator: useRootNavigator)!.push(MaterialPageRoute<void>(
|
Navigator.of(context, rootNavigator: useRootNavigator).push(MaterialPageRoute<void>(
|
||||||
builder: (BuildContext context) => LicensePage(
|
builder: (BuildContext context) => LicensePage(
|
||||||
applicationName: applicationName,
|
applicationName: applicationName,
|
||||||
applicationVersion: applicationVersion,
|
applicationVersion: applicationVersion,
|
||||||
|
@ -328,7 +330,7 @@ class AboutDialog extends StatelessWidget {
|
||||||
/// derived from the nearest [Title] widget. The version, icon, and legalese
|
/// derived from the nearest [Title] widget. The version, icon, and legalese
|
||||||
/// values default to the empty string.
|
/// values default to the empty string.
|
||||||
const AboutDialog({
|
const AboutDialog({
|
||||||
Key? key,
|
Key key,
|
||||||
this.applicationName,
|
this.applicationName,
|
||||||
this.applicationVersion,
|
this.applicationVersion,
|
||||||
this.applicationIcon,
|
this.applicationIcon,
|
||||||
|
@ -340,14 +342,14 @@ class AboutDialog extends StatelessWidget {
|
||||||
///
|
///
|
||||||
/// Defaults to the value of [Title.title], if a [Title] widget can be found.
|
/// Defaults to the value of [Title.title], if a [Title] widget can be found.
|
||||||
/// Otherwise, defaults to [Platform.resolvedExecutable].
|
/// Otherwise, defaults to [Platform.resolvedExecutable].
|
||||||
final String? applicationName;
|
final String applicationName;
|
||||||
|
|
||||||
/// The version of this build of the application.
|
/// The version of this build of the application.
|
||||||
///
|
///
|
||||||
/// This string is shown under the application name.
|
/// This string is shown under the application name.
|
||||||
///
|
///
|
||||||
/// Defaults to the empty string.
|
/// Defaults to the empty string.
|
||||||
final String? applicationVersion;
|
final String applicationVersion;
|
||||||
|
|
||||||
/// The icon to show next to the application name.
|
/// The icon to show next to the application name.
|
||||||
///
|
///
|
||||||
|
@ -355,14 +357,14 @@ class AboutDialog extends StatelessWidget {
|
||||||
///
|
///
|
||||||
/// Typically this will be an [ImageIcon] widget. It should honor the
|
/// Typically this will be an [ImageIcon] widget. It should honor the
|
||||||
/// [IconTheme]'s [IconThemeData.size].
|
/// [IconTheme]'s [IconThemeData.size].
|
||||||
final Widget? applicationIcon;
|
final Widget applicationIcon;
|
||||||
|
|
||||||
/// A string to show in small print.
|
/// A string to show in small print.
|
||||||
///
|
///
|
||||||
/// Typically this is a copyright notice.
|
/// Typically this is a copyright notice.
|
||||||
///
|
///
|
||||||
/// Defaults to the empty string.
|
/// Defaults to the empty string.
|
||||||
final String? applicationLegalese;
|
final String applicationLegalese;
|
||||||
|
|
||||||
/// Widgets to add to the dialog box after the name, version, and legalese.
|
/// Widgets to add to the dialog box after the name, version, and legalese.
|
||||||
///
|
///
|
||||||
|
@ -370,30 +372,30 @@ class AboutDialog extends StatelessWidget {
|
||||||
/// or other information to show in the about box.
|
/// or other information to show in the about box.
|
||||||
///
|
///
|
||||||
/// Defaults to nothing.
|
/// Defaults to nothing.
|
||||||
final List<Widget>? children;
|
final List<Widget> children;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
assert(debugCheckHasMaterialLocalizations(context));
|
assert(debugCheckHasMaterialLocalizations(context));
|
||||||
final String name = applicationName ?? _defaultApplicationName(context);
|
final String name = applicationName ?? _defaultApplicationName(context);
|
||||||
final String version = applicationVersion ?? _defaultApplicationVersion(context);
|
final String version = applicationVersion ?? _defaultApplicationVersion(context);
|
||||||
final Widget? icon = applicationIcon ?? _defaultApplicationIcon(context);
|
final Widget icon = applicationIcon ?? _defaultApplicationIcon(context);
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
content: ListBody(
|
content: ListBody(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Row(
|
Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
if (icon != null) IconTheme(data: Theme.of(context)!.iconTheme, child: icon),
|
if (icon != null) IconTheme(data: Theme.of(context).iconTheme, child: icon),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24.0),
|
padding: const EdgeInsets.symmetric(horizontal: 24.0),
|
||||||
child: ListBody(
|
child: ListBody(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Text(name, style: Theme.of(context)!.textTheme.headline5),
|
Text(name, style: Theme.of(context).textTheme.headline5),
|
||||||
Text(version, style: Theme.of(context)!.textTheme.bodyText2),
|
Text(version, style: Theme.of(context).textTheme.bodyText2),
|
||||||
const SizedBox(height: _textVerticalSeparation),
|
const SizedBox(height: _textVerticalSeparation),
|
||||||
Text(applicationLegalese ?? '', style: Theme.of(context)!.textTheme.caption),
|
Text(applicationLegalese ?? '', style: Theme.of(context).textTheme.caption),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -405,7 +407,7 @@ class AboutDialog extends StatelessWidget {
|
||||||
),
|
),
|
||||||
actions: <Widget>[
|
actions: <Widget>[
|
||||||
TextButton(
|
TextButton(
|
||||||
child: Text(MaterialLocalizations.of(context)!.viewLicensesButtonLabel),
|
child: Text(MaterialLocalizations.of(context).viewLicensesButtonLabel),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
showLicensePage(
|
showLicensePage(
|
||||||
context: context,
|
context: context,
|
||||||
|
@ -417,7 +419,7 @@ class AboutDialog extends StatelessWidget {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
child: Text(MaterialLocalizations.of(context)!.closeButtonLabel),
|
child: Text(MaterialLocalizations.of(context).closeButtonLabel),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
},
|
},
|
||||||
|
@ -447,7 +449,7 @@ class LicensePage extends StatefulWidget {
|
||||||
/// The licenses shown on the [LicensePage] are those returned by the
|
/// The licenses shown on the [LicensePage] are those returned by the
|
||||||
/// [LicenseRegistry] API, which can be used to add more licenses to the list.
|
/// [LicenseRegistry] API, which can be used to add more licenses to the list.
|
||||||
const LicensePage({
|
const LicensePage({
|
||||||
Key? key,
|
Key key,
|
||||||
this.applicationName,
|
this.applicationName,
|
||||||
this.applicationVersion,
|
this.applicationVersion,
|
||||||
this.applicationIcon,
|
this.applicationIcon,
|
||||||
|
@ -458,14 +460,14 @@ class LicensePage extends StatefulWidget {
|
||||||
///
|
///
|
||||||
/// Defaults to the value of [Title.title], if a [Title] widget can be found.
|
/// Defaults to the value of [Title.title], if a [Title] widget can be found.
|
||||||
/// Otherwise, defaults to [Platform.resolvedExecutable].
|
/// Otherwise, defaults to [Platform.resolvedExecutable].
|
||||||
final String? applicationName;
|
final String applicationName;
|
||||||
|
|
||||||
/// The version of this build of the application.
|
/// The version of this build of the application.
|
||||||
///
|
///
|
||||||
/// This string is shown under the application name.
|
/// This string is shown under the application name.
|
||||||
///
|
///
|
||||||
/// Defaults to the empty string.
|
/// Defaults to the empty string.
|
||||||
final String? applicationVersion;
|
final String applicationVersion;
|
||||||
|
|
||||||
/// The icon to show below the application name.
|
/// The icon to show below the application name.
|
||||||
///
|
///
|
||||||
|
@ -473,33 +475,33 @@ class LicensePage extends StatefulWidget {
|
||||||
///
|
///
|
||||||
/// Typically this will be an [ImageIcon] widget. It should honor the
|
/// Typically this will be an [ImageIcon] widget. It should honor the
|
||||||
/// [IconTheme]'s [IconThemeData.size].
|
/// [IconTheme]'s [IconThemeData.size].
|
||||||
final Widget? applicationIcon;
|
final Widget applicationIcon;
|
||||||
|
|
||||||
/// A string to show in small print.
|
/// A string to show in small print.
|
||||||
///
|
///
|
||||||
/// Typically this is a copyright notice.
|
/// Typically this is a copyright notice.
|
||||||
///
|
///
|
||||||
/// Defaults to the empty string.
|
/// Defaults to the empty string.
|
||||||
final String? applicationLegalese;
|
final String applicationLegalese;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_LicensePageState createState() => _LicensePageState();
|
_LicensePageState createState() => _LicensePageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _LicensePageState extends State<LicensePage> {
|
class _LicensePageState extends State<LicensePage> {
|
||||||
final ValueNotifier<int?> selectedId = ValueNotifier<int?>(null);
|
final ValueNotifier<int> selectedId = ValueNotifier<int>(null);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return _MasterDetailFlow(
|
return _MasterDetailFlow(
|
||||||
detailPageFABlessGutterWidth: _getGutterSize(context),
|
detailPageFABlessGutterWidth: _getGutterSize(context),
|
||||||
title: Text(MaterialLocalizations.of(context)!.licensesPageTitle),
|
title: Text(MaterialLocalizations.of(context).licensesPageTitle),
|
||||||
detailPageBuilder: _packageLicensePage,
|
detailPageBuilder: _packageLicensePage,
|
||||||
masterViewBuilder: _packagesView,
|
masterViewBuilder: _packagesView,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _packageLicensePage(BuildContext _, Object? args, ScrollController? scrollController) {
|
Widget _packageLicensePage(BuildContext _, Object args, ScrollController scrollController) {
|
||||||
assert(args is _DetailArguments);
|
assert(args is _DetailArguments);
|
||||||
final _DetailArguments detailArguments = args as _DetailArguments;
|
final _DetailArguments detailArguments = args as _DetailArguments;
|
||||||
return _PackageLicensePage(
|
return _PackageLicensePage(
|
||||||
|
@ -526,9 +528,9 @@ class _LicensePageState extends State<LicensePage> {
|
||||||
|
|
||||||
class _AboutProgram extends StatelessWidget {
|
class _AboutProgram extends StatelessWidget {
|
||||||
const _AboutProgram({
|
const _AboutProgram({
|
||||||
Key? key,
|
Key key,
|
||||||
required this.name,
|
@required this.name,
|
||||||
required this.version,
|
@required this.version,
|
||||||
this.icon,
|
this.icon,
|
||||||
this.legalese,
|
this.legalese,
|
||||||
}) : assert(name != null),
|
}) : assert(name != null),
|
||||||
|
@ -537,8 +539,8 @@ class _AboutProgram extends StatelessWidget {
|
||||||
|
|
||||||
final String name;
|
final String name;
|
||||||
final String version;
|
final String version;
|
||||||
final Widget? icon;
|
final Widget icon;
|
||||||
final String? legalese;
|
final String legalese;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -551,26 +553,26 @@ class _AboutProgram extends StatelessWidget {
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Text(
|
Text(
|
||||||
name,
|
name,
|
||||||
style: Theme.of(context)!.textTheme.headline5,
|
style: Theme.of(context).textTheme.headline5,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
if (icon != null)
|
if (icon != null)
|
||||||
IconTheme(data: Theme.of(context)!.iconTheme, child: icon!),
|
IconTheme(data: Theme.of(context).iconTheme, child: icon),
|
||||||
Text(
|
Text(
|
||||||
version,
|
version,
|
||||||
style: Theme.of(context)!.textTheme.bodyText2,
|
style: Theme.of(context).textTheme.bodyText2,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
const SizedBox(height: _textVerticalSeparation),
|
const SizedBox(height: _textVerticalSeparation),
|
||||||
Text(
|
Text(
|
||||||
legalese ?? '',
|
legalese ?? '',
|
||||||
style: Theme.of(context)!.textTheme.caption,
|
style: Theme.of(context).textTheme.caption,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
const SizedBox(height: _textVerticalSeparation),
|
const SizedBox(height: _textVerticalSeparation),
|
||||||
Text(
|
Text(
|
||||||
'Powered by Flutter',
|
'Powered by Flutter',
|
||||||
style: Theme.of(context)!.textTheme.bodyText2,
|
style: Theme.of(context).textTheme.bodyText2,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -581,17 +583,17 @@ class _AboutProgram extends StatelessWidget {
|
||||||
|
|
||||||
class _PackagesView extends StatefulWidget {
|
class _PackagesView extends StatefulWidget {
|
||||||
const _PackagesView({
|
const _PackagesView({
|
||||||
Key? key,
|
Key key,
|
||||||
required this.about,
|
@required this.about,
|
||||||
required this.isLateral,
|
@required this.isLateral,
|
||||||
required this.selectedId,
|
@required this.selectedId,
|
||||||
}) : assert(about != null),
|
}) : assert(about != null),
|
||||||
assert(isLateral != null),
|
assert(isLateral != null),
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
final Widget about;
|
final Widget about;
|
||||||
final bool isLateral;
|
final bool isLateral;
|
||||||
final ValueNotifier<int?> selectedId;
|
final ValueNotifier<int> selectedId;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_PackagesViewState createState() => _PackagesViewState();
|
_PackagesViewState createState() => _PackagesViewState();
|
||||||
|
@ -615,17 +617,17 @@ class _PackagesViewState extends State<_PackagesView> {
|
||||||
builder: (BuildContext context, BoxConstraints constraints) {
|
builder: (BuildContext context, BoxConstraints constraints) {
|
||||||
switch (snapshot.connectionState) {
|
switch (snapshot.connectionState) {
|
||||||
case ConnectionState.done:
|
case ConnectionState.done:
|
||||||
_initDefaultDetailPage(snapshot.data!, context);
|
_initDefaultDetailPage(snapshot.data, context);
|
||||||
return ValueListenableBuilder<int?>(
|
return ValueListenableBuilder<int>(
|
||||||
valueListenable: widget.selectedId,
|
valueListenable: widget.selectedId,
|
||||||
builder: (BuildContext context, int? selectedId, Widget? _) {
|
builder: (BuildContext context, int selectedId, Widget _) {
|
||||||
return Center(
|
return Center(
|
||||||
child: Material(
|
child: Material(
|
||||||
color: Theme.of(context)!.cardColor,
|
color: Theme.of(context).cardColor,
|
||||||
elevation: 4.0,
|
elevation: 4.0,
|
||||||
child: Container(
|
child: Container(
|
||||||
constraints: BoxConstraints.loose(const Size.fromWidth(600.0)),
|
constraints: BoxConstraints.loose(const Size.fromWidth(600.0)),
|
||||||
child: _packagesList(context, selectedId, snapshot.data!, widget.isLateral),
|
child: _packagesList(context, selectedId, snapshot.data, widget.isLateral),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -633,7 +635,7 @@ class _PackagesViewState extends State<_PackagesView> {
|
||||||
);
|
);
|
||||||
default:
|
default:
|
||||||
return Material(
|
return Material(
|
||||||
color: Theme.of(context)!.cardColor,
|
color: Theme.of(context).cardColor,
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
|
@ -654,8 +656,8 @@ class _PackagesViewState extends State<_PackagesView> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final String packageName = data.packages[widget.selectedId.value ?? 0];
|
final String packageName = data.packages[widget.selectedId.value ?? 0];
|
||||||
final List<int> bindings = data.packageLicenseBindings[packageName]!;
|
final List<int> bindings = data.packageLicenseBindings[packageName];
|
||||||
_MasterDetailFlow.of(context)!.setInitialDetailPage(
|
_MasterDetailFlow.of(context).setInitialDetailPage(
|
||||||
_DetailArguments(
|
_DetailArguments(
|
||||||
packageName,
|
packageName,
|
||||||
bindings.map((int i) => data.licenses[i]).toList(growable: false),
|
bindings.map((int i) => data.licenses[i]).toList(growable: false),
|
||||||
|
@ -665,7 +667,7 @@ class _PackagesViewState extends State<_PackagesView> {
|
||||||
|
|
||||||
Widget _packagesList(
|
Widget _packagesList(
|
||||||
final BuildContext context,
|
final BuildContext context,
|
||||||
final int? selectedId,
|
final int selectedId,
|
||||||
final _LicenseData data,
|
final _LicenseData data,
|
||||||
final bool drawSelection,
|
final bool drawSelection,
|
||||||
) {
|
) {
|
||||||
|
@ -678,7 +680,7 @@ class _PackagesViewState extends State<_PackagesView> {
|
||||||
.map<Widget>((MapEntry<int, String> entry) {
|
.map<Widget>((MapEntry<int, String> entry) {
|
||||||
final String packageName = entry.value;
|
final String packageName = entry.value;
|
||||||
final int index = entry.key;
|
final int index = entry.key;
|
||||||
final List<int> bindings = data.packageLicenseBindings[packageName]!;
|
final List<int> bindings = data.packageLicenseBindings[packageName];
|
||||||
return _PackageListTile(
|
return _PackageListTile(
|
||||||
packageName: packageName,
|
packageName: packageName,
|
||||||
index: index,
|
index: index,
|
||||||
|
@ -686,7 +688,7 @@ class _PackagesViewState extends State<_PackagesView> {
|
||||||
numberLicenses: bindings.length,
|
numberLicenses: bindings.length,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
widget.selectedId.value = index;
|
widget.selectedId.value = index;
|
||||||
_MasterDetailFlow.of(context)!.openDetailPage(_DetailArguments(
|
_MasterDetailFlow.of(context).openDetailPage(_DetailArguments(
|
||||||
packageName,
|
packageName,
|
||||||
bindings.map((int i) => data.licenses[i]).toList(growable: false),
|
bindings.map((int i) => data.licenses[i]).toList(growable: false),
|
||||||
));
|
));
|
||||||
|
@ -700,27 +702,27 @@ class _PackagesViewState extends State<_PackagesView> {
|
||||||
|
|
||||||
class _PackageListTile extends StatelessWidget {
|
class _PackageListTile extends StatelessWidget {
|
||||||
const _PackageListTile({
|
const _PackageListTile({
|
||||||
Key? key,
|
Key key,
|
||||||
required this.packageName,
|
this.packageName,
|
||||||
this.index,
|
this.index,
|
||||||
required this.isSelected,
|
this.isSelected,
|
||||||
required this.numberLicenses,
|
this.numberLicenses,
|
||||||
this.onTap,
|
this.onTap,
|
||||||
}) : super(key:key);
|
}) : super(key:key);
|
||||||
|
|
||||||
final String packageName;
|
final String packageName;
|
||||||
final int? index;
|
final int index;
|
||||||
final bool isSelected;
|
final bool isSelected;
|
||||||
final int numberLicenses;
|
final int numberLicenses;
|
||||||
final GestureTapCallback? onTap;
|
final GestureTapCallback onTap;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Ink(
|
return Ink(
|
||||||
color: isSelected ? Theme.of(context)!.highlightColor : Theme.of(context)!.cardColor,
|
color: isSelected ? Theme.of(context).highlightColor : Theme.of(context).cardColor,
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
title: Text(packageName),
|
title: Text(packageName),
|
||||||
subtitle: Text(MaterialLocalizations.of(context)!.licensesPackageDetailText(numberLicenses)),
|
subtitle: Text(MaterialLocalizations.of(context).licensesPackageDetailText(numberLicenses)),
|
||||||
selected: isSelected,
|
selected: isSelected,
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
),
|
),
|
||||||
|
@ -738,7 +740,7 @@ class _LicenseData {
|
||||||
|
|
||||||
// Special treatment for the first package since it should be the package
|
// Special treatment for the first package since it should be the package
|
||||||
// for delivered application.
|
// for delivered application.
|
||||||
String? firstPackage;
|
String firstPackage;
|
||||||
|
|
||||||
void addLicense(LicenseEntry entry) {
|
void addLicense(LicenseEntry entry) {
|
||||||
// Before the license can be added, we must first record the packages to
|
// Before the license can be added, we must first record the packages to
|
||||||
|
@ -748,7 +750,7 @@ class _LicenseData {
|
||||||
// Bind this license to the package using the next index value. This
|
// Bind this license to the package using the next index value. This
|
||||||
// creates a contract that this license must be inserted at this same
|
// creates a contract that this license must be inserted at this same
|
||||||
// index value.
|
// index value.
|
||||||
packageLicenseBindings[package]!.add(licenses.length);
|
packageLicenseBindings[package].add(licenses.length);
|
||||||
}
|
}
|
||||||
licenses.add(entry); // Completion of the contract above.
|
licenses.add(entry); // Completion of the contract above.
|
||||||
}
|
}
|
||||||
|
@ -766,7 +768,7 @@ class _LicenseData {
|
||||||
/// Sort the packages using some comparison method, or by the default manner,
|
/// Sort the packages using some comparison method, or by the default manner,
|
||||||
/// which is to put the application package first, followed by every other
|
/// which is to put the application package first, followed by every other
|
||||||
/// package in case-insensitive alphabetical order.
|
/// package in case-insensitive alphabetical order.
|
||||||
void sortPackages([int Function(String a, String b)? compare]) {
|
void sortPackages([int compare(String a, String b)]) {
|
||||||
packages.sort(compare ?? (String a, String b) {
|
packages.sort(compare ?? (String a, String b) {
|
||||||
// Based on how LicenseRegistry currently behaves, the first package
|
// Based on how LicenseRegistry currently behaves, the first package
|
||||||
// returned is the end user application license. This should be
|
// returned is the end user application license. This should be
|
||||||
|
@ -804,15 +806,15 @@ class _DetailArguments {
|
||||||
|
|
||||||
class _PackageLicensePage extends StatefulWidget {
|
class _PackageLicensePage extends StatefulWidget {
|
||||||
const _PackageLicensePage({
|
const _PackageLicensePage({
|
||||||
Key? key,
|
Key key,
|
||||||
required this.packageName,
|
this.packageName,
|
||||||
required this.licenseEntries,
|
this.licenseEntries,
|
||||||
required this.scrollController,
|
this.scrollController,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
final String packageName;
|
final String packageName;
|
||||||
final List<LicenseEntry> licenseEntries;
|
final List<LicenseEntry> licenseEntries;
|
||||||
final ScrollController? scrollController;
|
final ScrollController scrollController;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_PackageLicensePageState createState() => _PackageLicensePageState();
|
_PackageLicensePageState createState() => _PackageLicensePageState();
|
||||||
|
@ -845,7 +847,7 @@ class _PackageLicensePageState extends State<_PackageLicensePage> {
|
||||||
return true;
|
return true;
|
||||||
}());
|
}());
|
||||||
final List<LicenseParagraph> paragraphs =
|
final List<LicenseParagraph> paragraphs =
|
||||||
await SchedulerBinding.instance!.scheduleTask<List<LicenseParagraph>>(
|
await SchedulerBinding.instance.scheduleTask<List<LicenseParagraph>>(
|
||||||
license.paragraphs.toList,
|
license.paragraphs.toList,
|
||||||
Priority.animation,
|
Priority.animation,
|
||||||
debugLabel: 'License',
|
debugLabel: 'License',
|
||||||
|
@ -890,8 +892,8 @@ class _PackageLicensePageState extends State<_PackageLicensePage> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
assert(debugCheckHasMaterialLocalizations(context));
|
assert(debugCheckHasMaterialLocalizations(context));
|
||||||
final MaterialLocalizations localizations = MaterialLocalizations.of(context)!;
|
final MaterialLocalizations localizations = MaterialLocalizations.of(context);
|
||||||
final ThemeData? theme = Theme.of(context);
|
final ThemeData theme = Theme.of(context);
|
||||||
final String title = widget.packageName;
|
final String title = widget.packageName;
|
||||||
final String subtitle = localizations.licensesPackageDetailText(widget.licenseEntries.length);
|
final String subtitle = localizations.licensesPackageDetailText(widget.licenseEntries.length);
|
||||||
final double pad = _getGutterSize(context);
|
final double pad = _getGutterSize(context);
|
||||||
|
@ -914,7 +916,7 @@ class _PackageLicensePageState extends State<_PackageLicensePage> {
|
||||||
title: _PackageLicensePageTitle(
|
title: _PackageLicensePageTitle(
|
||||||
title,
|
title,
|
||||||
subtitle,
|
subtitle,
|
||||||
theme!.appBarTheme.textTheme ?? theme.primaryTextTheme,
|
theme.appBarTheme.textTheme ?? theme.primaryTextTheme,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
body: Center(
|
body: Center(
|
||||||
|
@ -941,7 +943,7 @@ class _PackageLicensePageState extends State<_PackageLicensePage> {
|
||||||
SliverAppBar(
|
SliverAppBar(
|
||||||
automaticallyImplyLeading: false,
|
automaticallyImplyLeading: false,
|
||||||
pinned: true,
|
pinned: true,
|
||||||
backgroundColor: theme!.cardColor,
|
backgroundColor: theme.cardColor,
|
||||||
title: _PackageLicensePageTitle(title, subtitle, theme.textTheme),
|
title: _PackageLicensePageTitle(title, subtitle, theme.textTheme),
|
||||||
),
|
),
|
||||||
SliverPadding(
|
SliverPadding(
|
||||||
|
@ -972,7 +974,7 @@ class _PackageLicensePageTitle extends StatelessWidget {
|
||||||
this.title,
|
this.title,
|
||||||
this.subtitle,
|
this.subtitle,
|
||||||
this.theme, {
|
this.theme, {
|
||||||
Key? key,
|
Key key,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
final String title;
|
final String title;
|
||||||
|
@ -999,7 +1001,7 @@ String _defaultApplicationName(BuildContext context) {
|
||||||
// someone really wants their application title to change dynamically, they
|
// someone really wants their application title to change dynamically, they
|
||||||
// can provide an explicit applicationName to the widgets defined in this
|
// can provide an explicit applicationName to the widgets defined in this
|
||||||
// file, instead of relying on the default.
|
// file, instead of relying on the default.
|
||||||
final Title? ancestorTitle = context.findAncestorWidgetOfExactType<Title>();
|
final Title ancestorTitle = context.findAncestorWidgetOfExactType<Title>();
|
||||||
return ancestorTitle?.title ?? Platform.resolvedExecutable.split(Platform.pathSeparator).last;
|
return ancestorTitle?.title ?? Platform.resolvedExecutable.split(Platform.pathSeparator).last;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1008,7 +1010,7 @@ String _defaultApplicationVersion(BuildContext context) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget? _defaultApplicationIcon(BuildContext context) {
|
Widget _defaultApplicationIcon(BuildContext context) {
|
||||||
// TODO(ianh): Get this from the embedder somehow.
|
// TODO(ianh): Get this from the embedder somehow.
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -1018,7 +1020,7 @@ const double _wideGutterSize = 24.0;
|
||||||
const double _narrowGutterSize = 12.0;
|
const double _narrowGutterSize = 12.0;
|
||||||
|
|
||||||
double _getGutterSize(BuildContext context) =>
|
double _getGutterSize(BuildContext context) =>
|
||||||
MediaQuery.of(context)!.size.width >= _materialGutterThreshold ? _wideGutterSize : _narrowGutterSize;
|
MediaQuery.of(context).size.width >= _materialGutterThreshold ? _wideGutterSize : _narrowGutterSize;
|
||||||
|
|
||||||
/// Signature for the builder callback used by [_MasterDetailFlow].
|
/// Signature for the builder callback used by [_MasterDetailFlow].
|
||||||
typedef _MasterViewBuilder = Widget Function(BuildContext context, bool isLateralUI);
|
typedef _MasterViewBuilder = Widget Function(BuildContext context, bool isLateralUI);
|
||||||
|
@ -1027,7 +1029,7 @@ typedef _MasterViewBuilder = Widget Function(BuildContext context, bool isLatera
|
||||||
///
|
///
|
||||||
/// scrollController is provided when the page destination is the draggable
|
/// scrollController is provided when the page destination is the draggable
|
||||||
/// sheet in the lateral UI. Otherwise, it is null.
|
/// sheet in the lateral UI. Otherwise, it is null.
|
||||||
typedef _DetailPageBuilder = Widget Function(BuildContext context, Object? arguments, ScrollController? scrollController);
|
typedef _DetailPageBuilder = Widget Function(BuildContext context, Object arguments, ScrollController scrollController);
|
||||||
|
|
||||||
/// Signature for the builder callback used by [_MasterDetailFlow.actionBuilder].
|
/// Signature for the builder callback used by [_MasterDetailFlow.actionBuilder].
|
||||||
///
|
///
|
||||||
|
@ -1076,9 +1078,9 @@ class _MasterDetailFlow extends StatefulWidget {
|
||||||
/// Creates a master detail navigation flow which is either nested or
|
/// Creates a master detail navigation flow which is either nested or
|
||||||
/// lateral depending on screen width.
|
/// lateral depending on screen width.
|
||||||
const _MasterDetailFlow({
|
const _MasterDetailFlow({
|
||||||
Key? key,
|
Key key,
|
||||||
required this.detailPageBuilder,
|
@required this.detailPageBuilder,
|
||||||
required this.masterViewBuilder,
|
@required this.masterViewBuilder,
|
||||||
this.actionBuilder,
|
this.actionBuilder,
|
||||||
this.automaticallyImplyLeading = true,
|
this.automaticallyImplyLeading = true,
|
||||||
this.breakpoint,
|
this.breakpoint,
|
||||||
|
@ -1111,7 +1113,7 @@ class _MasterDetailFlow extends StatefulWidget {
|
||||||
/// This builder is usually a wrapper around the [masterViewBuilder] builder to provide the
|
/// This builder is usually a wrapper around the [masterViewBuilder] builder to provide the
|
||||||
/// extra UI required to make a page. However, this builder is optional, and the master page
|
/// extra UI required to make a page. However, this builder is optional, and the master page
|
||||||
/// can be built using the master view builder and the configuration for the lateral UI's app bar.
|
/// can be built using the master view builder and the configuration for the lateral UI's app bar.
|
||||||
final _MasterViewBuilder? masterPageBuilder;
|
final _MasterViewBuilder masterPageBuilder;
|
||||||
|
|
||||||
/// Builder for the detail page.
|
/// Builder for the detail page.
|
||||||
///
|
///
|
||||||
|
@ -1122,29 +1124,29 @@ class _MasterDetailFlow extends StatefulWidget {
|
||||||
final _DetailPageBuilder detailPageBuilder;
|
final _DetailPageBuilder detailPageBuilder;
|
||||||
|
|
||||||
/// Override the width of the master view in the lateral UI.
|
/// Override the width of the master view in the lateral UI.
|
||||||
final double? masterViewWidth;
|
final double masterViewWidth;
|
||||||
|
|
||||||
/// Override the width of the floating action button gutter in the lateral UI.
|
/// Override the width of the floating action button gutter in the lateral UI.
|
||||||
final double? detailPageFABGutterWidth;
|
final double detailPageFABGutterWidth;
|
||||||
|
|
||||||
/// Override the width of the gutter when there is no floating action button.
|
/// Override the width of the gutter when there is no floating action button.
|
||||||
final double? detailPageFABlessGutterWidth;
|
final double detailPageFABlessGutterWidth;
|
||||||
|
|
||||||
/// Add a floating action button to the lateral UI. If no [masterPageBuilder] is supplied, this
|
/// Add a floating action button to the lateral UI. If no [masterPageBuilder] is supplied, this
|
||||||
/// floating action button is also used on the nested master page.
|
/// floating action button is also used on the nested master page.
|
||||||
///
|
///
|
||||||
/// See [Scaffold.floatingActionButton].
|
/// See [Scaffold.floatingActionButton].
|
||||||
final FloatingActionButton? floatingActionButton;
|
final FloatingActionButton floatingActionButton;
|
||||||
|
|
||||||
/// The title for the lateral UI [AppBar].
|
/// The title for the lateral UI [AppBar].
|
||||||
///
|
///
|
||||||
/// See [AppBar.title].
|
/// See [AppBar.title].
|
||||||
final Widget? title;
|
final Widget title;
|
||||||
|
|
||||||
/// A widget to display before the title for the lateral UI [AppBar].
|
/// A widget to display before the title for the lateral UI [AppBar].
|
||||||
///
|
///
|
||||||
/// See [AppBar.leading].
|
/// See [AppBar.leading].
|
||||||
final Widget? leading;
|
final Widget leading;
|
||||||
|
|
||||||
/// Override the framework from determining whether to show a leading widget or not.
|
/// Override the framework from determining whether to show a leading widget or not.
|
||||||
///
|
///
|
||||||
|
@ -1155,10 +1157,10 @@ class _MasterDetailFlow extends StatefulWidget {
|
||||||
/// app bar or not.
|
/// app bar or not.
|
||||||
///
|
///
|
||||||
/// See [AppBar.centerTitle].
|
/// See [AppBar.centerTitle].
|
||||||
final bool? centerTitle;
|
final bool centerTitle;
|
||||||
|
|
||||||
/// See [AppBar.flexibleSpace].
|
/// See [AppBar.flexibleSpace].
|
||||||
final Widget? flexibleSpace;
|
final Widget flexibleSpace;
|
||||||
|
|
||||||
/// Build actions for the lateral UI, and potentially the master page in the nested UI.
|
/// Build actions for the lateral UI, and potentially the master page in the nested UI.
|
||||||
///
|
///
|
||||||
|
@ -1169,25 +1171,25 @@ class _MasterDetailFlow extends StatefulWidget {
|
||||||
/// by [_MasterDetailFlow], then [_ActionLevel.composite] indicates the
|
/// by [_MasterDetailFlow], then [_ActionLevel.composite] indicates the
|
||||||
/// actions are for the
|
/// actions are for the
|
||||||
/// nested master page.
|
/// nested master page.
|
||||||
final _ActionBuilder? actionBuilder;
|
final _ActionBuilder actionBuilder;
|
||||||
|
|
||||||
/// Determine where the floating action button will go.
|
/// Determine where the floating action button will go.
|
||||||
///
|
///
|
||||||
/// If null, [FloatingActionButtonLocation.endTop] is used.
|
/// If null, [FloatingActionButtonLocation.endTop] is used.
|
||||||
///
|
///
|
||||||
/// Also see [Scaffold.floatingActionButtonLocation].
|
/// Also see [Scaffold.floatingActionButtonLocation].
|
||||||
final FloatingActionButtonLocation? floatingActionButtonLocation;
|
final FloatingActionButtonLocation floatingActionButtonLocation;
|
||||||
|
|
||||||
/// Determine where the floating action button will go on the master page.
|
/// Determine where the floating action button will go on the master page.
|
||||||
///
|
///
|
||||||
/// See [Scaffold.floatingActionButtonLocation].
|
/// See [Scaffold.floatingActionButtonLocation].
|
||||||
final FloatingActionButtonLocation? floatingActionButtonMasterPageLocation;
|
final FloatingActionButtonLocation floatingActionButtonMasterPageLocation;
|
||||||
|
|
||||||
/// Forces display mode and style.
|
/// Forces display mode and style.
|
||||||
final _LayoutMode displayMode;
|
final _LayoutMode displayMode;
|
||||||
|
|
||||||
/// Width at which layout changes from nested to lateral.
|
/// Width at which layout changes from nested to lateral.
|
||||||
final double? breakpoint;
|
final double breakpoint;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_MasterDetailFlowState createState() => _MasterDetailFlowState();
|
_MasterDetailFlowState createState() => _MasterDetailFlowState();
|
||||||
|
@ -1200,11 +1202,11 @@ class _MasterDetailFlow extends StatefulWidget {
|
||||||
/// ```dart
|
/// ```dart
|
||||||
/// _MasterDetailFlow.of(context).openDetailPage(arguments);
|
/// _MasterDetailFlow.of(context).openDetailPage(arguments);
|
||||||
/// ```
|
/// ```
|
||||||
static _MasterDetailFlowProxy? of(
|
static _MasterDetailFlowProxy of(
|
||||||
BuildContext context, {
|
BuildContext context, {
|
||||||
bool nullOk = false,
|
bool nullOk = false,
|
||||||
}) {
|
}) {
|
||||||
_PageOpener? pageOpener = context.findAncestorStateOfType<_MasterDetailScaffoldState>();
|
_PageOpener pageOpener = context.findAncestorStateOfType<_MasterDetailScaffoldState>();
|
||||||
pageOpener ??= context.findAncestorStateOfType<_MasterDetailFlowState>();
|
pageOpener ??= context.findAncestorStateOfType<_MasterDetailFlowState>();
|
||||||
assert(() {
|
assert(() {
|
||||||
if (pageOpener == null && !nullOk) {
|
if (pageOpener == null && !nullOk) {
|
||||||
|
@ -1251,10 +1253,10 @@ class _MasterDetailFlowState extends State<_MasterDetailFlow> implements _PageOp
|
||||||
_Focus focus = _Focus.master;
|
_Focus focus = _Focus.master;
|
||||||
|
|
||||||
/// Cache of arguments passed when opening a detail page. Used when rebuilding.
|
/// Cache of arguments passed when opening a detail page. Used when rebuilding.
|
||||||
Object? _cachedDetailArguments;
|
Object _cachedDetailArguments;
|
||||||
|
|
||||||
/// Record of the layout that was built.
|
/// Record of the layout that was built.
|
||||||
_LayoutMode? _builtLayout;
|
_LayoutMode _builtLayout;
|
||||||
|
|
||||||
/// Key to access navigator in the nested layout.
|
/// Key to access navigator in the nested layout.
|
||||||
final GlobalKey<NavigatorState> _navigatorKey = GlobalKey<NavigatorState>();
|
final GlobalKey<NavigatorState> _navigatorKey = GlobalKey<NavigatorState>();
|
||||||
|
@ -1263,7 +1265,7 @@ class _MasterDetailFlowState extends State<_MasterDetailFlow> implements _PageOp
|
||||||
void openDetailPage(Object arguments) {
|
void openDetailPage(Object arguments) {
|
||||||
_cachedDetailArguments = arguments;
|
_cachedDetailArguments = arguments;
|
||||||
if (_builtLayout == _LayoutMode.nested) {
|
if (_builtLayout == _LayoutMode.nested) {
|
||||||
_navigatorKey.currentState!.pushNamed(_navDetail, arguments: arguments);
|
_navigatorKey.currentState.pushNamed(_navDetail, arguments: arguments);
|
||||||
} else {
|
} else {
|
||||||
focus = _Focus.detail;
|
focus = _Focus.detail;
|
||||||
}
|
}
|
||||||
|
@ -1301,7 +1303,7 @@ class _MasterDetailFlowState extends State<_MasterDetailFlow> implements _PageOp
|
||||||
|
|
||||||
return WillPopScope(
|
return WillPopScope(
|
||||||
// Push pop check into nested navigator.
|
// Push pop check into nested navigator.
|
||||||
onWillPop: () async => !(await _navigatorKey.currentState!.maybePop()),
|
onWillPop: () async => !(await _navigatorKey.currentState.maybePop()),
|
||||||
child: Navigator(
|
child: Navigator(
|
||||||
key: _navigatorKey,
|
key: _navigatorKey,
|
||||||
initialRoute: 'initial',
|
initialRoute: 'initial',
|
||||||
|
@ -1341,11 +1343,11 @@ class _MasterDetailFlowState extends State<_MasterDetailFlow> implements _PageOp
|
||||||
return MaterialPageRoute<dynamic>(
|
return MaterialPageRoute<dynamic>(
|
||||||
builder: (BuildContext c) => BlockSemantics(
|
builder: (BuildContext c) => BlockSemantics(
|
||||||
child: widget.masterPageBuilder != null
|
child: widget.masterPageBuilder != null
|
||||||
? widget.masterPageBuilder!(c, false)
|
? widget.masterPageBuilder(c, false)
|
||||||
: _MasterPage(
|
: _MasterPage(
|
||||||
leading: widget.leading ??
|
leading: widget.leading ??
|
||||||
(widget.automaticallyImplyLeading && Navigator.of(context)!.canPop()
|
(widget.automaticallyImplyLeading && Navigator.of(context).canPop()
|
||||||
? BackButton(onPressed: () => Navigator.of(context)!.pop())
|
? BackButton(onPressed: () => Navigator.of(context).pop())
|
||||||
: null),
|
: null),
|
||||||
title: widget.title,
|
title: widget.title,
|
||||||
centerTitle: widget.centerTitle,
|
centerTitle: widget.centerTitle,
|
||||||
|
@ -1360,13 +1362,13 @@ class _MasterDetailFlowState extends State<_MasterDetailFlow> implements _PageOp
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
MaterialPageRoute<void> _detailPageRoute(Object? arguments) {
|
MaterialPageRoute<void> _detailPageRoute(Object arguments) {
|
||||||
return MaterialPageRoute<dynamic>(builder: (BuildContext context) {
|
return MaterialPageRoute<dynamic>(builder: (BuildContext context) {
|
||||||
return WillPopScope(
|
return WillPopScope(
|
||||||
onWillPop: () async {
|
onWillPop: () async {
|
||||||
// No need for setState() as rebuild happens on navigation pop.
|
// No need for setState() as rebuild happens on navigation pop.
|
||||||
focus = _Focus.master;
|
focus = _Focus.master;
|
||||||
Navigator.of(context)!.pop();
|
Navigator.of(context).pop();
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
child: BlockSemantics(child: widget.detailPageBuilder(context, arguments, null)),
|
child: BlockSemantics(child: widget.detailPageBuilder(context, arguments, null)),
|
||||||
|
@ -1380,7 +1382,7 @@ class _MasterDetailFlowState extends State<_MasterDetailFlow> implements _PageOp
|
||||||
actionBuilder: widget.actionBuilder ?? (_, __) => const<Widget>[],
|
actionBuilder: widget.actionBuilder ?? (_, __) => const<Widget>[],
|
||||||
automaticallyImplyLeading: widget.automaticallyImplyLeading,
|
automaticallyImplyLeading: widget.automaticallyImplyLeading,
|
||||||
centerTitle: widget.centerTitle,
|
centerTitle: widget.centerTitle,
|
||||||
detailPageBuilder: (BuildContext context, Object? args, ScrollController? scrollController) =>
|
detailPageBuilder: (BuildContext context, Object args, ScrollController scrollController) =>
|
||||||
widget.detailPageBuilder(context, args ?? _cachedDetailArguments, scrollController),
|
widget.detailPageBuilder(context, args ?? _cachedDetailArguments, scrollController),
|
||||||
floatingActionButton: widget.floatingActionButton,
|
floatingActionButton: widget.floatingActionButton,
|
||||||
detailPageFABlessGutterWidth: widget.detailPageFABlessGutterWidth,
|
detailPageFABlessGutterWidth: widget.detailPageFABlessGutterWidth,
|
||||||
|
@ -1397,7 +1399,7 @@ class _MasterDetailFlowState extends State<_MasterDetailFlow> implements _PageOp
|
||||||
|
|
||||||
class _MasterPage extends StatelessWidget {
|
class _MasterPage extends StatelessWidget {
|
||||||
const _MasterPage({
|
const _MasterPage({
|
||||||
Key? key,
|
Key key,
|
||||||
this.leading,
|
this.leading,
|
||||||
this.title,
|
this.title,
|
||||||
this.actionBuilder,
|
this.actionBuilder,
|
||||||
|
@ -1406,18 +1408,18 @@ class _MasterPage extends StatelessWidget {
|
||||||
this.floatingActionButton,
|
this.floatingActionButton,
|
||||||
this.floatingActionButtonLocation,
|
this.floatingActionButtonLocation,
|
||||||
this.masterViewBuilder,
|
this.masterViewBuilder,
|
||||||
required this.automaticallyImplyLeading,
|
this.automaticallyImplyLeading,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
final _MasterViewBuilder? masterViewBuilder;
|
final _MasterViewBuilder masterViewBuilder;
|
||||||
final Widget? title;
|
final Widget title;
|
||||||
final Widget? leading;
|
final Widget leading;
|
||||||
final bool automaticallyImplyLeading;
|
final bool automaticallyImplyLeading;
|
||||||
final bool? centerTitle;
|
final bool centerTitle;
|
||||||
final Widget? flexibleSpace;
|
final Widget flexibleSpace;
|
||||||
final _ActionBuilder? actionBuilder;
|
final _ActionBuilder actionBuilder;
|
||||||
final FloatingActionButton? floatingActionButton;
|
final FloatingActionButton floatingActionButton;
|
||||||
final FloatingActionButtonLocation? floatingActionButtonLocation;
|
final FloatingActionButtonLocation floatingActionButtonLocation;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -1427,12 +1429,12 @@ class _MasterPage extends StatelessWidget {
|
||||||
leading: leading,
|
leading: leading,
|
||||||
actions: actionBuilder == null
|
actions: actionBuilder == null
|
||||||
? const <Widget>[]
|
? const <Widget>[]
|
||||||
: actionBuilder!(context, _ActionLevel.composite),
|
: actionBuilder(context, _ActionLevel.composite),
|
||||||
centerTitle: centerTitle,
|
centerTitle: centerTitle,
|
||||||
flexibleSpace: flexibleSpace,
|
flexibleSpace: flexibleSpace,
|
||||||
automaticallyImplyLeading: automaticallyImplyLeading,
|
automaticallyImplyLeading: automaticallyImplyLeading,
|
||||||
),
|
),
|
||||||
body: masterViewBuilder!(context, false),
|
body: masterViewBuilder(context, false),
|
||||||
floatingActionButton: floatingActionButton,
|
floatingActionButton: floatingActionButton,
|
||||||
floatingActionButtonLocation: floatingActionButtonLocation,
|
floatingActionButtonLocation: floatingActionButtonLocation,
|
||||||
);
|
);
|
||||||
|
@ -1447,16 +1449,16 @@ const double _kDetailPageFABGutterWidth = 84.0;
|
||||||
|
|
||||||
class _MasterDetailScaffold extends StatefulWidget {
|
class _MasterDetailScaffold extends StatefulWidget {
|
||||||
const _MasterDetailScaffold({
|
const _MasterDetailScaffold({
|
||||||
Key? key,
|
Key key,
|
||||||
required this.detailPageBuilder,
|
@required this.detailPageBuilder,
|
||||||
required this.masterViewBuilder,
|
@required this.masterViewBuilder,
|
||||||
this.actionBuilder,
|
this.actionBuilder,
|
||||||
this.floatingActionButton,
|
this.floatingActionButton,
|
||||||
this.floatingActionButtonLocation,
|
this.floatingActionButtonLocation,
|
||||||
this.initialArguments,
|
this.initialArguments,
|
||||||
this.leading,
|
this.leading,
|
||||||
this.title,
|
this.title,
|
||||||
required this.automaticallyImplyLeading,
|
this.automaticallyImplyLeading,
|
||||||
this.centerTitle,
|
this.centerTitle,
|
||||||
this.detailPageFABlessGutterWidth,
|
this.detailPageFABlessGutterWidth,
|
||||||
this.detailPageFABGutterWidth,
|
this.detailPageFABGutterWidth,
|
||||||
|
@ -1473,17 +1475,17 @@ class _MasterDetailScaffold extends StatefulWidget {
|
||||||
/// that uses the [ScrollController] provided. In fact, it is strongly recommended the entire
|
/// that uses the [ScrollController] provided. In fact, it is strongly recommended the entire
|
||||||
/// lateral page is scrollable.
|
/// lateral page is scrollable.
|
||||||
final _DetailPageBuilder detailPageBuilder;
|
final _DetailPageBuilder detailPageBuilder;
|
||||||
final _ActionBuilder? actionBuilder;
|
final _ActionBuilder actionBuilder;
|
||||||
final FloatingActionButton? floatingActionButton;
|
final FloatingActionButton floatingActionButton;
|
||||||
final FloatingActionButtonLocation? floatingActionButtonLocation;
|
final FloatingActionButtonLocation floatingActionButtonLocation;
|
||||||
final Object? initialArguments;
|
final Object initialArguments;
|
||||||
final Widget? leading;
|
final Widget leading;
|
||||||
final Widget? title;
|
final Widget title;
|
||||||
final bool automaticallyImplyLeading;
|
final bool automaticallyImplyLeading;
|
||||||
final bool? centerTitle;
|
final bool centerTitle;
|
||||||
final double? detailPageFABlessGutterWidth;
|
final double detailPageFABlessGutterWidth;
|
||||||
final double? detailPageFABGutterWidth;
|
final double detailPageFABGutterWidth;
|
||||||
final double? masterViewWidth;
|
final double masterViewWidth;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_MasterDetailScaffoldState createState() => _MasterDetailScaffoldState();
|
_MasterDetailScaffoldState createState() => _MasterDetailScaffoldState();
|
||||||
|
@ -1491,12 +1493,12 @@ class _MasterDetailScaffold extends StatefulWidget {
|
||||||
|
|
||||||
class _MasterDetailScaffoldState extends State<_MasterDetailScaffold>
|
class _MasterDetailScaffoldState extends State<_MasterDetailScaffold>
|
||||||
implements _PageOpener {
|
implements _PageOpener {
|
||||||
late FloatingActionButtonLocation floatingActionButtonLocation;
|
FloatingActionButtonLocation floatingActionButtonLocation;
|
||||||
late double detailPageFABGutterWidth;
|
double detailPageFABGutterWidth;
|
||||||
late double detailPageFABlessGutterWidth;
|
double detailPageFABlessGutterWidth;
|
||||||
late double masterViewWidth;
|
double masterViewWidth;
|
||||||
|
|
||||||
final ValueNotifier<Object?> _detailArguments = ValueNotifier<Object?>(null);
|
final ValueNotifier<Object> _detailArguments = ValueNotifier<Object>(null);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
@ -1509,16 +1511,16 @@ class _MasterDetailScaffoldState extends State<_MasterDetailScaffold>
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void openDetailPage(Object arguments) {
|
void openDetailPage(Object arguments) {
|
||||||
SchedulerBinding.instance!
|
SchedulerBinding.instance
|
||||||
.addPostFrameCallback((_) => _detailArguments.value = arguments);
|
.addPostFrameCallback((_) => _detailArguments.value = arguments);
|
||||||
_MasterDetailFlow.of(context)!.openDetailPage(arguments);
|
_MasterDetailFlow.of(context).openDetailPage(arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void setInitialDetailPage(Object arguments) {
|
void setInitialDetailPage(Object arguments) {
|
||||||
SchedulerBinding.instance!
|
SchedulerBinding.instance
|
||||||
.addPostFrameCallback((_) => _detailArguments.value = arguments);
|
.addPostFrameCallback((_) => _detailArguments.value = arguments);
|
||||||
_MasterDetailFlow.of(context)!.setInitialDetailPage(arguments);
|
_MasterDetailFlow.of(context).setInitialDetailPage(arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -1529,7 +1531,7 @@ class _MasterDetailScaffoldState extends State<_MasterDetailScaffold>
|
||||||
floatingActionButtonLocation: floatingActionButtonLocation,
|
floatingActionButtonLocation: floatingActionButtonLocation,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: widget.title,
|
title: widget.title,
|
||||||
actions: widget.actionBuilder!(context, _ActionLevel.top),
|
actions: widget.actionBuilder(context, _ActionLevel.top),
|
||||||
leading: widget.leading,
|
leading: widget.leading,
|
||||||
automaticallyImplyLeading: widget.automaticallyImplyLeading,
|
automaticallyImplyLeading: widget.automaticallyImplyLeading,
|
||||||
centerTitle: widget.centerTitle,
|
centerTitle: widget.centerTitle,
|
||||||
|
@ -1542,10 +1544,10 @@ class _MasterDetailScaffoldState extends State<_MasterDetailScaffold>
|
||||||
constraints:
|
constraints:
|
||||||
BoxConstraints.tightFor(width: masterViewWidth),
|
BoxConstraints.tightFor(width: masterViewWidth),
|
||||||
child: IconTheme(
|
child: IconTheme(
|
||||||
data: Theme.of(context)!.primaryIconTheme,
|
data: Theme.of(context).primaryIconTheme,
|
||||||
child: ButtonBar(
|
child: ButtonBar(
|
||||||
children:
|
children:
|
||||||
widget.actionBuilder!(context, _ActionLevel.view),
|
widget.actionBuilder(context, _ActionLevel.view),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -1565,9 +1567,9 @@ class _MasterDetailScaffoldState extends State<_MasterDetailScaffold>
|
||||||
? detailPageFABlessGutterWidth
|
? detailPageFABlessGutterWidth
|
||||||
: detailPageFABGutterWidth,
|
: detailPageFABGutterWidth,
|
||||||
),
|
),
|
||||||
child: ValueListenableBuilder<Object?>(
|
child: ValueListenableBuilder<Object>(
|
||||||
valueListenable: _detailArguments,
|
valueListenable: _detailArguments,
|
||||||
builder: (BuildContext context, Object? value, Widget? child) {
|
builder: (BuildContext context, Object value, Widget child) {
|
||||||
return AnimatedSwitcher(
|
return AnimatedSwitcher(
|
||||||
transitionBuilder:
|
transitionBuilder:
|
||||||
(Widget child, Animation<double> animation) =>
|
(Widget child, Animation<double> animation) =>
|
||||||
|
@ -1576,7 +1578,7 @@ class _MasterDetailScaffoldState extends State<_MasterDetailScaffold>
|
||||||
null, null, animation, null, child),
|
null, null, animation, null, child),
|
||||||
duration: const Duration(milliseconds: 500),
|
duration: const Duration(milliseconds: 500),
|
||||||
child: Container(
|
child: Container(
|
||||||
key: ValueKey<Object?>(value ?? widget.initialArguments),
|
key: ValueKey<Object>(value ?? widget.initialArguments),
|
||||||
constraints: const BoxConstraints.expand(),
|
constraints: const BoxConstraints.expand(),
|
||||||
child: _DetailView(
|
child: _DetailView(
|
||||||
builder: widget.detailPageBuilder,
|
builder: widget.detailPageBuilder,
|
||||||
|
@ -1599,7 +1601,7 @@ class _MasterDetailScaffoldState extends State<_MasterDetailScaffold>
|
||||||
? Scaffold(
|
? Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: widget.title,
|
title: widget.title,
|
||||||
actions: widget.actionBuilder!(context, _ActionLevel.top),
|
actions: widget.actionBuilder(context, _ActionLevel.top),
|
||||||
leading: widget.leading,
|
leading: widget.leading,
|
||||||
automaticallyImplyLeading: widget.automaticallyImplyLeading,
|
automaticallyImplyLeading: widget.automaticallyImplyLeading,
|
||||||
centerTitle: widget.centerTitle,
|
centerTitle: widget.centerTitle,
|
||||||
|
@ -1613,23 +1615,23 @@ class _MasterDetailScaffoldState extends State<_MasterDetailScaffold>
|
||||||
|
|
||||||
class _DetailView extends StatelessWidget {
|
class _DetailView extends StatelessWidget {
|
||||||
const _DetailView({
|
const _DetailView({
|
||||||
Key? key,
|
Key key,
|
||||||
required _DetailPageBuilder builder,
|
@required _DetailPageBuilder builder,
|
||||||
Object? arguments,
|
Object arguments,
|
||||||
}) : assert(builder != null),
|
}) : assert(builder != null),
|
||||||
_builder = builder,
|
_builder = builder,
|
||||||
_arguments = arguments,
|
_arguments = arguments,
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
final _DetailPageBuilder _builder;
|
final _DetailPageBuilder _builder;
|
||||||
final Object? _arguments;
|
final Object _arguments;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (_arguments == null) {
|
if (_arguments == null) {
|
||||||
return Container();
|
return Container();
|
||||||
}
|
}
|
||||||
final double screenHeight = MediaQuery.of(context)!.size.height;
|
final double screenHeight = MediaQuery.of(context).size.height;
|
||||||
final double minHeight = (screenHeight - kToolbarHeight) / screenHeight;
|
final double minHeight = (screenHeight - kToolbarHeight) / screenHeight;
|
||||||
|
|
||||||
return DraggableScrollableSheet(
|
return DraggableScrollableSheet(
|
||||||
|
@ -1641,7 +1643,7 @@ class _DetailView extends StatelessWidget {
|
||||||
return MouseRegion(
|
return MouseRegion(
|
||||||
// TODO(TonicArtos): Remove MouseRegion workaround for pointer hover events passing through DraggableScrollableSheet once https://github.com/flutter/flutter/issues/59741 is resolved.
|
// TODO(TonicArtos): Remove MouseRegion workaround for pointer hover events passing through DraggableScrollableSheet once https://github.com/flutter/flutter/issues/59741 is resolved.
|
||||||
child: Card(
|
child: Card(
|
||||||
color: Theme.of(context)!.cardColor,
|
color: Theme.of(context).cardColor,
|
||||||
elevation: _kCardElevation,
|
elevation: _kCardElevation,
|
||||||
clipBehavior: Clip.antiAlias,
|
clipBehavior: Clip.antiAlias,
|
||||||
margin: const EdgeInsets.fromLTRB(
|
margin: const EdgeInsets.fromLTRB(
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
// @dart = 2.8
|
||||||
|
|
||||||
import 'dart:ui' as ui;
|
import 'dart:ui' as ui;
|
||||||
|
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
@ -164,7 +166,7 @@ class MaterialApp extends StatefulWidget {
|
||||||
///
|
///
|
||||||
/// The boolean arguments, [routes], and [navigatorObservers], must not be null.
|
/// The boolean arguments, [routes], and [navigatorObservers], must not be null.
|
||||||
const MaterialApp({
|
const MaterialApp({
|
||||||
Key? key,
|
Key key,
|
||||||
this.navigatorKey,
|
this.navigatorKey,
|
||||||
this.home,
|
this.home,
|
||||||
this.routes = const <String, WidgetBuilder>{},
|
this.routes = const <String, WidgetBuilder>{},
|
||||||
|
@ -213,10 +215,10 @@ class MaterialApp extends StatefulWidget {
|
||||||
|
|
||||||
/// Creates a [MaterialApp] that uses the [Router] instead of a [Navigator].
|
/// Creates a [MaterialApp] that uses the [Router] instead of a [Navigator].
|
||||||
const MaterialApp.router({
|
const MaterialApp.router({
|
||||||
Key? key,
|
Key key,
|
||||||
this.routeInformationProvider,
|
this.routeInformationProvider,
|
||||||
required this.routeInformationParser,
|
@required this.routeInformationParser,
|
||||||
required this.routerDelegate,
|
@required this.routerDelegate,
|
||||||
this.backButtonDispatcher,
|
this.backButtonDispatcher,
|
||||||
this.builder,
|
this.builder,
|
||||||
this.title = '',
|
this.title = '',
|
||||||
|
@ -261,10 +263,10 @@ class MaterialApp extends StatefulWidget {
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
/// {@macro flutter.widgets.widgetsApp.navigatorKey}
|
/// {@macro flutter.widgets.widgetsApp.navigatorKey}
|
||||||
final GlobalKey<NavigatorState>? navigatorKey;
|
final GlobalKey<NavigatorState> navigatorKey;
|
||||||
|
|
||||||
/// {@macro flutter.widgets.widgetsApp.home}
|
/// {@macro flutter.widgets.widgetsApp.home}
|
||||||
final Widget? home;
|
final Widget home;
|
||||||
|
|
||||||
/// The application's top-level routing table.
|
/// The application's top-level routing table.
|
||||||
///
|
///
|
||||||
|
@ -274,41 +276,41 @@ class MaterialApp extends StatefulWidget {
|
||||||
/// an appropriate transition, including [Hero] animations, to the new route.
|
/// an appropriate transition, including [Hero] animations, to the new route.
|
||||||
///
|
///
|
||||||
/// {@macro flutter.widgets.widgetsApp.routes}
|
/// {@macro flutter.widgets.widgetsApp.routes}
|
||||||
final Map<String, WidgetBuilder>? routes;
|
final Map<String, WidgetBuilder> routes;
|
||||||
|
|
||||||
/// {@macro flutter.widgets.widgetsApp.initialRoute}
|
/// {@macro flutter.widgets.widgetsApp.initialRoute}
|
||||||
final String? initialRoute;
|
final String initialRoute;
|
||||||
|
|
||||||
/// {@macro flutter.widgets.widgetsApp.onGenerateRoute}
|
/// {@macro flutter.widgets.widgetsApp.onGenerateRoute}
|
||||||
final RouteFactory? onGenerateRoute;
|
final RouteFactory onGenerateRoute;
|
||||||
|
|
||||||
/// {@macro flutter.widgets.widgetsApp.onGenerateInitialRoutes}
|
/// {@macro flutter.widgets.widgetsApp.onGenerateInitialRoutes}
|
||||||
final InitialRouteListFactory? onGenerateInitialRoutes;
|
final InitialRouteListFactory onGenerateInitialRoutes;
|
||||||
|
|
||||||
/// {@macro flutter.widgets.widgetsApp.onUnknownRoute}
|
/// {@macro flutter.widgets.widgetsApp.onUnknownRoute}
|
||||||
final RouteFactory? onUnknownRoute;
|
final RouteFactory onUnknownRoute;
|
||||||
|
|
||||||
/// {@macro flutter.widgets.widgetsApp.navigatorObservers}
|
/// {@macro flutter.widgets.widgetsApp.navigatorObservers}
|
||||||
final List<NavigatorObserver>? navigatorObservers;
|
final List<NavigatorObserver> navigatorObservers;
|
||||||
|
|
||||||
/// {@macro flutter.widgets.widgetsApp.routeInformationProvider}
|
/// {@macro flutter.widgets.widgetsApp.routeInformationProvider}
|
||||||
final RouteInformationProvider? routeInformationProvider;
|
final RouteInformationProvider routeInformationProvider;
|
||||||
|
|
||||||
/// {@macro flutter.widgets.widgetsApp.routeInformationParser}
|
/// {@macro flutter.widgets.widgetsApp.routeInformationParser}
|
||||||
final RouteInformationParser<Object>? routeInformationParser;
|
final RouteInformationParser<Object> routeInformationParser;
|
||||||
|
|
||||||
/// {@macro flutter.widgets.widgetsApp.routerDelegate}
|
/// {@macro flutter.widgets.widgetsApp.routerDelegate}
|
||||||
final RouterDelegate<Object>? routerDelegate;
|
final RouterDelegate<Object> routerDelegate;
|
||||||
|
|
||||||
/// {@macro flutter.widgets.widgetsApp.backButtonDispatcher}
|
/// {@macro flutter.widgets.widgetsApp.backButtonDispatcher}
|
||||||
final BackButtonDispatcher? backButtonDispatcher;
|
final BackButtonDispatcher backButtonDispatcher;
|
||||||
|
|
||||||
/// {@macro flutter.widgets.widgetsApp.builder}
|
/// {@macro flutter.widgets.widgetsApp.builder}
|
||||||
///
|
///
|
||||||
/// Material specific features such as [showDialog] and [showMenu], and widgets
|
/// Material specific features such as [showDialog] and [showMenu], and widgets
|
||||||
/// such as [Tooltip], [PopupMenuButton], also require a [Navigator] to properly
|
/// such as [Tooltip], [PopupMenuButton], also require a [Navigator] to properly
|
||||||
/// function.
|
/// function.
|
||||||
final TransitionBuilder? builder;
|
final TransitionBuilder builder;
|
||||||
|
|
||||||
/// {@macro flutter.widgets.widgetsApp.title}
|
/// {@macro flutter.widgets.widgetsApp.title}
|
||||||
///
|
///
|
||||||
|
@ -318,7 +320,7 @@ class MaterialApp extends StatefulWidget {
|
||||||
/// {@macro flutter.widgets.widgetsApp.onGenerateTitle}
|
/// {@macro flutter.widgets.widgetsApp.onGenerateTitle}
|
||||||
///
|
///
|
||||||
/// This value is passed unmodified to [WidgetsApp.onGenerateTitle].
|
/// This value is passed unmodified to [WidgetsApp.onGenerateTitle].
|
||||||
final GenerateAppTitle? onGenerateTitle;
|
final GenerateAppTitle onGenerateTitle;
|
||||||
|
|
||||||
/// Default visual properties, like colors fonts and shapes, for this app's
|
/// Default visual properties, like colors fonts and shapes, for this app's
|
||||||
/// material widgets.
|
/// material widgets.
|
||||||
|
@ -337,7 +339,7 @@ class MaterialApp extends StatefulWidget {
|
||||||
/// and [darkTheme] in [MaterialApp].
|
/// and [darkTheme] in [MaterialApp].
|
||||||
/// * [ThemeData.brightness], which indicates the [Brightness] of a theme's
|
/// * [ThemeData.brightness], which indicates the [Brightness] of a theme's
|
||||||
/// colors.
|
/// colors.
|
||||||
final ThemeData? theme;
|
final ThemeData theme;
|
||||||
|
|
||||||
/// The [ThemeData] to use when a 'dark mode' is requested by the system.
|
/// The [ThemeData] to use when a 'dark mode' is requested by the system.
|
||||||
///
|
///
|
||||||
|
@ -359,7 +361,7 @@ class MaterialApp extends StatefulWidget {
|
||||||
/// and [darkTheme] in [MaterialApp].
|
/// and [darkTheme] in [MaterialApp].
|
||||||
/// * [ThemeData.brightness], which is typically set to the value of
|
/// * [ThemeData.brightness], which is typically set to the value of
|
||||||
/// [MediaQueryData.platformBrightness].
|
/// [MediaQueryData.platformBrightness].
|
||||||
final ThemeData? darkTheme;
|
final ThemeData darkTheme;
|
||||||
|
|
||||||
/// The [ThemeData] to use when 'high contrast' is requested by the system.
|
/// The [ThemeData] to use when 'high contrast' is requested by the system.
|
||||||
///
|
///
|
||||||
|
@ -372,7 +374,7 @@ class MaterialApp extends StatefulWidget {
|
||||||
///
|
///
|
||||||
/// * [MediaQueryData.highContrast], which indicates the platform's
|
/// * [MediaQueryData.highContrast], which indicates the platform's
|
||||||
/// desire to increase contrast.
|
/// desire to increase contrast.
|
||||||
final ThemeData? highContrastTheme;
|
final ThemeData highContrastTheme;
|
||||||
|
|
||||||
/// The [ThemeData] to use when a 'dark mode' and 'high contrast' is requested
|
/// The [ThemeData] to use when a 'dark mode' and 'high contrast' is requested
|
||||||
/// by the system.
|
/// by the system.
|
||||||
|
@ -388,7 +390,7 @@ class MaterialApp extends StatefulWidget {
|
||||||
///
|
///
|
||||||
/// * [MediaQueryData.highContrast], which indicates the platform's
|
/// * [MediaQueryData.highContrast], which indicates the platform's
|
||||||
/// desire to increase contrast.
|
/// desire to increase contrast.
|
||||||
final ThemeData? highContrastDarkTheme;
|
final ThemeData highContrastDarkTheme;
|
||||||
|
|
||||||
/// Determines which theme will be used by the application if both [theme]
|
/// Determines which theme will be used by the application if both [theme]
|
||||||
/// and [darkTheme] are provided.
|
/// and [darkTheme] are provided.
|
||||||
|
@ -414,13 +416,13 @@ class MaterialApp extends StatefulWidget {
|
||||||
/// * [darkTheme], which is used when a dark mode is selected.
|
/// * [darkTheme], which is used when a dark mode is selected.
|
||||||
/// * [ThemeData.brightness], which indicates to various parts of the
|
/// * [ThemeData.brightness], which indicates to various parts of the
|
||||||
/// system what kind of theme is being used.
|
/// system what kind of theme is being used.
|
||||||
final ThemeMode? themeMode;
|
final ThemeMode themeMode;
|
||||||
|
|
||||||
/// {@macro flutter.widgets.widgetsApp.color}
|
/// {@macro flutter.widgets.widgetsApp.color}
|
||||||
final Color? color;
|
final Color color;
|
||||||
|
|
||||||
/// {@macro flutter.widgets.widgetsApp.locale}
|
/// {@macro flutter.widgets.widgetsApp.locale}
|
||||||
final Locale? locale;
|
final Locale locale;
|
||||||
|
|
||||||
/// {@macro flutter.widgets.widgetsApp.localizationsDelegates}
|
/// {@macro flutter.widgets.widgetsApp.localizationsDelegates}
|
||||||
///
|
///
|
||||||
|
@ -513,17 +515,17 @@ class MaterialApp extends StatefulWidget {
|
||||||
/// which provides material localizations for many languages.
|
/// which provides material localizations for many languages.
|
||||||
/// * The Flutter Internationalization Tutorial,
|
/// * The Flutter Internationalization Tutorial,
|
||||||
/// <https://flutter.dev/tutorials/internationalization/>.
|
/// <https://flutter.dev/tutorials/internationalization/>.
|
||||||
final Iterable<LocalizationsDelegate<dynamic>>? localizationsDelegates;
|
final Iterable<LocalizationsDelegate<dynamic>> localizationsDelegates;
|
||||||
|
|
||||||
/// {@macro flutter.widgets.widgetsApp.localeListResolutionCallback}
|
/// {@macro flutter.widgets.widgetsApp.localeListResolutionCallback}
|
||||||
///
|
///
|
||||||
/// This callback is passed along to the [WidgetsApp] built by this widget.
|
/// This callback is passed along to the [WidgetsApp] built by this widget.
|
||||||
final LocaleListResolutionCallback? localeListResolutionCallback;
|
final LocaleListResolutionCallback localeListResolutionCallback;
|
||||||
|
|
||||||
/// {@macro flutter.widgets.widgetsApp.localeResolutionCallback}
|
/// {@macro flutter.widgets.widgetsApp.localeResolutionCallback}
|
||||||
///
|
///
|
||||||
/// This callback is passed along to the [WidgetsApp] built by this widget.
|
/// This callback is passed along to the [WidgetsApp] built by this widget.
|
||||||
final LocaleResolutionCallback? localeResolutionCallback;
|
final LocaleResolutionCallback localeResolutionCallback;
|
||||||
|
|
||||||
/// {@macro flutter.widgets.widgetsApp.supportedLocales}
|
/// {@macro flutter.widgets.widgetsApp.supportedLocales}
|
||||||
///
|
///
|
||||||
|
@ -585,7 +587,7 @@ class MaterialApp extends StatefulWidget {
|
||||||
/// ```
|
/// ```
|
||||||
/// {@end-tool}
|
/// {@end-tool}
|
||||||
/// {@macro flutter.widgets.widgetsApp.shortcuts.seeAlso}
|
/// {@macro flutter.widgets.widgetsApp.shortcuts.seeAlso}
|
||||||
final Map<LogicalKeySet, Intent>? shortcuts;
|
final Map<LogicalKeySet, Intent> shortcuts;
|
||||||
|
|
||||||
/// {@macro flutter.widgets.widgetsApp.actions}
|
/// {@macro flutter.widgets.widgetsApp.actions}
|
||||||
/// {@tool snippet}
|
/// {@tool snippet}
|
||||||
|
@ -618,10 +620,10 @@ class MaterialApp extends StatefulWidget {
|
||||||
/// ```
|
/// ```
|
||||||
/// {@end-tool}
|
/// {@end-tool}
|
||||||
/// {@macro flutter.widgets.widgetsApp.actions.seeAlso}
|
/// {@macro flutter.widgets.widgetsApp.actions.seeAlso}
|
||||||
final Map<Type, Action<Intent>>? actions;
|
final Map<Type, Action<Intent>> actions;
|
||||||
|
|
||||||
/// {@macro flutter.widgets.widgetsApp.restorationScopeId}
|
/// {@macro flutter.widgets.widgetsApp.restorationScopeId}
|
||||||
final String? restorationScopeId;
|
final String restorationScopeId;
|
||||||
|
|
||||||
/// Turns on a [GridPaper] overlay that paints a baseline grid
|
/// Turns on a [GridPaper] overlay that paints a baseline grid
|
||||||
/// Material apps.
|
/// Material apps.
|
||||||
|
@ -641,7 +643,7 @@ class MaterialApp extends StatefulWidget {
|
||||||
/// Used by the [MaterialApp].
|
/// Used by the [MaterialApp].
|
||||||
static HeroController createMaterialHeroController() {
|
static HeroController createMaterialHeroController() {
|
||||||
return HeroController(
|
return HeroController(
|
||||||
createRectTween: (Rect? begin, Rect? end) {
|
createRectTween: (Rect begin, Rect end) {
|
||||||
return MaterialRectArcTween(begin: begin, end: end);
|
return MaterialRectArcTween(begin: begin, end: end);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -651,7 +653,7 @@ class MaterialApp extends StatefulWidget {
|
||||||
class _MaterialScrollBehavior extends ScrollBehavior {
|
class _MaterialScrollBehavior extends ScrollBehavior {
|
||||||
@override
|
@override
|
||||||
TargetPlatform getPlatform(BuildContext context) {
|
TargetPlatform getPlatform(BuildContext context) {
|
||||||
return Theme.of(context)!.platform;
|
return Theme.of(context).platform;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -669,14 +671,15 @@ class _MaterialScrollBehavior extends ScrollBehavior {
|
||||||
return GlowingOverscrollIndicator(
|
return GlowingOverscrollIndicator(
|
||||||
child: child,
|
child: child,
|
||||||
axisDirection: axisDirection,
|
axisDirection: axisDirection,
|
||||||
color: Theme.of(context)!.accentColor,
|
color: Theme.of(context).accentColor,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _MaterialAppState extends State<MaterialApp> {
|
class _MaterialAppState extends State<MaterialApp> {
|
||||||
late HeroController _heroController;
|
HeroController _heroController;
|
||||||
|
|
||||||
bool get _usesRouter => widget.routerDelegate != null;
|
bool get _usesRouter => widget.routerDelegate != null;
|
||||||
|
|
||||||
|
@ -693,7 +696,7 @@ class _MaterialAppState extends State<MaterialApp> {
|
||||||
// _MaterialLocalizationsDelegate.
|
// _MaterialLocalizationsDelegate.
|
||||||
Iterable<LocalizationsDelegate<dynamic>> get _localizationsDelegates sync* {
|
Iterable<LocalizationsDelegate<dynamic>> get _localizationsDelegates sync* {
|
||||||
if (widget.localizationsDelegates != null)
|
if (widget.localizationsDelegates != null)
|
||||||
yield* widget.localizationsDelegates!;
|
yield* widget.localizationsDelegates;
|
||||||
yield DefaultMaterialLocalizations.delegate;
|
yield DefaultMaterialLocalizations.delegate;
|
||||||
yield DefaultCupertinoLocalizations.delegate;
|
yield DefaultCupertinoLocalizations.delegate;
|
||||||
}
|
}
|
||||||
|
@ -706,14 +709,14 @@ class _MaterialAppState extends State<MaterialApp> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _materialBuilder(BuildContext context, Widget? child) {
|
Widget _materialBuilder(BuildContext context, Widget child) {
|
||||||
// Resolve which theme to use based on brightness and high contrast.
|
// Resolve which theme to use based on brightness and high contrast.
|
||||||
final ThemeMode mode = widget.themeMode ?? ThemeMode.system;
|
final ThemeMode mode = widget.themeMode ?? ThemeMode.system;
|
||||||
final Brightness platformBrightness = MediaQuery.platformBrightnessOf(context);
|
final Brightness platformBrightness = MediaQuery.platformBrightnessOf(context);
|
||||||
final bool useDarkTheme = mode == ThemeMode.dark
|
final bool useDarkTheme = mode == ThemeMode.dark
|
||||||
|| (mode == ThemeMode.system && platformBrightness == ui.Brightness.dark);
|
|| (mode == ThemeMode.system && platformBrightness == ui.Brightness.dark);
|
||||||
final bool highContrast = MediaQuery.highContrastOf(context);
|
final bool highContrast = MediaQuery.highContrastOf(context);
|
||||||
ThemeData? theme;
|
ThemeData theme;
|
||||||
|
|
||||||
if (useDarkTheme && highContrast && widget.highContrastDarkTheme != null) {
|
if (useDarkTheme && highContrast && widget.highContrastDarkTheme != null) {
|
||||||
theme = widget.highContrastDarkTheme;
|
theme = widget.highContrastDarkTheme;
|
||||||
|
@ -741,10 +744,10 @@ class _MaterialAppState extends State<MaterialApp> {
|
||||||
// surround widget.builder with yet another builder so that
|
// surround widget.builder with yet another builder so that
|
||||||
// a context separates them and Theme.of() correctly
|
// a context separates them and Theme.of() correctly
|
||||||
// resolves to the theme we passed to AnimatedTheme.
|
// resolves to the theme we passed to AnimatedTheme.
|
||||||
return widget.builder!(context, child);
|
return widget.builder(context, child);
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
: child!,
|
: child,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -761,8 +764,8 @@ class _MaterialAppState extends State<MaterialApp> {
|
||||||
return WidgetsApp.router(
|
return WidgetsApp.router(
|
||||||
key: GlobalObjectKey(this),
|
key: GlobalObjectKey(this),
|
||||||
routeInformationProvider: widget.routeInformationProvider,
|
routeInformationProvider: widget.routeInformationProvider,
|
||||||
routeInformationParser: widget.routeInformationParser!,
|
routeInformationParser: widget.routeInformationParser,
|
||||||
routerDelegate: widget.routerDelegate!,
|
routerDelegate: widget.routerDelegate,
|
||||||
backButtonDispatcher: widget.backButtonDispatcher,
|
backButtonDispatcher: widget.backButtonDispatcher,
|
||||||
builder: _materialBuilder,
|
builder: _materialBuilder,
|
||||||
title: widget.title,
|
title: widget.title,
|
||||||
|
@ -789,12 +792,12 @@ class _MaterialAppState extends State<MaterialApp> {
|
||||||
return WidgetsApp(
|
return WidgetsApp(
|
||||||
key: GlobalObjectKey(this),
|
key: GlobalObjectKey(this),
|
||||||
navigatorKey: widget.navigatorKey,
|
navigatorKey: widget.navigatorKey,
|
||||||
navigatorObservers: widget.navigatorObservers!,
|
navigatorObservers: widget.navigatorObservers,
|
||||||
pageRouteBuilder: <T>(RouteSettings settings, WidgetBuilder builder) {
|
pageRouteBuilder: <T>(RouteSettings settings, WidgetBuilder builder) {
|
||||||
return MaterialPageRoute<T>(settings: settings, builder: builder);
|
return MaterialPageRoute<T>(settings: settings, builder: builder);
|
||||||
},
|
},
|
||||||
home: widget.home,
|
home: widget.home,
|
||||||
routes: widget.routes!,
|
routes: widget.routes,
|
||||||
initialRoute: widget.initialRoute,
|
initialRoute: widget.initialRoute,
|
||||||
onGenerateRoute: widget.onGenerateRoute,
|
onGenerateRoute: widget.onGenerateRoute,
|
||||||
onGenerateInitialRoutes: widget.onGenerateInitialRoutes,
|
onGenerateInitialRoutes: widget.onGenerateInitialRoutes,
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
// @dart = 2.8
|
||||||
|
|
||||||
import 'dart:math' as math;
|
import 'dart:math' as math;
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
@ -190,7 +192,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
|
||||||
///
|
///
|
||||||
/// Typically used in the [Scaffold.appBar] property.
|
/// Typically used in the [Scaffold.appBar] property.
|
||||||
AppBar({
|
AppBar({
|
||||||
Key? key,
|
Key key,
|
||||||
this.leading,
|
this.leading,
|
||||||
this.automaticallyImplyLeading = true,
|
this.automaticallyImplyLeading = true,
|
||||||
this.title,
|
this.title,
|
||||||
|
@ -219,7 +221,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
|
||||||
assert(titleSpacing != null),
|
assert(titleSpacing != null),
|
||||||
assert(toolbarOpacity != null),
|
assert(toolbarOpacity != null),
|
||||||
assert(bottomOpacity != null),
|
assert(bottomOpacity != null),
|
||||||
preferredSize = Size.fromHeight(toolbarHeight ?? kToolbarHeight + (bottom?.preferredSize.height ?? 0.0)),
|
preferredSize = Size.fromHeight(toolbarHeight ?? kToolbarHeight + (bottom?.preferredSize?.height ?? 0.0)),
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
/// A widget to display before the [title].
|
/// A widget to display before the [title].
|
||||||
|
@ -267,7 +269,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
|
||||||
///
|
///
|
||||||
/// * [Scaffold.appBar], in which an [AppBar] is usually placed.
|
/// * [Scaffold.appBar], in which an [AppBar] is usually placed.
|
||||||
/// * [Scaffold.drawer], in which the [Drawer] is usually placed.
|
/// * [Scaffold.drawer], in which the [Drawer] is usually placed.
|
||||||
final Widget? leading;
|
final Widget leading;
|
||||||
|
|
||||||
/// Controls whether we should try to imply the leading widget if null.
|
/// Controls whether we should try to imply the leading widget if null.
|
||||||
///
|
///
|
||||||
|
@ -306,7 +308,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
|
||||||
/// ),
|
/// ),
|
||||||
/// )
|
/// )
|
||||||
/// ```
|
/// ```
|
||||||
final Widget? title;
|
final Widget title;
|
||||||
|
|
||||||
/// Widgets to display in a row after the [title] widget.
|
/// Widgets to display in a row after the [title] widget.
|
||||||
///
|
///
|
||||||
|
@ -317,7 +319,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
|
||||||
/// The [actions] become the trailing component of the [NavigationToolbar] built
|
/// The [actions] become the trailing component of the [NavigationToolbar] built
|
||||||
/// by this widget. The height of each action is constrained to be no bigger
|
/// by this widget. The height of each action is constrained to be no bigger
|
||||||
/// than the [toolbarHeight].
|
/// than the [toolbarHeight].
|
||||||
final List<Widget>? actions;
|
final List<Widget> actions;
|
||||||
|
|
||||||
/// This widget is stacked behind the toolbar and the tab bar. It's height will
|
/// This widget is stacked behind the toolbar and the tab bar. It's height will
|
||||||
/// be the same as the app bar's overall height.
|
/// be the same as the app bar's overall height.
|
||||||
|
@ -327,7 +329,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
|
||||||
/// changes the [AppBar]'s height when scrolled.
|
/// changes the [AppBar]'s height when scrolled.
|
||||||
///
|
///
|
||||||
/// Typically a [FlexibleSpaceBar]. See [FlexibleSpaceBar] for details.
|
/// Typically a [FlexibleSpaceBar]. See [FlexibleSpaceBar] for details.
|
||||||
final Widget? flexibleSpace;
|
final Widget flexibleSpace;
|
||||||
|
|
||||||
/// This widget appears across the bottom of the app bar.
|
/// This widget appears across the bottom of the app bar.
|
||||||
///
|
///
|
||||||
|
@ -337,7 +339,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [PreferredSize], which can be used to give an arbitrary widget a preferred size.
|
/// * [PreferredSize], which can be used to give an arbitrary widget a preferred size.
|
||||||
final PreferredSizeWidget? bottom;
|
final PreferredSizeWidget bottom;
|
||||||
|
|
||||||
/// The z-coordinate at which to place this app bar relative to its parent.
|
/// The z-coordinate at which to place this app bar relative to its parent.
|
||||||
///
|
///
|
||||||
|
@ -348,20 +350,20 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
|
||||||
/// If this property is null, then [AppBarTheme.elevation] of
|
/// If this property is null, then [AppBarTheme.elevation] of
|
||||||
/// [ThemeData.appBarTheme] is used. If that is also null, the default value
|
/// [ThemeData.appBarTheme] is used. If that is also null, the default value
|
||||||
/// is 4.
|
/// is 4.
|
||||||
final double? elevation;
|
final double elevation;
|
||||||
|
|
||||||
/// The color to paint the shadow below the app bar.
|
/// The color to paint the shadow below the app bar.
|
||||||
///
|
///
|
||||||
/// If this property is null, then [AppBarTheme.shadowColor] of
|
/// If this property is null, then [AppBarTheme.shadowColor] of
|
||||||
/// [ThemeData.appBarTheme] is used. If that is also null, the default value
|
/// [ThemeData.appBarTheme] is used. If that is also null, the default value
|
||||||
/// is fully opaque black.
|
/// is fully opaque black.
|
||||||
final Color? shadowColor;
|
final Color shadowColor;
|
||||||
|
|
||||||
/// The material's shape as well its shadow.
|
/// The material's shape as well its shadow.
|
||||||
///
|
///
|
||||||
/// A shadow is only displayed if the [elevation] is greater than
|
/// A shadow is only displayed if the [elevation] is greater than
|
||||||
/// zero.
|
/// zero.
|
||||||
final ShapeBorder? shape;
|
final ShapeBorder shape;
|
||||||
|
|
||||||
/// The color to use for the app bar's material. Typically this should be set
|
/// The color to use for the app bar's material. Typically this should be set
|
||||||
/// along with [brightness], [iconTheme], [textTheme].
|
/// along with [brightness], [iconTheme], [textTheme].
|
||||||
|
@ -369,7 +371,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
|
||||||
/// If this property is null, then [AppBarTheme.color] of
|
/// If this property is null, then [AppBarTheme.color] of
|
||||||
/// [ThemeData.appBarTheme] is used. If that is also null, then
|
/// [ThemeData.appBarTheme] is used. If that is also null, then
|
||||||
/// [ThemeData.primaryColor] is used.
|
/// [ThemeData.primaryColor] is used.
|
||||||
final Color? backgroundColor;
|
final Color backgroundColor;
|
||||||
|
|
||||||
/// The brightness of the app bar's material. Typically this is set along
|
/// The brightness of the app bar's material. Typically this is set along
|
||||||
/// with [backgroundColor], [iconTheme], [textTheme].
|
/// with [backgroundColor], [iconTheme], [textTheme].
|
||||||
|
@ -377,7 +379,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
|
||||||
/// If this property is null, then [AppBarTheme.brightness] of
|
/// If this property is null, then [AppBarTheme.brightness] of
|
||||||
/// [ThemeData.appBarTheme] is used. If that is also null, then
|
/// [ThemeData.appBarTheme] is used. If that is also null, then
|
||||||
/// [ThemeData.primaryColorBrightness] is used.
|
/// [ThemeData.primaryColorBrightness] is used.
|
||||||
final Brightness? brightness;
|
final Brightness brightness;
|
||||||
|
|
||||||
/// The color, opacity, and size to use for app bar icons. Typically this
|
/// The color, opacity, and size to use for app bar icons. Typically this
|
||||||
/// is set along with [backgroundColor], [brightness], [textTheme].
|
/// is set along with [backgroundColor], [brightness], [textTheme].
|
||||||
|
@ -385,7 +387,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
|
||||||
/// If this property is null, then [AppBarTheme.iconTheme] of
|
/// If this property is null, then [AppBarTheme.iconTheme] of
|
||||||
/// [ThemeData.appBarTheme] is used. If that is also null, then
|
/// [ThemeData.appBarTheme] is used. If that is also null, then
|
||||||
/// [ThemeData.primaryIconTheme] is used.
|
/// [ThemeData.primaryIconTheme] is used.
|
||||||
final IconThemeData? iconTheme;
|
final IconThemeData iconTheme;
|
||||||
|
|
||||||
/// The color, opacity, and size to use for the icons that appear in the app
|
/// The color, opacity, and size to use for the icons that appear in the app
|
||||||
/// bar's [actions]. This should only be used when the [actions] should be
|
/// bar's [actions]. This should only be used when the [actions] should be
|
||||||
|
@ -395,7 +397,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
|
||||||
/// If this property is null, then [AppBarTheme.actionsIconTheme] of
|
/// If this property is null, then [AppBarTheme.actionsIconTheme] of
|
||||||
/// [ThemeData.appBarTheme] is used. If that is also null, then this falls
|
/// [ThemeData.appBarTheme] is used. If that is also null, then this falls
|
||||||
/// back to [iconTheme].
|
/// back to [iconTheme].
|
||||||
final IconThemeData? actionsIconTheme;
|
final IconThemeData actionsIconTheme;
|
||||||
|
|
||||||
/// The typographic styles to use for text in the app bar. Typically this is
|
/// The typographic styles to use for text in the app bar. Typically this is
|
||||||
/// set along with [brightness] [backgroundColor], [iconTheme].
|
/// set along with [brightness] [backgroundColor], [iconTheme].
|
||||||
|
@ -403,7 +405,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
|
||||||
/// If this property is null, then [AppBarTheme.textTheme] of
|
/// If this property is null, then [AppBarTheme.textTheme] of
|
||||||
/// [ThemeData.appBarTheme] is used. If that is also null, then
|
/// [ThemeData.appBarTheme] is used. If that is also null, then
|
||||||
/// [ThemeData.primaryTextTheme] is used.
|
/// [ThemeData.primaryTextTheme] is used.
|
||||||
final TextTheme? textTheme;
|
final TextTheme textTheme;
|
||||||
|
|
||||||
/// Whether this app bar is being displayed at the top of the screen.
|
/// Whether this app bar is being displayed at the top of the screen.
|
||||||
///
|
///
|
||||||
|
@ -417,7 +419,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
|
||||||
/// If this property is null, then [AppBarTheme.centerTitle] of
|
/// If this property is null, then [AppBarTheme.centerTitle] of
|
||||||
/// [ThemeData.appBarTheme] is used. If that is also null, then value is
|
/// [ThemeData.appBarTheme] is used. If that is also null, then value is
|
||||||
/// adapted to the current [TargetPlatform].
|
/// adapted to the current [TargetPlatform].
|
||||||
final bool? centerTitle;
|
final bool centerTitle;
|
||||||
|
|
||||||
/// Whether the title should be wrapped with header [Semantics].
|
/// Whether the title should be wrapped with header [Semantics].
|
||||||
///
|
///
|
||||||
|
@ -459,18 +461,18 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
|
||||||
/// Defines the height of the toolbar component of an [AppBar].
|
/// Defines the height of the toolbar component of an [AppBar].
|
||||||
///
|
///
|
||||||
/// By default, the value of `toolbarHeight` is [kToolbarHeight].
|
/// By default, the value of `toolbarHeight` is [kToolbarHeight].
|
||||||
final double? toolbarHeight;
|
final double toolbarHeight;
|
||||||
|
|
||||||
/// Defines the width of [leading] widget.
|
/// Defines the width of [leading] widget.
|
||||||
///
|
///
|
||||||
/// By default, the value of `leadingWidth` is 56.0.
|
/// By default, the value of `leadingWidth` is 56.0.
|
||||||
final double? leadingWidth;
|
final double leadingWidth;
|
||||||
|
|
||||||
bool _getEffectiveCenterTitle(ThemeData theme) {
|
bool _getEffectiveCenterTitle(ThemeData theme) {
|
||||||
if (centerTitle != null)
|
if (centerTitle != null)
|
||||||
return centerTitle!;
|
return centerTitle;
|
||||||
if (theme.appBarTheme.centerTitle != null)
|
if (theme.appBarTheme.centerTitle != null)
|
||||||
return theme.appBarTheme.centerTitle!;
|
return theme.appBarTheme.centerTitle;
|
||||||
assert(theme.platform != null);
|
assert(theme.platform != null);
|
||||||
switch (theme.platform) {
|
switch (theme.platform) {
|
||||||
case TargetPlatform.android:
|
case TargetPlatform.android:
|
||||||
|
@ -480,8 +482,9 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
|
||||||
return false;
|
return false;
|
||||||
case TargetPlatform.iOS:
|
case TargetPlatform.iOS:
|
||||||
case TargetPlatform.macOS:
|
case TargetPlatform.macOS:
|
||||||
return actions == null || actions!.length < 2;
|
return actions == null || actions.length < 2;
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -493,21 +496,21 @@ class _AppBarState extends State<AppBar> {
|
||||||
static const Color _defaultShadowColor = Color(0xFF000000);
|
static const Color _defaultShadowColor = Color(0xFF000000);
|
||||||
|
|
||||||
void _handleDrawerButton() {
|
void _handleDrawerButton() {
|
||||||
Scaffold.of(context)!.openDrawer();
|
Scaffold.of(context).openDrawer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handleDrawerButtonEnd() {
|
void _handleDrawerButtonEnd() {
|
||||||
Scaffold.of(context)!.openEndDrawer();
|
Scaffold.of(context).openEndDrawer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
assert(!widget.primary || debugCheckHasMediaQuery(context));
|
assert(!widget.primary || debugCheckHasMediaQuery(context));
|
||||||
assert(debugCheckHasMaterialLocalizations(context));
|
assert(debugCheckHasMaterialLocalizations(context));
|
||||||
final ThemeData? theme = Theme.of(context);
|
final ThemeData theme = Theme.of(context);
|
||||||
final AppBarTheme appBarTheme = AppBarTheme.of(context);
|
final AppBarTheme appBarTheme = AppBarTheme.of(context);
|
||||||
final ScaffoldState? scaffold = Scaffold.of(context, nullOk: true);
|
final ScaffoldState scaffold = Scaffold.of(context, nullOk: true);
|
||||||
final ModalRoute<dynamic>? parentRoute = ModalRoute.of(context);
|
final ModalRoute<dynamic> parentRoute = ModalRoute.of(context);
|
||||||
|
|
||||||
final bool hasDrawer = scaffold?.hasDrawer ?? false;
|
final bool hasDrawer = scaffold?.hasDrawer ?? false;
|
||||||
final bool hasEndDrawer = scaffold?.hasEndDrawer ?? false;
|
final bool hasEndDrawer = scaffold?.hasEndDrawer ?? false;
|
||||||
|
@ -518,23 +521,23 @@ class _AppBarState extends State<AppBar> {
|
||||||
|
|
||||||
IconThemeData overallIconTheme = widget.iconTheme
|
IconThemeData overallIconTheme = widget.iconTheme
|
||||||
?? appBarTheme.iconTheme
|
?? appBarTheme.iconTheme
|
||||||
?? theme!.primaryIconTheme;
|
?? theme.primaryIconTheme;
|
||||||
IconThemeData actionsIconTheme = widget.actionsIconTheme
|
IconThemeData actionsIconTheme = widget.actionsIconTheme
|
||||||
?? appBarTheme.actionsIconTheme
|
?? appBarTheme.actionsIconTheme
|
||||||
?? overallIconTheme;
|
?? overallIconTheme;
|
||||||
TextStyle? centerStyle = widget.textTheme?.headline6
|
TextStyle centerStyle = widget.textTheme?.headline6
|
||||||
?? appBarTheme.textTheme?.headline6
|
?? appBarTheme.textTheme?.headline6
|
||||||
?? theme!.primaryTextTheme.headline6;
|
?? theme.primaryTextTheme.headline6;
|
||||||
TextStyle? sideStyle = widget.textTheme?.bodyText2
|
TextStyle sideStyle = widget.textTheme?.bodyText2
|
||||||
?? appBarTheme.textTheme?.bodyText2
|
?? appBarTheme.textTheme?.bodyText2
|
||||||
?? theme!.primaryTextTheme.bodyText2;
|
?? theme.primaryTextTheme.bodyText2;
|
||||||
|
|
||||||
if (widget.toolbarOpacity != 1.0) {
|
if (widget.toolbarOpacity != 1.0) {
|
||||||
final double opacity = const Interval(0.25, 1.0, curve: Curves.fastOutSlowIn).transform(widget.toolbarOpacity);
|
final double opacity = const Interval(0.25, 1.0, curve: Curves.fastOutSlowIn).transform(widget.toolbarOpacity);
|
||||||
if (centerStyle?.color != null)
|
if (centerStyle?.color != null)
|
||||||
centerStyle = centerStyle!.copyWith(color: centerStyle.color!.withOpacity(opacity));
|
centerStyle = centerStyle.copyWith(color: centerStyle.color.withOpacity(opacity));
|
||||||
if (sideStyle?.color != null)
|
if (sideStyle?.color != null)
|
||||||
sideStyle = sideStyle!.copyWith(color: sideStyle.color!.withOpacity(opacity));
|
sideStyle = sideStyle.copyWith(color: sideStyle.color.withOpacity(opacity));
|
||||||
overallIconTheme = overallIconTheme.copyWith(
|
overallIconTheme = overallIconTheme.copyWith(
|
||||||
opacity: opacity * (overallIconTheme.opacity ?? 1.0)
|
opacity: opacity * (overallIconTheme.opacity ?? 1.0)
|
||||||
);
|
);
|
||||||
|
@ -543,13 +546,13 @@ class _AppBarState extends State<AppBar> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget? leading = widget.leading;
|
Widget leading = widget.leading;
|
||||||
if (leading == null && widget.automaticallyImplyLeading) {
|
if (leading == null && widget.automaticallyImplyLeading) {
|
||||||
if (hasDrawer) {
|
if (hasDrawer) {
|
||||||
leading = IconButton(
|
leading = IconButton(
|
||||||
icon: const Icon(Icons.menu),
|
icon: const Icon(Icons.menu),
|
||||||
onPressed: _handleDrawerButton,
|
onPressed: _handleDrawerButton,
|
||||||
tooltip: MaterialLocalizations.of(context)!.openAppDrawerTooltip,
|
tooltip: MaterialLocalizations.of(context).openAppDrawerTooltip,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
if (!hasEndDrawer && canPop)
|
if (!hasEndDrawer && canPop)
|
||||||
|
@ -563,10 +566,10 @@ class _AppBarState extends State<AppBar> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget? title = widget.title;
|
Widget title = widget.title;
|
||||||
if (title != null) {
|
if (title != null) {
|
||||||
bool? namesRoute;
|
bool namesRoute;
|
||||||
switch (theme!.platform) {
|
switch (theme.platform) {
|
||||||
case TargetPlatform.android:
|
case TargetPlatform.android:
|
||||||
case TargetPlatform.fuchsia:
|
case TargetPlatform.fuchsia:
|
||||||
case TargetPlatform.linux:
|
case TargetPlatform.linux:
|
||||||
|
@ -599,7 +602,7 @@ class _AppBarState extends State<AppBar> {
|
||||||
// sizes. To opt out, wrap the [title] widget in a [MediaQuery] widget
|
// sizes. To opt out, wrap the [title] widget in a [MediaQuery] widget
|
||||||
// with [MediaQueryData.textScaleFactor] set to
|
// with [MediaQueryData.textScaleFactor] set to
|
||||||
// `MediaQuery.textScaleFactorOf(context)`.
|
// `MediaQuery.textScaleFactorOf(context)`.
|
||||||
final MediaQueryData mediaQueryData = MediaQuery.of(context)!;
|
final MediaQueryData mediaQueryData = MediaQuery.of(context);
|
||||||
title = MediaQuery(
|
title = MediaQuery(
|
||||||
data: mediaQueryData.copyWith(
|
data: mediaQueryData.copyWith(
|
||||||
textScaleFactor: math.min(
|
textScaleFactor: math.min(
|
||||||
|
@ -611,18 +614,18 @@ class _AppBarState extends State<AppBar> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget? actions;
|
Widget actions;
|
||||||
if (widget.actions != null && widget.actions!.isNotEmpty) {
|
if (widget.actions != null && widget.actions.isNotEmpty) {
|
||||||
actions = Row(
|
actions = Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: widget.actions!,
|
children: widget.actions,
|
||||||
);
|
);
|
||||||
} else if (hasEndDrawer) {
|
} else if (hasEndDrawer) {
|
||||||
actions = IconButton(
|
actions = IconButton(
|
||||||
icon: const Icon(Icons.menu),
|
icon: const Icon(Icons.menu),
|
||||||
onPressed: _handleDrawerButtonEnd,
|
onPressed: _handleDrawerButtonEnd,
|
||||||
tooltip: MaterialLocalizations.of(context)!.openAppDrawerTooltip,
|
tooltip: MaterialLocalizations.of(context).openAppDrawerTooltip,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -638,7 +641,7 @@ class _AppBarState extends State<AppBar> {
|
||||||
leading: leading,
|
leading: leading,
|
||||||
middle: title,
|
middle: title,
|
||||||
trailing: actions,
|
trailing: actions,
|
||||||
centerMiddle: widget._getEffectiveCenterTitle(theme!),
|
centerMiddle: widget._getEffectiveCenterTitle(theme),
|
||||||
middleSpacing: widget.titleSpacing,
|
middleSpacing: widget.titleSpacing,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -667,7 +670,7 @@ class _AppBarState extends State<AppBar> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (widget.bottomOpacity == 1.0)
|
if (widget.bottomOpacity == 1.0)
|
||||||
widget.bottom!
|
widget.bottom
|
||||||
else
|
else
|
||||||
Opacity(
|
Opacity(
|
||||||
opacity: const Interval(0.25, 1.0, curve: Curves.fastOutSlowIn).transform(widget.bottomOpacity),
|
opacity: const Interval(0.25, 1.0, curve: Curves.fastOutSlowIn).transform(widget.bottomOpacity),
|
||||||
|
@ -746,7 +749,7 @@ class _AppBarState extends State<AppBar> {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _FloatingAppBar extends StatefulWidget {
|
class _FloatingAppBar extends StatefulWidget {
|
||||||
const _FloatingAppBar({ Key? key, required this.child }) : super(key: key);
|
const _FloatingAppBar({ Key key, this.child }) : super(key: key);
|
||||||
|
|
||||||
final Widget child;
|
final Widget child;
|
||||||
|
|
||||||
|
@ -757,26 +760,26 @@ class _FloatingAppBar extends StatefulWidget {
|
||||||
// A wrapper for the widget created by _SliverAppBarDelegate that starts and
|
// A wrapper for the widget created by _SliverAppBarDelegate that starts and
|
||||||
// stops the floating app bar's snap-into-view or snap-out-of-view animation.
|
// stops the floating app bar's snap-into-view or snap-out-of-view animation.
|
||||||
class _FloatingAppBarState extends State<_FloatingAppBar> {
|
class _FloatingAppBarState extends State<_FloatingAppBar> {
|
||||||
ScrollPosition? _position;
|
ScrollPosition _position;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void didChangeDependencies() {
|
void didChangeDependencies() {
|
||||||
super.didChangeDependencies();
|
super.didChangeDependencies();
|
||||||
if (_position != null)
|
if (_position != null)
|
||||||
_position!.isScrollingNotifier.removeListener(_isScrollingListener);
|
_position.isScrollingNotifier.removeListener(_isScrollingListener);
|
||||||
_position = Scrollable.of(context)?.position;
|
_position = Scrollable.of(context)?.position;
|
||||||
if (_position != null)
|
if (_position != null)
|
||||||
_position!.isScrollingNotifier.addListener(_isScrollingListener);
|
_position.isScrollingNotifier.addListener(_isScrollingListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
if (_position != null)
|
if (_position != null)
|
||||||
_position!.isScrollingNotifier.removeListener(_isScrollingListener);
|
_position.isScrollingNotifier.removeListener(_isScrollingListener);
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderSliverFloatingPersistentHeader? _headerRenderer() {
|
RenderSliverFloatingPersistentHeader _headerRenderer() {
|
||||||
return context.findAncestorRenderObjectOfType<RenderSliverFloatingPersistentHeader>();
|
return context.findAncestorRenderObjectOfType<RenderSliverFloatingPersistentHeader>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -786,11 +789,11 @@ class _FloatingAppBarState extends State<_FloatingAppBar> {
|
||||||
|
|
||||||
// When a scroll stops, then maybe snap the appbar into view.
|
// When a scroll stops, then maybe snap the appbar into view.
|
||||||
// Similarly, when a scroll starts, then maybe stop the snap animation.
|
// Similarly, when a scroll starts, then maybe stop the snap animation.
|
||||||
final RenderSliverFloatingPersistentHeader? header = _headerRenderer();
|
final RenderSliverFloatingPersistentHeader header = _headerRenderer();
|
||||||
if (_position!.isScrollingNotifier.value)
|
if (_position.isScrollingNotifier.value)
|
||||||
header?.maybeStopSnapAnimation(_position!.userScrollDirection);
|
header?.maybeStopSnapAnimation(_position.userScrollDirection);
|
||||||
else
|
else
|
||||||
header?.maybeStartSnapAnimation(_position!.userScrollDirection);
|
header?.maybeStartSnapAnimation(_position.userScrollDirection);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -799,69 +802,69 @@ class _FloatingAppBarState extends State<_FloatingAppBar> {
|
||||||
|
|
||||||
class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
|
class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
|
||||||
_SliverAppBarDelegate({
|
_SliverAppBarDelegate({
|
||||||
required this.leading,
|
@required this.leading,
|
||||||
required this.automaticallyImplyLeading,
|
@required this.automaticallyImplyLeading,
|
||||||
required this.title,
|
@required this.title,
|
||||||
required this.actions,
|
@required this.actions,
|
||||||
required this.flexibleSpace,
|
@required this.flexibleSpace,
|
||||||
required this.bottom,
|
@required this.bottom,
|
||||||
required this.elevation,
|
@required this.elevation,
|
||||||
required this.shadowColor,
|
@required this.shadowColor,
|
||||||
required this.forceElevated,
|
@required this.forceElevated,
|
||||||
required this.backgroundColor,
|
@required this.backgroundColor,
|
||||||
required this.brightness,
|
@required this.brightness,
|
||||||
required this.iconTheme,
|
@required this.iconTheme,
|
||||||
required this.actionsIconTheme,
|
@required this.actionsIconTheme,
|
||||||
required this.textTheme,
|
@required this.textTheme,
|
||||||
required this.primary,
|
@required this.primary,
|
||||||
required this.centerTitle,
|
@required this.centerTitle,
|
||||||
required this.excludeHeaderSemantics,
|
@required this.excludeHeaderSemantics,
|
||||||
required this.titleSpacing,
|
@required this.titleSpacing,
|
||||||
required this.expandedHeight,
|
@required this.expandedHeight,
|
||||||
required this.collapsedHeight,
|
@required this.collapsedHeight,
|
||||||
required this.topPadding,
|
@required this.topPadding,
|
||||||
required this.floating,
|
@required this.floating,
|
||||||
required this.pinned,
|
@required this.pinned,
|
||||||
required this.vsync,
|
@required this.vsync,
|
||||||
required this.snapConfiguration,
|
@required this.snapConfiguration,
|
||||||
required this.stretchConfiguration,
|
@required this.stretchConfiguration,
|
||||||
required this.showOnScreenConfiguration,
|
@required this.showOnScreenConfiguration,
|
||||||
required this.shape,
|
@required this.shape,
|
||||||
required this.toolbarHeight,
|
@required this.toolbarHeight,
|
||||||
required this.leadingWidth,
|
@required this.leadingWidth,
|
||||||
}) : assert(primary || topPadding == 0.0),
|
}) : assert(primary || topPadding == 0.0),
|
||||||
assert(
|
assert(
|
||||||
!floating || (snapConfiguration == null && showOnScreenConfiguration == null) || vsync != null,
|
!floating || (snapConfiguration == null && showOnScreenConfiguration == null) || vsync != null,
|
||||||
'vsync cannot be null when snapConfiguration or showOnScreenConfiguration is not null, and floating is true',
|
'vsync cannot be null when snapConfiguration or showOnScreenConfiguration is not null, and floating is true',
|
||||||
),
|
),
|
||||||
_bottomHeight = bottom?.preferredSize.height ?? 0.0;
|
_bottomHeight = bottom?.preferredSize?.height ?? 0.0;
|
||||||
|
|
||||||
final Widget? leading;
|
final Widget leading;
|
||||||
final bool automaticallyImplyLeading;
|
final bool automaticallyImplyLeading;
|
||||||
final Widget? title;
|
final Widget title;
|
||||||
final List<Widget>? actions;
|
final List<Widget> actions;
|
||||||
final Widget? flexibleSpace;
|
final Widget flexibleSpace;
|
||||||
final PreferredSizeWidget? bottom;
|
final PreferredSizeWidget bottom;
|
||||||
final double? elevation;
|
final double elevation;
|
||||||
final Color? shadowColor;
|
final Color shadowColor;
|
||||||
final bool forceElevated;
|
final bool forceElevated;
|
||||||
final Color? backgroundColor;
|
final Color backgroundColor;
|
||||||
final Brightness? brightness;
|
final Brightness brightness;
|
||||||
final IconThemeData? iconTheme;
|
final IconThemeData iconTheme;
|
||||||
final IconThemeData? actionsIconTheme;
|
final IconThemeData actionsIconTheme;
|
||||||
final TextTheme? textTheme;
|
final TextTheme textTheme;
|
||||||
final bool primary;
|
final bool primary;
|
||||||
final bool? centerTitle;
|
final bool centerTitle;
|
||||||
final bool excludeHeaderSemantics;
|
final bool excludeHeaderSemantics;
|
||||||
final double titleSpacing;
|
final double titleSpacing;
|
||||||
final double? expandedHeight;
|
final double expandedHeight;
|
||||||
final double collapsedHeight;
|
final double collapsedHeight;
|
||||||
final double topPadding;
|
final double topPadding;
|
||||||
final bool floating;
|
final bool floating;
|
||||||
final bool pinned;
|
final bool pinned;
|
||||||
final ShapeBorder? shape;
|
final ShapeBorder shape;
|
||||||
final double? toolbarHeight;
|
final double toolbarHeight;
|
||||||
final double? leadingWidth;
|
final double leadingWidth;
|
||||||
|
|
||||||
final double _bottomHeight;
|
final double _bottomHeight;
|
||||||
|
|
||||||
|
@ -875,13 +878,13 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
|
||||||
final TickerProvider vsync;
|
final TickerProvider vsync;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final FloatingHeaderSnapConfiguration? snapConfiguration;
|
final FloatingHeaderSnapConfiguration snapConfiguration;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final OverScrollHeaderStretchConfiguration? stretchConfiguration;
|
final OverScrollHeaderStretchConfiguration stretchConfiguration;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final PersistentHeaderShowOnScreenConfiguration? showOnScreenConfiguration;
|
final PersistentHeaderShowOnScreenConfiguration showOnScreenConfiguration;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
|
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
|
||||||
|
@ -891,7 +894,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
|
||||||
|
|
||||||
final bool isPinnedWithOpacityFade = pinned && floating && bottom != null && extraToolbarHeight == 0.0;
|
final bool isPinnedWithOpacityFade = pinned && floating && bottom != null && extraToolbarHeight == 0.0;
|
||||||
final double toolbarOpacity = !pinned || isPinnedWithOpacityFade
|
final double toolbarOpacity = !pinned || isPinnedWithOpacityFade
|
||||||
? (visibleToolbarHeight / (toolbarHeight ?? kToolbarHeight)).clamp(0.0, 1.0)
|
? (visibleToolbarHeight / (toolbarHeight ?? kToolbarHeight)).clamp(0.0, 1.0) as double
|
||||||
: 1.0;
|
: 1.0;
|
||||||
|
|
||||||
final Widget appBar = FlexibleSpaceBar.createSettings(
|
final Widget appBar = FlexibleSpaceBar.createSettings(
|
||||||
|
@ -921,7 +924,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
|
||||||
titleSpacing: titleSpacing,
|
titleSpacing: titleSpacing,
|
||||||
shape: shape,
|
shape: shape,
|
||||||
toolbarOpacity: toolbarOpacity,
|
toolbarOpacity: toolbarOpacity,
|
||||||
bottomOpacity: pinned ? 1.0 : ((visibleMainHeight / _bottomHeight).clamp(0.0, 1.0)),
|
bottomOpacity: pinned ? 1.0 : ((visibleMainHeight / _bottomHeight).clamp(0.0, 1.0) as double),
|
||||||
toolbarHeight: toolbarHeight,
|
toolbarHeight: toolbarHeight,
|
||||||
leadingWidth: leadingWidth,
|
leadingWidth: leadingWidth,
|
||||||
),
|
),
|
||||||
|
@ -1051,7 +1054,7 @@ class SliverAppBar extends StatefulWidget {
|
||||||
/// The arguments [forceElevated], [primary], [floating], [pinned], [snap]
|
/// The arguments [forceElevated], [primary], [floating], [pinned], [snap]
|
||||||
/// and [automaticallyImplyLeading] must not be null.
|
/// and [automaticallyImplyLeading] must not be null.
|
||||||
const SliverAppBar({
|
const SliverAppBar({
|
||||||
Key? key,
|
Key key,
|
||||||
this.leading,
|
this.leading,
|
||||||
this.automaticallyImplyLeading = true,
|
this.automaticallyImplyLeading = true,
|
||||||
this.title,
|
this.title,
|
||||||
|
@ -1103,7 +1106,7 @@ class SliverAppBar extends StatefulWidget {
|
||||||
/// [IconButton] that opens the drawer. If there's no [Drawer] and the parent
|
/// [IconButton] that opens the drawer. If there's no [Drawer] and the parent
|
||||||
/// [Navigator] can go back, the [AppBar] will use a [BackButton] that calls
|
/// [Navigator] can go back, the [AppBar] will use a [BackButton] that calls
|
||||||
/// [Navigator.maybePop].
|
/// [Navigator.maybePop].
|
||||||
final Widget? leading;
|
final Widget leading;
|
||||||
|
|
||||||
/// Controls whether we should try to imply the leading widget if null.
|
/// Controls whether we should try to imply the leading widget if null.
|
||||||
///
|
///
|
||||||
|
@ -1116,7 +1119,7 @@ class SliverAppBar extends StatefulWidget {
|
||||||
///
|
///
|
||||||
/// Typically a [Text] widget containing a description of the current contents
|
/// Typically a [Text] widget containing a description of the current contents
|
||||||
/// of the app.
|
/// of the app.
|
||||||
final Widget? title;
|
final Widget title;
|
||||||
|
|
||||||
/// Widgets to display after the [title] widget.
|
/// Widgets to display after the [title] widget.
|
||||||
///
|
///
|
||||||
|
@ -1149,7 +1152,7 @@ class SliverAppBar extends StatefulWidget {
|
||||||
/// )
|
/// )
|
||||||
/// ```
|
/// ```
|
||||||
/// {@end-tool}
|
/// {@end-tool}
|
||||||
final List<Widget>? actions;
|
final List<Widget> actions;
|
||||||
|
|
||||||
/// This widget is stacked behind the toolbar and the tab bar. It's height will
|
/// This widget is stacked behind the toolbar and the tab bar. It's height will
|
||||||
/// be the same as the app bar's overall height.
|
/// be the same as the app bar's overall height.
|
||||||
|
@ -1158,7 +1161,7 @@ class SliverAppBar extends StatefulWidget {
|
||||||
/// must be large enough to accommodate the [SliverAppBar.flexibleSpace] widget.
|
/// must be large enough to accommodate the [SliverAppBar.flexibleSpace] widget.
|
||||||
///
|
///
|
||||||
/// Typically a [FlexibleSpaceBar]. See [FlexibleSpaceBar] for details.
|
/// Typically a [FlexibleSpaceBar]. See [FlexibleSpaceBar] for details.
|
||||||
final Widget? flexibleSpace;
|
final Widget flexibleSpace;
|
||||||
|
|
||||||
/// This widget appears across the bottom of the app bar.
|
/// This widget appears across the bottom of the app bar.
|
||||||
///
|
///
|
||||||
|
@ -1168,7 +1171,7 @@ class SliverAppBar extends StatefulWidget {
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [PreferredSize], which can be used to give an arbitrary widget a preferred size.
|
/// * [PreferredSize], which can be used to give an arbitrary widget a preferred size.
|
||||||
final PreferredSizeWidget? bottom;
|
final PreferredSizeWidget bottom;
|
||||||
|
|
||||||
/// The z-coordinate at which to place this app bar when it is above other
|
/// The z-coordinate at which to place this app bar when it is above other
|
||||||
/// content. This controls the size of the shadow below the app bar.
|
/// content. This controls the size of the shadow below the app bar.
|
||||||
|
@ -1181,7 +1184,7 @@ class SliverAppBar extends StatefulWidget {
|
||||||
/// no content underneath it. For example, if the app bar is [pinned] but no
|
/// no content underneath it. For example, if the app bar is [pinned] but no
|
||||||
/// content is scrolled under it, or if it scrolls with the content, then no
|
/// content is scrolled under it, or if it scrolls with the content, then no
|
||||||
/// shadow is drawn, regardless of the value of [elevation].
|
/// shadow is drawn, regardless of the value of [elevation].
|
||||||
final double? elevation;
|
final double elevation;
|
||||||
|
|
||||||
/// The color to paint the shadow below the app bar. Typically this should be set
|
/// The color to paint the shadow below the app bar. Typically this should be set
|
||||||
/// along with [elevation].
|
/// along with [elevation].
|
||||||
|
@ -1189,7 +1192,7 @@ class SliverAppBar extends StatefulWidget {
|
||||||
/// If this property is null, then [AppBarTheme.shadowColor] of
|
/// If this property is null, then [AppBarTheme.shadowColor] of
|
||||||
/// [ThemeData.appBarTheme] is used, if that is also null, the default value
|
/// [ThemeData.appBarTheme] is used, if that is also null, the default value
|
||||||
/// is fully opaque black.
|
/// is fully opaque black.
|
||||||
final Color? shadowColor;
|
final Color shadowColor;
|
||||||
|
|
||||||
/// Whether to show the shadow appropriate for the [elevation] even if the
|
/// Whether to show the shadow appropriate for the [elevation] even if the
|
||||||
/// content is not scrolled under the [AppBar].
|
/// content is not scrolled under the [AppBar].
|
||||||
|
@ -1208,7 +1211,7 @@ class SliverAppBar extends StatefulWidget {
|
||||||
/// If this property is null, then [AppBarTheme.color] of
|
/// If this property is null, then [AppBarTheme.color] of
|
||||||
/// [ThemeData.appBarTheme] is used. If that is also null, then
|
/// [ThemeData.appBarTheme] is used. If that is also null, then
|
||||||
/// [ThemeData.primaryColor] is used.
|
/// [ThemeData.primaryColor] is used.
|
||||||
final Color? backgroundColor;
|
final Color backgroundColor;
|
||||||
|
|
||||||
/// The brightness of the app bar's material. Typically this is set along
|
/// The brightness of the app bar's material. Typically this is set along
|
||||||
/// with [backgroundColor], [iconTheme], [textTheme].
|
/// with [backgroundColor], [iconTheme], [textTheme].
|
||||||
|
@ -1216,7 +1219,7 @@ class SliverAppBar extends StatefulWidget {
|
||||||
/// If this property is null, then [AppBarTheme.brightness] of
|
/// If this property is null, then [AppBarTheme.brightness] of
|
||||||
/// [ThemeData.appBarTheme] is used. If that is also null, then
|
/// [ThemeData.appBarTheme] is used. If that is also null, then
|
||||||
/// [ThemeData.primaryColorBrightness] is used.
|
/// [ThemeData.primaryColorBrightness] is used.
|
||||||
final Brightness? brightness;
|
final Brightness brightness;
|
||||||
|
|
||||||
/// The color, opacity, and size to use for app bar icons. Typically this
|
/// The color, opacity, and size to use for app bar icons. Typically this
|
||||||
/// is set along with [backgroundColor], [brightness], [textTheme].
|
/// is set along with [backgroundColor], [brightness], [textTheme].
|
||||||
|
@ -1224,7 +1227,7 @@ class SliverAppBar extends StatefulWidget {
|
||||||
/// If this property is null, then [AppBarTheme.iconTheme] of
|
/// If this property is null, then [AppBarTheme.iconTheme] of
|
||||||
/// [ThemeData.appBarTheme] is used, if that is also null, then
|
/// [ThemeData.appBarTheme] is used, if that is also null, then
|
||||||
/// [ThemeData.primaryIconTheme] is used.
|
/// [ThemeData.primaryIconTheme] is used.
|
||||||
final IconThemeData? iconTheme;
|
final IconThemeData iconTheme;
|
||||||
|
|
||||||
/// The color, opacity, and size to use for trailing app bar icons. This
|
/// The color, opacity, and size to use for trailing app bar icons. This
|
||||||
/// should only be used when the trailing icons should be themed differently
|
/// should only be used when the trailing icons should be themed differently
|
||||||
|
@ -1233,7 +1236,7 @@ class SliverAppBar extends StatefulWidget {
|
||||||
/// If this property is null, then [AppBarTheme.actionsIconTheme] of
|
/// If this property is null, then [AppBarTheme.actionsIconTheme] of
|
||||||
/// [ThemeData.appBarTheme] is used, if that is also null, then this falls
|
/// [ThemeData.appBarTheme] is used, if that is also null, then this falls
|
||||||
/// back to [iconTheme].
|
/// back to [iconTheme].
|
||||||
final IconThemeData? actionsIconTheme;
|
final IconThemeData actionsIconTheme;
|
||||||
|
|
||||||
/// The typographic styles to use for text in the app bar. Typically this is
|
/// The typographic styles to use for text in the app bar. Typically this is
|
||||||
/// set along with [brightness] [backgroundColor], [iconTheme].
|
/// set along with [brightness] [backgroundColor], [iconTheme].
|
||||||
|
@ -1241,7 +1244,7 @@ class SliverAppBar extends StatefulWidget {
|
||||||
/// If this property is null, then [AppBarTheme.textTheme] of
|
/// If this property is null, then [AppBarTheme.textTheme] of
|
||||||
/// [ThemeData.appBarTheme] is used, if that is also null, then
|
/// [ThemeData.appBarTheme] is used, if that is also null, then
|
||||||
/// [ThemeData.primaryTextTheme] is used.
|
/// [ThemeData.primaryTextTheme] is used.
|
||||||
final TextTheme? textTheme;
|
final TextTheme textTheme;
|
||||||
|
|
||||||
/// Whether this app bar is being displayed at the top of the screen.
|
/// Whether this app bar is being displayed at the top of the screen.
|
||||||
///
|
///
|
||||||
|
@ -1252,7 +1255,7 @@ class SliverAppBar extends StatefulWidget {
|
||||||
/// Whether the title should be centered.
|
/// Whether the title should be centered.
|
||||||
///
|
///
|
||||||
/// Defaults to being adapted to the current [TargetPlatform].
|
/// Defaults to being adapted to the current [TargetPlatform].
|
||||||
final bool? centerTitle;
|
final bool centerTitle;
|
||||||
|
|
||||||
/// Whether the title should be wrapped with header [Semantics].
|
/// Whether the title should be wrapped with header [Semantics].
|
||||||
///
|
///
|
||||||
|
@ -1276,7 +1279,7 @@ class SliverAppBar extends StatefulWidget {
|
||||||
/// If [pinned] and [floating] are true, with [bottom] set, the default
|
/// If [pinned] and [floating] are true, with [bottom] set, the default
|
||||||
/// collapsed height is only the height of [PreferredSizeWidget.preferredSize]
|
/// collapsed height is only the height of [PreferredSizeWidget.preferredSize]
|
||||||
/// with the [MediaQuery] top padding.
|
/// with the [MediaQuery] top padding.
|
||||||
final double? collapsedHeight;
|
final double collapsedHeight;
|
||||||
|
|
||||||
/// The size of the app bar when it is fully expanded.
|
/// The size of the app bar when it is fully expanded.
|
||||||
///
|
///
|
||||||
|
@ -1286,7 +1289,7 @@ class SliverAppBar extends StatefulWidget {
|
||||||
///
|
///
|
||||||
/// This does not include the status bar height (which will be automatically
|
/// This does not include the status bar height (which will be automatically
|
||||||
/// included if [primary] is true).
|
/// included if [primary] is true).
|
||||||
final double? expandedHeight;
|
final double expandedHeight;
|
||||||
|
|
||||||
/// Whether the app bar should become visible as soon as the user scrolls
|
/// Whether the app bar should become visible as soon as the user scrolls
|
||||||
/// towards the app bar.
|
/// towards the app bar.
|
||||||
|
@ -1338,7 +1341,7 @@ class SliverAppBar extends StatefulWidget {
|
||||||
/// The material's shape as well as its shadow.
|
/// The material's shape as well as its shadow.
|
||||||
///
|
///
|
||||||
/// A shadow is only displayed if the [elevation] is greater than zero.
|
/// A shadow is only displayed if the [elevation] is greater than zero.
|
||||||
final ShapeBorder? shape;
|
final ShapeBorder shape;
|
||||||
|
|
||||||
/// If [snap] and [floating] are true then the floating app bar will "snap"
|
/// If [snap] and [floating] are true then the floating app bar will "snap"
|
||||||
/// into view.
|
/// into view.
|
||||||
|
@ -1385,7 +1388,7 @@ class SliverAppBar extends StatefulWidget {
|
||||||
|
|
||||||
/// The callback function to be executed when a user over-scrolls to the
|
/// The callback function to be executed when a user over-scrolls to the
|
||||||
/// offset specified by [stretchTriggerOffset].
|
/// offset specified by [stretchTriggerOffset].
|
||||||
final AsyncCallback? onStretchTrigger;
|
final AsyncCallback onStretchTrigger;
|
||||||
|
|
||||||
/// Defines the height of the toolbar component of an [AppBar].
|
/// Defines the height of the toolbar component of an [AppBar].
|
||||||
///
|
///
|
||||||
|
@ -1395,7 +1398,7 @@ class SliverAppBar extends StatefulWidget {
|
||||||
/// Defines the width of [leading] widget.
|
/// Defines the width of [leading] widget.
|
||||||
///
|
///
|
||||||
/// By default, the value of `leadingWidth` is 56.0.
|
/// By default, the value of `leadingWidth` is 56.0.
|
||||||
final double? leadingWidth;
|
final double leadingWidth;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_SliverAppBarState createState() => _SliverAppBarState();
|
_SliverAppBarState createState() => _SliverAppBarState();
|
||||||
|
@ -1404,9 +1407,9 @@ class SliverAppBar extends StatefulWidget {
|
||||||
// This class is only Stateful because it owns the TickerProvider used
|
// This class is only Stateful because it owns the TickerProvider used
|
||||||
// by the floating appbar snap animation (via FloatingHeaderSnapConfiguration).
|
// by the floating appbar snap animation (via FloatingHeaderSnapConfiguration).
|
||||||
class _SliverAppBarState extends State<SliverAppBar> with TickerProviderStateMixin {
|
class _SliverAppBarState extends State<SliverAppBar> with TickerProviderStateMixin {
|
||||||
FloatingHeaderSnapConfiguration? _snapConfiguration;
|
FloatingHeaderSnapConfiguration _snapConfiguration;
|
||||||
OverScrollHeaderStretchConfiguration? _stretchConfiguration;
|
OverScrollHeaderStretchConfiguration _stretchConfiguration;
|
||||||
PersistentHeaderShowOnScreenConfiguration? _showOnScreenConfiguration;
|
PersistentHeaderShowOnScreenConfiguration _showOnScreenConfiguration;
|
||||||
|
|
||||||
void _updateSnapConfiguration() {
|
void _updateSnapConfiguration() {
|
||||||
if (widget.snap && widget.floating) {
|
if (widget.snap && widget.floating) {
|
||||||
|
@ -1453,8 +1456,8 @@ class _SliverAppBarState extends State<SliverAppBar> with TickerProviderStateMix
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
assert(!widget.primary || debugCheckHasMediaQuery(context));
|
assert(!widget.primary || debugCheckHasMediaQuery(context));
|
||||||
final double bottomHeight = widget.bottom?.preferredSize.height ?? 0.0;
|
final double bottomHeight = widget.bottom?.preferredSize?.height ?? 0.0;
|
||||||
final double topPadding = widget.primary ? MediaQuery.of(context)!.padding.top : 0.0;
|
final double topPadding = widget.primary ? MediaQuery.of(context).padding.top : 0.0;
|
||||||
final double collapsedHeight = (widget.pinned && widget.floating && widget.bottom != null)
|
final double collapsedHeight = (widget.pinned && widget.floating && widget.bottom != null)
|
||||||
? (widget.collapsedHeight ?? 0.0) + bottomHeight + topPadding
|
? (widget.collapsedHeight ?? 0.0) + bottomHeight + topPadding
|
||||||
: (widget.collapsedHeight ?? widget.toolbarHeight) + bottomHeight + topPadding;
|
: (widget.collapsedHeight ?? widget.toolbarHeight) + bottomHeight + topPadding;
|
||||||
|
@ -1506,7 +1509,7 @@ class _SliverAppBarState extends State<SliverAppBar> with TickerProviderStateMix
|
||||||
// center it within its (NavigationToolbar) parent, and allow the
|
// center it within its (NavigationToolbar) parent, and allow the
|
||||||
// parent to constrain the title's actual height.
|
// parent to constrain the title's actual height.
|
||||||
class _AppBarTitleBox extends SingleChildRenderObjectWidget {
|
class _AppBarTitleBox extends SingleChildRenderObjectWidget {
|
||||||
const _AppBarTitleBox({ Key? key, required Widget child }) : assert(child != null), super(key: key, child: child);
|
const _AppBarTitleBox({ Key key, @required Widget child }) : assert(child != null), super(key: key, child: child);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_RenderAppBarTitleBox createRenderObject(BuildContext context) {
|
_RenderAppBarTitleBox createRenderObject(BuildContext context) {
|
||||||
|
@ -1523,15 +1526,16 @@ class _AppBarTitleBox extends SingleChildRenderObjectWidget {
|
||||||
|
|
||||||
class _RenderAppBarTitleBox extends RenderAligningShiftedBox {
|
class _RenderAppBarTitleBox extends RenderAligningShiftedBox {
|
||||||
_RenderAppBarTitleBox({
|
_RenderAppBarTitleBox({
|
||||||
RenderBox? child,
|
RenderBox child,
|
||||||
TextDirection? textDirection,
|
TextDirection textDirection,
|
||||||
}) : super(child: child, alignment: Alignment.center, textDirection: textDirection);
|
}) : super(child: child, alignment: Alignment.center, textDirection: textDirection);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void performLayout() {
|
void performLayout() {
|
||||||
|
final BoxConstraints constraints = this.constraints;
|
||||||
final BoxConstraints innerConstraints = constraints.copyWith(maxHeight: double.infinity);
|
final BoxConstraints innerConstraints = constraints.copyWith(maxHeight: double.infinity);
|
||||||
child!.layout(innerConstraints, parentUsesSize: true);
|
child.layout(innerConstraints, parentUsesSize: true);
|
||||||
size = constraints.constrain(child!.size);
|
size = constraints.constrain(child.size);
|
||||||
alignChild();
|
alignChild();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
// @dart = 2.8
|
||||||
|
|
||||||
import 'dart:ui' show lerpDouble;
|
import 'dart:ui' show lerpDouble;
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
@ -44,54 +46,54 @@ class AppBarTheme with Diagnosticable {
|
||||||
/// Default value for [AppBar.brightness].
|
/// Default value for [AppBar.brightness].
|
||||||
///
|
///
|
||||||
/// If null, [AppBar] uses [ThemeData.primaryColorBrightness].
|
/// If null, [AppBar] uses [ThemeData.primaryColorBrightness].
|
||||||
final Brightness? brightness;
|
final Brightness brightness;
|
||||||
|
|
||||||
/// Default value for [AppBar.backgroundColor].
|
/// Default value for [AppBar.backgroundColor].
|
||||||
///
|
///
|
||||||
/// If null, [AppBar] uses [ThemeData.primaryColor].
|
/// If null, [AppBar] uses [ThemeData.primaryColor].
|
||||||
final Color? color;
|
final Color color;
|
||||||
|
|
||||||
/// Default value for [AppBar.elevation].
|
/// Default value for [AppBar.elevation].
|
||||||
///
|
///
|
||||||
/// If null, [AppBar] uses a default value of 4.0.
|
/// If null, [AppBar] uses a default value of 4.0.
|
||||||
final double? elevation;
|
final double elevation;
|
||||||
|
|
||||||
/// Default value for [AppBar.shadowColor].
|
/// Default value for [AppBar.shadowColor].
|
||||||
///
|
///
|
||||||
/// If null, [AppBar] uses a default value of fully opaque black.
|
/// If null, [AppBar] uses a default value of fully opaque black.
|
||||||
final Color? shadowColor;
|
final Color shadowColor;
|
||||||
|
|
||||||
/// Default value for [AppBar.iconTheme].
|
/// Default value for [AppBar.iconTheme].
|
||||||
///
|
///
|
||||||
/// If null, [AppBar] uses [ThemeData.primaryIconTheme].
|
/// If null, [AppBar] uses [ThemeData.primaryIconTheme].
|
||||||
final IconThemeData? iconTheme;
|
final IconThemeData iconTheme;
|
||||||
|
|
||||||
/// Default value for [AppBar.actionsIconTheme].
|
/// Default value for [AppBar.actionsIconTheme].
|
||||||
///
|
///
|
||||||
/// If null, [AppBar] uses [ThemeData.primaryIconTheme].
|
/// If null, [AppBar] uses [ThemeData.primaryIconTheme].
|
||||||
final IconThemeData? actionsIconTheme;
|
final IconThemeData actionsIconTheme;
|
||||||
|
|
||||||
/// Default value for [AppBar.textTheme].
|
/// Default value for [AppBar.textTheme].
|
||||||
///
|
///
|
||||||
/// If null, [AppBar] uses [ThemeData.primaryTextTheme].
|
/// If null, [AppBar] uses [ThemeData.primaryTextTheme].
|
||||||
final TextTheme? textTheme;
|
final TextTheme textTheme;
|
||||||
|
|
||||||
/// Default value for [AppBar.centerTitle].
|
/// Default value for [AppBar.centerTitle].
|
||||||
///
|
///
|
||||||
/// If null, the value is adapted to current [TargetPlatform].
|
/// If null, the value is adapted to current [TargetPlatform].
|
||||||
final bool? centerTitle;
|
final bool centerTitle;
|
||||||
|
|
||||||
/// Creates a copy of this object with the given fields replaced with the
|
/// Creates a copy of this object with the given fields replaced with the
|
||||||
/// new values.
|
/// new values.
|
||||||
AppBarTheme copyWith({
|
AppBarTheme copyWith({
|
||||||
IconThemeData? actionsIconTheme,
|
IconThemeData actionsIconTheme,
|
||||||
Brightness? brightness,
|
Brightness brightness,
|
||||||
Color? color,
|
Color color,
|
||||||
double? elevation,
|
double elevation,
|
||||||
Color? shadowColor,
|
Color shadowColor,
|
||||||
IconThemeData? iconTheme,
|
IconThemeData iconTheme,
|
||||||
TextTheme? textTheme,
|
TextTheme textTheme,
|
||||||
bool? centerTitle,
|
bool centerTitle,
|
||||||
}) {
|
}) {
|
||||||
return AppBarTheme(
|
return AppBarTheme(
|
||||||
brightness: brightness ?? this.brightness,
|
brightness: brightness ?? this.brightness,
|
||||||
|
@ -107,7 +109,7 @@ class AppBarTheme with Diagnosticable {
|
||||||
|
|
||||||
/// The [ThemeData.appBarTheme] property of the ambient [Theme].
|
/// The [ThemeData.appBarTheme] property of the ambient [Theme].
|
||||||
static AppBarTheme of(BuildContext context) {
|
static AppBarTheme of(BuildContext context) {
|
||||||
return Theme.of(context)!.appBarTheme;
|
return Theme.of(context).appBarTheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Linearly interpolate between two AppBar themes.
|
/// Linearly interpolate between two AppBar themes.
|
||||||
|
@ -115,7 +117,7 @@ class AppBarTheme with Diagnosticable {
|
||||||
/// The argument `t` must not be null.
|
/// The argument `t` must not be null.
|
||||||
///
|
///
|
||||||
/// {@macro dart.ui.shadow.lerp}
|
/// {@macro dart.ui.shadow.lerp}
|
||||||
static AppBarTheme lerp(AppBarTheme? a, AppBarTheme? b, double t) {
|
static AppBarTheme lerp(AppBarTheme a, AppBarTheme b, double t) {
|
||||||
assert(t != null);
|
assert(t != null);
|
||||||
return AppBarTheme(
|
return AppBarTheme(
|
||||||
brightness: t < 0.5 ? a?.brightness : b?.brightness,
|
brightness: t < 0.5 ? a?.brightness : b?.brightness,
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
// @dart = 2.8
|
||||||
|
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
import 'debug.dart';
|
import 'debug.dart';
|
||||||
|
@ -25,7 +27,7 @@ import 'theme.dart';
|
||||||
class BackButtonIcon extends StatelessWidget {
|
class BackButtonIcon extends StatelessWidget {
|
||||||
/// Creates an icon that shows the appropriate "back" image for
|
/// Creates an icon that shows the appropriate "back" image for
|
||||||
/// the current platform (as obtained from the [Theme]).
|
/// the current platform (as obtained from the [Theme]).
|
||||||
const BackButtonIcon({ Key? key }) : super(key: key);
|
const BackButtonIcon({ Key key }) : super(key: key);
|
||||||
|
|
||||||
/// Returns the appropriate "back" icon for the given `platform`.
|
/// Returns the appropriate "back" icon for the given `platform`.
|
||||||
static IconData _getIconData(TargetPlatform platform) {
|
static IconData _getIconData(TargetPlatform platform) {
|
||||||
|
@ -39,10 +41,12 @@ class BackButtonIcon extends StatelessWidget {
|
||||||
case TargetPlatform.macOS:
|
case TargetPlatform.macOS:
|
||||||
return Icons.arrow_back_ios;
|
return Icons.arrow_back_ios;
|
||||||
}
|
}
|
||||||
|
assert(false);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => Icon(_getIconData(Theme.of(context)!.platform));
|
Widget build(BuildContext context) => Icon(_getIconData(Theme.of(context).platform));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A material design back button.
|
/// A material design back button.
|
||||||
|
@ -74,13 +78,13 @@ class BackButtonIcon extends StatelessWidget {
|
||||||
class BackButton extends StatelessWidget {
|
class BackButton extends StatelessWidget {
|
||||||
/// Creates an [IconButton] with the appropriate "back" icon for the current
|
/// Creates an [IconButton] with the appropriate "back" icon for the current
|
||||||
/// target platform.
|
/// target platform.
|
||||||
const BackButton({ Key? key, this.color, this.onPressed }) : super(key: key);
|
const BackButton({ Key key, this.color, this.onPressed }) : super(key: key);
|
||||||
|
|
||||||
/// The color to use for the icon.
|
/// The color to use for the icon.
|
||||||
///
|
///
|
||||||
/// Defaults to the [IconThemeData.color] specified in the ambient [IconTheme],
|
/// Defaults to the [IconThemeData.color] specified in the ambient [IconTheme],
|
||||||
/// which usually matches the ambient [Theme]'s [ThemeData.iconTheme].
|
/// which usually matches the ambient [Theme]'s [ThemeData.iconTheme].
|
||||||
final Color? color;
|
final Color color;
|
||||||
|
|
||||||
/// An override callback to perform instead of the default behavior which is
|
/// An override callback to perform instead of the default behavior which is
|
||||||
/// to pop the [Navigator].
|
/// to pop the [Navigator].
|
||||||
|
@ -90,7 +94,7 @@ class BackButton extends StatelessWidget {
|
||||||
/// situations.
|
/// situations.
|
||||||
///
|
///
|
||||||
/// Defaults to null.
|
/// Defaults to null.
|
||||||
final VoidCallback? onPressed;
|
final VoidCallback onPressed;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -98,10 +102,10 @@ class BackButton extends StatelessWidget {
|
||||||
return IconButton(
|
return IconButton(
|
||||||
icon: const BackButtonIcon(),
|
icon: const BackButtonIcon(),
|
||||||
color: color,
|
color: color,
|
||||||
tooltip: MaterialLocalizations.of(context)!.backButtonTooltip,
|
tooltip: MaterialLocalizations.of(context).backButtonTooltip,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (onPressed != null) {
|
if (onPressed != null) {
|
||||||
onPressed!();
|
onPressed();
|
||||||
} else {
|
} else {
|
||||||
Navigator.maybePop(context);
|
Navigator.maybePop(context);
|
||||||
}
|
}
|
||||||
|
@ -128,13 +132,13 @@ class BackButton extends StatelessWidget {
|
||||||
/// * [IconButton], to create other material design icon buttons.
|
/// * [IconButton], to create other material design icon buttons.
|
||||||
class CloseButton extends StatelessWidget {
|
class CloseButton extends StatelessWidget {
|
||||||
/// Creates a Material Design close button.
|
/// Creates a Material Design close button.
|
||||||
const CloseButton({ Key? key, this.color, this.onPressed }) : super(key: key);
|
const CloseButton({ Key key, this.color, this.onPressed }) : super(key: key);
|
||||||
|
|
||||||
/// The color to use for the icon.
|
/// The color to use for the icon.
|
||||||
///
|
///
|
||||||
/// Defaults to the [IconThemeData.color] specified in the ambient [IconTheme],
|
/// Defaults to the [IconThemeData.color] specified in the ambient [IconTheme],
|
||||||
/// which usually matches the ambient [Theme]'s [ThemeData.iconTheme].
|
/// which usually matches the ambient [Theme]'s [ThemeData.iconTheme].
|
||||||
final Color? color;
|
final Color color;
|
||||||
|
|
||||||
/// An override callback to perform instead of the default behavior which is
|
/// An override callback to perform instead of the default behavior which is
|
||||||
/// to pop the [Navigator].
|
/// to pop the [Navigator].
|
||||||
|
@ -144,7 +148,7 @@ class CloseButton extends StatelessWidget {
|
||||||
/// situations.
|
/// situations.
|
||||||
///
|
///
|
||||||
/// Defaults to null.
|
/// Defaults to null.
|
||||||
final VoidCallback? onPressed;
|
final VoidCallback onPressed;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -152,10 +156,10 @@ class CloseButton extends StatelessWidget {
|
||||||
return IconButton(
|
return IconButton(
|
||||||
icon: const Icon(Icons.close),
|
icon: const Icon(Icons.close),
|
||||||
color: color,
|
color: color,
|
||||||
tooltip: MaterialLocalizations.of(context)!.closeButtonTooltip,
|
tooltip: MaterialLocalizations.of(context).closeButtonTooltip,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (onPressed != null) {
|
if (onPressed != null) {
|
||||||
onPressed!();
|
onPressed();
|
||||||
} else {
|
} else {
|
||||||
Navigator.maybePop(context);
|
Navigator.maybePop(context);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
// @dart = 2.8
|
||||||
|
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
import 'banner_theme.dart';
|
import 'banner_theme.dart';
|
||||||
|
@ -33,10 +35,10 @@ class MaterialBanner extends StatelessWidget {
|
||||||
/// The [actions], [content], and [forceActionsBelow] must be non-null.
|
/// The [actions], [content], and [forceActionsBelow] must be non-null.
|
||||||
/// The [actions.length] must be greater than 0.
|
/// The [actions.length] must be greater than 0.
|
||||||
const MaterialBanner({
|
const MaterialBanner({
|
||||||
Key? key,
|
Key key,
|
||||||
required this.content,
|
@required this.content,
|
||||||
this.contentTextStyle,
|
this.contentTextStyle,
|
||||||
required this.actions,
|
@required this.actions,
|
||||||
this.leading,
|
this.leading,
|
||||||
this.backgroundColor,
|
this.backgroundColor,
|
||||||
this.padding,
|
this.padding,
|
||||||
|
@ -56,7 +58,7 @@ class MaterialBanner extends StatelessWidget {
|
||||||
///
|
///
|
||||||
/// If `null`, [MaterialBannerThemeData.contentTextStyle] is used. If that is
|
/// If `null`, [MaterialBannerThemeData.contentTextStyle] is used. If that is
|
||||||
/// also `null`, [TextTheme.bodyText2] of [ThemeData.textTheme] is used.
|
/// also `null`, [TextTheme.bodyText2] of [ThemeData.textTheme] is used.
|
||||||
final TextStyle? contentTextStyle;
|
final TextStyle contentTextStyle;
|
||||||
|
|
||||||
/// The set of actions that are displayed at the bottom or trailing side of
|
/// The set of actions that are displayed at the bottom or trailing side of
|
||||||
/// the [MaterialBanner].
|
/// the [MaterialBanner].
|
||||||
|
@ -67,13 +69,13 @@ class MaterialBanner extends StatelessWidget {
|
||||||
/// The (optional) leading widget of the [MaterialBanner].
|
/// The (optional) leading widget of the [MaterialBanner].
|
||||||
///
|
///
|
||||||
/// Typically an [Icon] widget.
|
/// Typically an [Icon] widget.
|
||||||
final Widget? leading;
|
final Widget leading;
|
||||||
|
|
||||||
/// The color of the surface of this [MaterialBanner].
|
/// The color of the surface of this [MaterialBanner].
|
||||||
///
|
///
|
||||||
/// If `null`, [MaterialBannerThemeData.backgroundColor] is used. If that is
|
/// If `null`, [MaterialBannerThemeData.backgroundColor] is used. If that is
|
||||||
/// also `null`, [ColorScheme.surface] of [ThemeData.colorScheme] is used.
|
/// also `null`, [ColorScheme.surface] of [ThemeData.colorScheme] is used.
|
||||||
final Color? backgroundColor;
|
final Color backgroundColor;
|
||||||
|
|
||||||
/// The amount of space by which to inset the [content].
|
/// The amount of space by which to inset the [content].
|
||||||
///
|
///
|
||||||
|
@ -82,12 +84,12 @@ class MaterialBanner extends StatelessWidget {
|
||||||
///
|
///
|
||||||
/// If the [actions] are trailing the [content], this defaults to
|
/// If the [actions] are trailing the [content], this defaults to
|
||||||
/// `EdgeInsetsDirectional.only(start: 16.0, top: 2.0)`.
|
/// `EdgeInsetsDirectional.only(start: 16.0, top: 2.0)`.
|
||||||
final EdgeInsetsGeometry? padding;
|
final EdgeInsetsGeometry padding;
|
||||||
|
|
||||||
/// The amount of space by which to inset the [leading] widget.
|
/// The amount of space by which to inset the [leading] widget.
|
||||||
///
|
///
|
||||||
/// This defaults to `EdgeInsetsDirectional.only(end: 16.0)`.
|
/// This defaults to `EdgeInsetsDirectional.only(end: 16.0)`.
|
||||||
final EdgeInsetsGeometry? leadingPadding;
|
final EdgeInsetsGeometry leadingPadding;
|
||||||
|
|
||||||
/// An override to force the [actions] to be below the [content] regardless of
|
/// An override to force the [actions] to be below the [content] regardless of
|
||||||
/// how many there are.
|
/// how many there are.
|
||||||
|
@ -102,7 +104,7 @@ class MaterialBanner extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
assert(actions.isNotEmpty);
|
assert(actions.isNotEmpty);
|
||||||
|
|
||||||
final ThemeData? theme = Theme.of(context);
|
final ThemeData theme = Theme.of(context);
|
||||||
final MaterialBannerThemeData bannerTheme = MaterialBannerTheme.of(context);
|
final MaterialBannerThemeData bannerTheme = MaterialBannerTheme.of(context);
|
||||||
|
|
||||||
final bool isSingleRow = actions.length == 1 && !forceActionsBelow;
|
final bool isSingleRow = actions.length == 1 && !forceActionsBelow;
|
||||||
|
@ -125,10 +127,10 @@ class MaterialBanner extends StatelessWidget {
|
||||||
|
|
||||||
final Color backgroundColor = this.backgroundColor
|
final Color backgroundColor = this.backgroundColor
|
||||||
?? bannerTheme.backgroundColor
|
?? bannerTheme.backgroundColor
|
||||||
?? theme!.colorScheme.surface;
|
?? theme.colorScheme.surface;
|
||||||
final TextStyle? textStyle = contentTextStyle
|
final TextStyle textStyle = contentTextStyle
|
||||||
?? bannerTheme.contentTextStyle
|
?? bannerTheme.contentTextStyle
|
||||||
?? theme!.textTheme.bodyText2;
|
?? theme.textTheme.bodyText2;
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
color: backgroundColor,
|
color: backgroundColor,
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
// @dart = 2.8
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
|
@ -36,25 +38,25 @@ class MaterialBannerThemeData with Diagnosticable {
|
||||||
});
|
});
|
||||||
|
|
||||||
/// The background color of a [MaterialBanner].
|
/// The background color of a [MaterialBanner].
|
||||||
final Color? backgroundColor;
|
final Color backgroundColor;
|
||||||
|
|
||||||
/// Used to configure the [DefaultTextStyle] for the [MaterialBanner.content]
|
/// Used to configure the [DefaultTextStyle] for the [MaterialBanner.content]
|
||||||
/// widget.
|
/// widget.
|
||||||
final TextStyle? contentTextStyle;
|
final TextStyle contentTextStyle;
|
||||||
|
|
||||||
/// The amount of space by which to inset [MaterialBanner.content].
|
/// The amount of space by which to inset [MaterialBanner.content].
|
||||||
final EdgeInsetsGeometry? padding;
|
final EdgeInsetsGeometry padding;
|
||||||
|
|
||||||
/// The amount of space by which to inset [MaterialBanner.leading].
|
/// The amount of space by which to inset [MaterialBanner.leading].
|
||||||
final EdgeInsetsGeometry? leadingPadding;
|
final EdgeInsetsGeometry leadingPadding;
|
||||||
|
|
||||||
/// Creates a copy of this object with the given fields replaced with the
|
/// Creates a copy of this object with the given fields replaced with the
|
||||||
/// new values.
|
/// new values.
|
||||||
MaterialBannerThemeData copyWith({
|
MaterialBannerThemeData copyWith({
|
||||||
Color? backgroundColor,
|
Color backgroundColor,
|
||||||
TextStyle? contentTextStyle,
|
TextStyle contentTextStyle,
|
||||||
EdgeInsetsGeometry? padding,
|
EdgeInsetsGeometry padding,
|
||||||
EdgeInsetsGeometry? leadingPadding,
|
EdgeInsetsGeometry leadingPadding,
|
||||||
}) {
|
}) {
|
||||||
return MaterialBannerThemeData(
|
return MaterialBannerThemeData(
|
||||||
backgroundColor: backgroundColor ?? this.backgroundColor,
|
backgroundColor: backgroundColor ?? this.backgroundColor,
|
||||||
|
@ -69,7 +71,7 @@ class MaterialBannerThemeData with Diagnosticable {
|
||||||
/// The argument `t` must not be null.
|
/// The argument `t` must not be null.
|
||||||
///
|
///
|
||||||
/// {@macro dart.ui.shadow.lerp}
|
/// {@macro dart.ui.shadow.lerp}
|
||||||
static MaterialBannerThemeData lerp(MaterialBannerThemeData? a, MaterialBannerThemeData? b, double t) {
|
static MaterialBannerThemeData lerp(MaterialBannerThemeData a, MaterialBannerThemeData b, double t) {
|
||||||
assert(t != null);
|
assert(t != null);
|
||||||
return MaterialBannerThemeData(
|
return MaterialBannerThemeData(
|
||||||
backgroundColor: Color.lerp(a?.backgroundColor, b?.backgroundColor, t),
|
backgroundColor: Color.lerp(a?.backgroundColor, b?.backgroundColor, t),
|
||||||
|
@ -121,13 +123,13 @@ class MaterialBannerTheme extends InheritedTheme {
|
||||||
/// Creates a banner theme that controls the configurations for
|
/// Creates a banner theme that controls the configurations for
|
||||||
/// [MaterialBanner]s in its widget subtree.
|
/// [MaterialBanner]s in its widget subtree.
|
||||||
const MaterialBannerTheme({
|
const MaterialBannerTheme({
|
||||||
Key? key,
|
Key key,
|
||||||
this.data,
|
this.data,
|
||||||
required Widget child,
|
Widget child,
|
||||||
}) : super(key: key, child: child);
|
}) : super(key: key, child: child);
|
||||||
|
|
||||||
/// The properties for descendant [MaterialBanner] widgets.
|
/// The properties for descendant [MaterialBanner] widgets.
|
||||||
final MaterialBannerThemeData? data;
|
final MaterialBannerThemeData data;
|
||||||
|
|
||||||
/// The closest instance of this class's [data] value that encloses the given
|
/// The closest instance of this class's [data] value that encloses the given
|
||||||
/// context.
|
/// context.
|
||||||
|
@ -141,13 +143,13 @@ class MaterialBannerTheme extends InheritedTheme {
|
||||||
/// MaterialBannerThemeData theme = MaterialBannerTheme.of(context);
|
/// MaterialBannerThemeData theme = MaterialBannerTheme.of(context);
|
||||||
/// ```
|
/// ```
|
||||||
static MaterialBannerThemeData of(BuildContext context) {
|
static MaterialBannerThemeData of(BuildContext context) {
|
||||||
final MaterialBannerTheme? bannerTheme = context.dependOnInheritedWidgetOfExactType<MaterialBannerTheme>();
|
final MaterialBannerTheme bannerTheme = context.dependOnInheritedWidgetOfExactType<MaterialBannerTheme>();
|
||||||
return bannerTheme?.data ?? Theme.of(context)!.bannerTheme;
|
return bannerTheme?.data ?? Theme.of(context).bannerTheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget wrap(BuildContext context, Widget child) {
|
Widget wrap(BuildContext context, Widget child) {
|
||||||
final MaterialBannerTheme? ancestorTheme = context.findAncestorWidgetOfExactType<MaterialBannerTheme>();
|
final MaterialBannerTheme ancestorTheme = context.findAncestorWidgetOfExactType<MaterialBannerTheme>();
|
||||||
return identical(this, ancestorTheme) ? child : MaterialBannerTheme(data: data, child: child);
|
return identical(this, ancestorTheme) ? child : MaterialBannerTheme(data: data, child: child);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
// @dart = 2.8
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
@ -48,7 +50,7 @@ class BottomAppBar extends StatefulWidget {
|
||||||
/// If the corresponding [BottomAppBarTheme] property is null, then the default
|
/// If the corresponding [BottomAppBarTheme] property is null, then the default
|
||||||
/// specified in the property's documentation will be used.
|
/// specified in the property's documentation will be used.
|
||||||
const BottomAppBar({
|
const BottomAppBar({
|
||||||
Key? key,
|
Key key,
|
||||||
this.color,
|
this.color,
|
||||||
this.elevation,
|
this.elevation,
|
||||||
this.shape,
|
this.shape,
|
||||||
|
@ -66,14 +68,14 @@ class BottomAppBar extends StatefulWidget {
|
||||||
///
|
///
|
||||||
/// Typically this the child will be a [Row], with the first child
|
/// Typically this the child will be a [Row], with the first child
|
||||||
/// being an [IconButton] with the [Icons.menu] icon.
|
/// being an [IconButton] with the [Icons.menu] icon.
|
||||||
final Widget? child;
|
final Widget child;
|
||||||
|
|
||||||
/// The bottom app bar's background color.
|
/// The bottom app bar's background color.
|
||||||
///
|
///
|
||||||
/// If this property is null then [BottomAppBarTheme.color] of
|
/// If this property is null then [BottomAppBarTheme.color] of
|
||||||
/// [ThemeData.bottomAppBarTheme] is used. If that's null then
|
/// [ThemeData.bottomAppBarTheme] is used. If that's null then
|
||||||
/// [ThemeData.bottomAppBarColor] is used.
|
/// [ThemeData.bottomAppBarColor] is used.
|
||||||
final Color? color;
|
final Color color;
|
||||||
|
|
||||||
/// The z-coordinate at which to place this bottom app bar relative to its
|
/// The z-coordinate at which to place this bottom app bar relative to its
|
||||||
/// parent.
|
/// parent.
|
||||||
|
@ -84,14 +86,14 @@ class BottomAppBar extends StatefulWidget {
|
||||||
/// If this property is null then [BottomAppBarTheme.elevation] of
|
/// If this property is null then [BottomAppBarTheme.elevation] of
|
||||||
/// [ThemeData.bottomAppBarTheme] is used. If that's null, the default value
|
/// [ThemeData.bottomAppBarTheme] is used. If that's null, the default value
|
||||||
/// is 8.
|
/// is 8.
|
||||||
final double? elevation;
|
final double elevation;
|
||||||
|
|
||||||
/// The notch that is made for the floating action button.
|
/// The notch that is made for the floating action button.
|
||||||
///
|
///
|
||||||
/// If this property is null then [BottomAppBarTheme.shape] of
|
/// If this property is null then [BottomAppBarTheme.shape] of
|
||||||
/// [ThemeData.bottomAppBarTheme] is used. If that's null then the shape will
|
/// [ThemeData.bottomAppBarTheme] is used. If that's null then the shape will
|
||||||
/// be rectangular with no notch.
|
/// be rectangular with no notch.
|
||||||
final NotchedShape? shape;
|
final NotchedShape shape;
|
||||||
|
|
||||||
/// {@macro flutter.widgets.Clip}
|
/// {@macro flutter.widgets.Clip}
|
||||||
///
|
///
|
||||||
|
@ -109,19 +111,19 @@ class BottomAppBar extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _BottomAppBarState extends State<BottomAppBar> {
|
class _BottomAppBarState extends State<BottomAppBar> {
|
||||||
late ValueListenable<ScaffoldGeometry> geometryListenable;
|
ValueListenable<ScaffoldGeometry> geometryListenable;
|
||||||
static const double _defaultElevation = 8.0;
|
static const double _defaultElevation = 8.0;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void didChangeDependencies() {
|
void didChangeDependencies() {
|
||||||
super.didChangeDependencies();
|
super.didChangeDependencies();
|
||||||
geometryListenable = Scaffold.geometryOf(context)!;
|
geometryListenable = Scaffold.geometryOf(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final BottomAppBarTheme babTheme = BottomAppBarTheme.of(context);
|
final BottomAppBarTheme babTheme = BottomAppBarTheme.of(context);
|
||||||
final NotchedShape? notchedShape = widget.shape ?? babTheme.shape;
|
final NotchedShape notchedShape = widget.shape ?? babTheme.shape;
|
||||||
final CustomClipper<Path> clipper = notchedShape != null
|
final CustomClipper<Path> clipper = notchedShape != null
|
||||||
? _BottomAppBarClipper(
|
? _BottomAppBarClipper(
|
||||||
geometry: geometryListenable,
|
geometry: geometryListenable,
|
||||||
|
@ -130,7 +132,7 @@ class _BottomAppBarState extends State<BottomAppBar> {
|
||||||
)
|
)
|
||||||
: const ShapeBorderClipper(shape: RoundedRectangleBorder());
|
: const ShapeBorderClipper(shape: RoundedRectangleBorder());
|
||||||
final double elevation = widget.elevation ?? babTheme.elevation ?? _defaultElevation;
|
final double elevation = widget.elevation ?? babTheme.elevation ?? _defaultElevation;
|
||||||
final Color color = widget.color ?? babTheme.color ?? Theme.of(context)!.bottomAppBarColor;
|
final Color color = widget.color ?? babTheme.color ?? Theme.of(context).bottomAppBarColor;
|
||||||
final Color effectiveColor = ElevationOverlay.applyOverlay(context, color, elevation);
|
final Color effectiveColor = ElevationOverlay.applyOverlay(context, color, elevation);
|
||||||
return PhysicalShape(
|
return PhysicalShape(
|
||||||
clipper: clipper,
|
clipper: clipper,
|
||||||
|
@ -141,7 +143,7 @@ class _BottomAppBarState extends State<BottomAppBar> {
|
||||||
type: MaterialType.transparency,
|
type: MaterialType.transparency,
|
||||||
child: widget.child == null
|
child: widget.child == null
|
||||||
? null
|
? null
|
||||||
: SafeArea(child: widget.child!),
|
: SafeArea(child: widget.child),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -149,9 +151,9 @@ class _BottomAppBarState extends State<BottomAppBar> {
|
||||||
|
|
||||||
class _BottomAppBarClipper extends CustomClipper<Path> {
|
class _BottomAppBarClipper extends CustomClipper<Path> {
|
||||||
const _BottomAppBarClipper({
|
const _BottomAppBarClipper({
|
||||||
required this.geometry,
|
@required this.geometry,
|
||||||
required this.shape,
|
@required this.shape,
|
||||||
required this.notchMargin,
|
@required this.notchMargin,
|
||||||
}) : assert(geometry != null),
|
}) : assert(geometry != null),
|
||||||
assert(shape != null),
|
assert(shape != null),
|
||||||
assert(notchMargin != null),
|
assert(notchMargin != null),
|
||||||
|
@ -166,9 +168,9 @@ class _BottomAppBarClipper extends CustomClipper<Path> {
|
||||||
// button is the floating action button's bounding rectangle in the
|
// button is the floating action button's bounding rectangle in the
|
||||||
// coordinate system whose origin is at the appBar's top left corner,
|
// coordinate system whose origin is at the appBar's top left corner,
|
||||||
// or null if there is no floating action button.
|
// or null if there is no floating action button.
|
||||||
final Rect? button = geometry.value.floatingActionButtonArea?.translate(
|
final Rect button = geometry.value.floatingActionButtonArea?.translate(
|
||||||
0.0,
|
0.0,
|
||||||
geometry.value.bottomNavigationBarTop! * -1.0,
|
geometry.value.bottomNavigationBarTop * -1.0,
|
||||||
);
|
);
|
||||||
return shape.getOuterPath(Offset.zero & size, button?.inflate(notchMargin));
|
return shape.getOuterPath(Offset.zero & size, button?.inflate(notchMargin));
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
// @dart = 2.8
|
||||||
|
|
||||||
import 'dart:ui' show lerpDouble;
|
import 'dart:ui' show lerpDouble;
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
@ -37,20 +39,20 @@ class BottomAppBarTheme with Diagnosticable {
|
||||||
/// Default value for [BottomAppBar.color].
|
/// Default value for [BottomAppBar.color].
|
||||||
///
|
///
|
||||||
/// If null, [BottomAppBar] uses [ThemeData.bottomAppBarColor].
|
/// If null, [BottomAppBar] uses [ThemeData.bottomAppBarColor].
|
||||||
final Color? color;
|
final Color color;
|
||||||
|
|
||||||
/// Default value for [BottomAppBar.elevation].
|
/// Default value for [BottomAppBar.elevation].
|
||||||
final double? elevation;
|
final double elevation;
|
||||||
|
|
||||||
/// Default value for [BottomAppBar.shape].
|
/// Default value for [BottomAppBar.shape].
|
||||||
final NotchedShape? shape;
|
final NotchedShape shape;
|
||||||
|
|
||||||
/// Creates a copy of this object but with the given fields replaced with the
|
/// Creates a copy of this object but with the given fields replaced with the
|
||||||
/// new values.
|
/// new values.
|
||||||
BottomAppBarTheme copyWith({
|
BottomAppBarTheme copyWith({
|
||||||
Color? color,
|
Color color,
|
||||||
double? elevation,
|
double elevation,
|
||||||
NotchedShape? shape,
|
NotchedShape shape,
|
||||||
}) {
|
}) {
|
||||||
return BottomAppBarTheme(
|
return BottomAppBarTheme(
|
||||||
color: color ?? this.color,
|
color: color ?? this.color,
|
||||||
|
@ -61,7 +63,7 @@ class BottomAppBarTheme with Diagnosticable {
|
||||||
|
|
||||||
/// The [ThemeData.bottomAppBarTheme] property of the ambient [Theme].
|
/// The [ThemeData.bottomAppBarTheme] property of the ambient [Theme].
|
||||||
static BottomAppBarTheme of(BuildContext context) {
|
static BottomAppBarTheme of(BuildContext context) {
|
||||||
return Theme.of(context)!.bottomAppBarTheme;
|
return Theme.of(context).bottomAppBarTheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Linearly interpolate between two BAB themes.
|
/// Linearly interpolate between two BAB themes.
|
||||||
|
@ -69,7 +71,7 @@ class BottomAppBarTheme with Diagnosticable {
|
||||||
/// The argument `t` must not be null.
|
/// The argument `t` must not be null.
|
||||||
///
|
///
|
||||||
/// {@macro dart.ui.shadow.lerp}
|
/// {@macro dart.ui.shadow.lerp}
|
||||||
static BottomAppBarTheme lerp(BottomAppBarTheme? a, BottomAppBarTheme? b, double t) {
|
static BottomAppBarTheme lerp(BottomAppBarTheme a, BottomAppBarTheme b, double t) {
|
||||||
assert(t != null);
|
assert(t != null);
|
||||||
return BottomAppBarTheme(
|
return BottomAppBarTheme(
|
||||||
color: Color.lerp(a?.color, b?.color, t),
|
color: Color.lerp(a?.color, b?.color, t),
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
// @dart = 2.8
|
||||||
|
|
||||||
import 'dart:collection' show Queue;
|
import 'dart:collection' show Queue;
|
||||||
import 'dart:math' as math;
|
import 'dart:math' as math;
|
||||||
|
|
||||||
|
@ -170,16 +172,16 @@ class BottomNavigationBar extends StatefulWidget {
|
||||||
/// [BottomNavigationBarType.fixed] and `false` if [type] is
|
/// [BottomNavigationBarType.fixed] and `false` if [type] is
|
||||||
/// [BottomNavigationBarType.shifting].
|
/// [BottomNavigationBarType.shifting].
|
||||||
BottomNavigationBar({
|
BottomNavigationBar({
|
||||||
Key? key,
|
Key key,
|
||||||
required this.items,
|
@required this.items,
|
||||||
this.onTap,
|
this.onTap,
|
||||||
this.currentIndex = 0,
|
this.currentIndex = 0,
|
||||||
this.elevation,
|
this.elevation,
|
||||||
this.type,
|
this.type,
|
||||||
Color? fixedColor,
|
Color fixedColor,
|
||||||
this.backgroundColor,
|
this.backgroundColor,
|
||||||
this.iconSize = 24.0,
|
this.iconSize = 24.0,
|
||||||
Color? selectedItemColor,
|
Color selectedItemColor,
|
||||||
this.unselectedItemColor,
|
this.unselectedItemColor,
|
||||||
this.selectedIconTheme,
|
this.selectedIconTheme,
|
||||||
this.unselectedIconTheme,
|
this.unselectedIconTheme,
|
||||||
|
@ -219,7 +221,7 @@ class BottomNavigationBar extends StatefulWidget {
|
||||||
/// The stateful widget that creates the bottom navigation bar needs to keep
|
/// The stateful widget that creates the bottom navigation bar needs to keep
|
||||||
/// track of the index of the selected [BottomNavigationBarItem] and call
|
/// track of the index of the selected [BottomNavigationBarItem] and call
|
||||||
/// `setState` to rebuild the bottom navigation bar with the new [currentIndex].
|
/// `setState` to rebuild the bottom navigation bar with the new [currentIndex].
|
||||||
final ValueChanged<int>? onTap;
|
final ValueChanged<int> onTap;
|
||||||
|
|
||||||
/// The index into [items] for the current active [BottomNavigationBarItem].
|
/// The index into [items] for the current active [BottomNavigationBarItem].
|
||||||
final int currentIndex;
|
final int currentIndex;
|
||||||
|
@ -229,26 +231,26 @@ class BottomNavigationBar extends StatefulWidget {
|
||||||
/// If null, defaults to `8.0`.
|
/// If null, defaults to `8.0`.
|
||||||
///
|
///
|
||||||
/// {@macro flutter.material.material.elevation}
|
/// {@macro flutter.material.material.elevation}
|
||||||
final double? elevation;
|
final double elevation;
|
||||||
|
|
||||||
/// Defines the layout and behavior of a [BottomNavigationBar].
|
/// Defines the layout and behavior of a [BottomNavigationBar].
|
||||||
///
|
///
|
||||||
/// See documentation for [BottomNavigationBarType] for information on the
|
/// See documentation for [BottomNavigationBarType] for information on the
|
||||||
/// meaning of different types.
|
/// meaning of different types.
|
||||||
final BottomNavigationBarType? type;
|
final BottomNavigationBarType type;
|
||||||
|
|
||||||
/// The value of [selectedItemColor].
|
/// The value of [selectedItemColor].
|
||||||
///
|
///
|
||||||
/// This getter only exists for backwards compatibility, the
|
/// This getter only exists for backwards compatibility, the
|
||||||
/// [selectedItemColor] property is preferred.
|
/// [selectedItemColor] property is preferred.
|
||||||
Color? get fixedColor => selectedItemColor;
|
Color get fixedColor => selectedItemColor;
|
||||||
|
|
||||||
/// The color of the [BottomNavigationBar] itself.
|
/// The color of the [BottomNavigationBar] itself.
|
||||||
///
|
///
|
||||||
/// If [type] is [BottomNavigationBarType.shifting] and the
|
/// If [type] is [BottomNavigationBarType.shifting] and the
|
||||||
/// [items] have [BottomNavigationBarItem.backgroundColor] set, the [items]'
|
/// [items] have [BottomNavigationBarItem.backgroundColor] set, the [items]'
|
||||||
/// backgroundColor will splash and overwrite this color.
|
/// backgroundColor will splash and overwrite this color.
|
||||||
final Color? backgroundColor;
|
final Color backgroundColor;
|
||||||
|
|
||||||
/// The size of all of the [BottomNavigationBarItem] icons.
|
/// The size of all of the [BottomNavigationBarItem] icons.
|
||||||
///
|
///
|
||||||
|
@ -259,13 +261,13 @@ class BottomNavigationBar extends StatefulWidget {
|
||||||
/// [BottomNavigationBarItem.title].
|
/// [BottomNavigationBarItem.title].
|
||||||
///
|
///
|
||||||
/// If null then the [ThemeData.primaryColor] is used.
|
/// If null then the [ThemeData.primaryColor] is used.
|
||||||
final Color? selectedItemColor;
|
final Color selectedItemColor;
|
||||||
|
|
||||||
/// The color of the unselected [BottomNavigationBarItem.icon] and
|
/// The color of the unselected [BottomNavigationBarItem.icon] and
|
||||||
/// [BottomNavigationBarItem.title]s.
|
/// [BottomNavigationBarItem.title]s.
|
||||||
///
|
///
|
||||||
/// If null then the [TextTheme.caption]'s color is used.
|
/// If null then the [TextTheme.caption]'s color is used.
|
||||||
final Color? unselectedItemColor;
|
final Color unselectedItemColor;
|
||||||
|
|
||||||
/// The size, opacity, and color of the icon in the currently selected
|
/// The size, opacity, and color of the icon in the currently selected
|
||||||
/// [BottomNavigationBarItem.icon].
|
/// [BottomNavigationBarItem.icon].
|
||||||
|
@ -276,7 +278,7 @@ class BottomNavigationBar extends StatefulWidget {
|
||||||
/// It this field is provided, it must contain non-null [IconThemeData.size]
|
/// It this field is provided, it must contain non-null [IconThemeData.size]
|
||||||
/// and [IconThemeData.color] properties. Also, if this field is supplied,
|
/// and [IconThemeData.color] properties. Also, if this field is supplied,
|
||||||
/// [unselectedIconTheme] must be provided.
|
/// [unselectedIconTheme] must be provided.
|
||||||
final IconThemeData? selectedIconTheme;
|
final IconThemeData selectedIconTheme;
|
||||||
|
|
||||||
/// The size, opacity, and color of the icon in the currently unselected
|
/// The size, opacity, and color of the icon in the currently unselected
|
||||||
/// [BottomNavigationBarItem.icon]s.
|
/// [BottomNavigationBarItem.icon]s.
|
||||||
|
@ -287,15 +289,15 @@ class BottomNavigationBar extends StatefulWidget {
|
||||||
/// It this field is provided, it must contain non-null [IconThemeData.size]
|
/// It this field is provided, it must contain non-null [IconThemeData.size]
|
||||||
/// and [IconThemeData.color] properties. Also, if this field is supplied,
|
/// and [IconThemeData.color] properties. Also, if this field is supplied,
|
||||||
/// [unselectedIconTheme] must be provided.
|
/// [unselectedIconTheme] must be provided.
|
||||||
final IconThemeData? unselectedIconTheme;
|
final IconThemeData unselectedIconTheme;
|
||||||
|
|
||||||
/// The [TextStyle] of the [BottomNavigationBarItem] labels when they are
|
/// The [TextStyle] of the [BottomNavigationBarItem] labels when they are
|
||||||
/// selected.
|
/// selected.
|
||||||
final TextStyle? selectedLabelStyle;
|
final TextStyle selectedLabelStyle;
|
||||||
|
|
||||||
/// The [TextStyle] of the [BottomNavigationBarItem] labels when they are not
|
/// The [TextStyle] of the [BottomNavigationBarItem] labels when they are not
|
||||||
/// selected.
|
/// selected.
|
||||||
final TextStyle? unselectedLabelStyle;
|
final TextStyle unselectedLabelStyle;
|
||||||
|
|
||||||
/// The font size of the [BottomNavigationBarItem] labels when they are selected.
|
/// The font size of the [BottomNavigationBarItem] labels when they are selected.
|
||||||
///
|
///
|
||||||
|
@ -315,7 +317,7 @@ class BottomNavigationBar extends StatefulWidget {
|
||||||
final double unselectedFontSize;
|
final double unselectedFontSize;
|
||||||
|
|
||||||
/// Whether the labels are shown for the selected [BottomNavigationBarItem].
|
/// Whether the labels are shown for the selected [BottomNavigationBarItem].
|
||||||
final bool? showUnselectedLabels;
|
final bool showUnselectedLabels;
|
||||||
|
|
||||||
/// Whether the labels are shown for the unselected [BottomNavigationBarItem]s.
|
/// Whether the labels are shown for the unselected [BottomNavigationBarItem]s.
|
||||||
final bool showSelectedLabels;
|
final bool showSelectedLabels;
|
||||||
|
@ -324,7 +326,7 @@ class BottomNavigationBar extends StatefulWidget {
|
||||||
/// tiles.
|
/// tiles.
|
||||||
///
|
///
|
||||||
/// If this property is null, [SystemMouseCursors.click] will be used.
|
/// If this property is null, [SystemMouseCursors.click] will be used.
|
||||||
final MouseCursor? mouseCursor;
|
final MouseCursor mouseCursor;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_BottomNavigationBarState createState() => _BottomNavigationBarState();
|
_BottomNavigationBarState createState() => _BottomNavigationBarState();
|
||||||
|
@ -342,14 +344,14 @@ class _BottomNavigationTile extends StatelessWidget {
|
||||||
this.colorTween,
|
this.colorTween,
|
||||||
this.flex,
|
this.flex,
|
||||||
this.selected = false,
|
this.selected = false,
|
||||||
required this.selectedLabelStyle,
|
@required this.selectedLabelStyle,
|
||||||
required this.unselectedLabelStyle,
|
@required this.unselectedLabelStyle,
|
||||||
required this.selectedIconTheme,
|
@required this.selectedIconTheme,
|
||||||
required this.unselectedIconTheme,
|
@required this.unselectedIconTheme,
|
||||||
this.showSelectedLabels,
|
this.showSelectedLabels,
|
||||||
this.showUnselectedLabels,
|
this.showUnselectedLabels,
|
||||||
this.indexLabel,
|
this.indexLabel,
|
||||||
required this.mouseCursor,
|
@required this.mouseCursor,
|
||||||
}) : assert(type != null),
|
}) : assert(type != null),
|
||||||
assert(item != null),
|
assert(item != null),
|
||||||
assert(animation != null),
|
assert(animation != null),
|
||||||
|
@ -362,17 +364,17 @@ class _BottomNavigationTile extends StatelessWidget {
|
||||||
final BottomNavigationBarItem item;
|
final BottomNavigationBarItem item;
|
||||||
final Animation<double> animation;
|
final Animation<double> animation;
|
||||||
final double iconSize;
|
final double iconSize;
|
||||||
final VoidCallback? onTap;
|
final VoidCallback onTap;
|
||||||
final ColorTween? colorTween;
|
final ColorTween colorTween;
|
||||||
final double? flex;
|
final double flex;
|
||||||
final bool selected;
|
final bool selected;
|
||||||
final IconThemeData? selectedIconTheme;
|
final IconThemeData selectedIconTheme;
|
||||||
final IconThemeData? unselectedIconTheme;
|
final IconThemeData unselectedIconTheme;
|
||||||
final TextStyle selectedLabelStyle;
|
final TextStyle selectedLabelStyle;
|
||||||
final TextStyle unselectedLabelStyle;
|
final TextStyle unselectedLabelStyle;
|
||||||
final String? indexLabel;
|
final String indexLabel;
|
||||||
final bool? showSelectedLabels;
|
final bool showSelectedLabels;
|
||||||
final bool? showUnselectedLabels;
|
final bool showUnselectedLabels;
|
||||||
final MouseCursor mouseCursor;
|
final MouseCursor mouseCursor;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -385,13 +387,13 @@ class _BottomNavigationTile extends StatelessWidget {
|
||||||
|
|
||||||
final BottomNavigationBarThemeData bottomTheme = BottomNavigationBarTheme.of(context);
|
final BottomNavigationBarThemeData bottomTheme = BottomNavigationBarTheme.of(context);
|
||||||
|
|
||||||
final double selectedFontSize = selectedLabelStyle.fontSize!;
|
final double selectedFontSize = selectedLabelStyle.fontSize;
|
||||||
|
|
||||||
final double selectedIconSize = selectedIconTheme?.size
|
final double selectedIconSize = selectedIconTheme?.size
|
||||||
?? bottomTheme.selectedIconTheme?.size
|
?? bottomTheme?.selectedIconTheme?.size
|
||||||
?? iconSize;
|
?? iconSize;
|
||||||
final double unselectedIconSize = unselectedIconTheme?.size
|
final double unselectedIconSize = unselectedIconTheme?.size
|
||||||
?? bottomTheme.unselectedIconTheme?.size
|
?? bottomTheme?.unselectedIconTheme?.size
|
||||||
?? iconSize;
|
?? iconSize;
|
||||||
|
|
||||||
// The amount that the selected icon is bigger than the unselected icons,
|
// The amount that the selected icon is bigger than the unselected icons,
|
||||||
|
@ -420,7 +422,7 @@ class _BottomNavigationTile extends StatelessWidget {
|
||||||
// =======
|
// =======
|
||||||
double bottomPadding;
|
double bottomPadding;
|
||||||
double topPadding;
|
double topPadding;
|
||||||
if (showSelectedLabels! && !showUnselectedLabels!) {
|
if (showSelectedLabels && !showUnselectedLabels) {
|
||||||
bottomPadding = Tween<double>(
|
bottomPadding = Tween<double>(
|
||||||
begin: selectedIconDiff / 2.0,
|
begin: selectedIconDiff / 2.0,
|
||||||
end: selectedFontSize / 2.0 - unselectedIconDiff / 2.0,
|
end: selectedFontSize / 2.0 - unselectedIconDiff / 2.0,
|
||||||
|
@ -429,7 +431,7 @@ class _BottomNavigationTile extends StatelessWidget {
|
||||||
begin: selectedFontSize + selectedIconDiff / 2.0,
|
begin: selectedFontSize + selectedIconDiff / 2.0,
|
||||||
end: selectedFontSize / 2.0 - unselectedIconDiff / 2.0,
|
end: selectedFontSize / 2.0 - unselectedIconDiff / 2.0,
|
||||||
).evaluate(animation);
|
).evaluate(animation);
|
||||||
} else if (!showSelectedLabels! && !showUnselectedLabels!) {
|
} else if (!showSelectedLabels && !showUnselectedLabels) {
|
||||||
bottomPadding = Tween<double>(
|
bottomPadding = Tween<double>(
|
||||||
begin: selectedIconDiff / 2.0,
|
begin: selectedIconDiff / 2.0,
|
||||||
end: unselectedIconDiff / 2.0,
|
end: unselectedIconDiff / 2.0,
|
||||||
|
@ -454,7 +456,7 @@ class _BottomNavigationTile extends StatelessWidget {
|
||||||
size = 1;
|
size = 1;
|
||||||
break;
|
break;
|
||||||
case BottomNavigationBarType.shifting:
|
case BottomNavigationBarType.shifting:
|
||||||
size = (flex! * 1000.0).round();
|
size = (flex * 1000.0).round();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -469,7 +471,7 @@ class _BottomNavigationTile extends StatelessWidget {
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
_TileIcon(
|
_TileIcon(
|
||||||
colorTween: colorTween!,
|
colorTween: colorTween,
|
||||||
animation: animation,
|
animation: animation,
|
||||||
iconSize: iconSize,
|
iconSize: iconSize,
|
||||||
selected: selected,
|
selected: selected,
|
||||||
|
@ -478,13 +480,13 @@ class _BottomNavigationTile extends StatelessWidget {
|
||||||
unselectedIconTheme: unselectedIconTheme ?? bottomTheme.unselectedIconTheme,
|
unselectedIconTheme: unselectedIconTheme ?? bottomTheme.unselectedIconTheme,
|
||||||
),
|
),
|
||||||
_Label(
|
_Label(
|
||||||
colorTween: colorTween!,
|
colorTween: colorTween,
|
||||||
animation: animation,
|
animation: animation,
|
||||||
item: item,
|
item: item,
|
||||||
selectedLabelStyle: selectedLabelStyle,
|
selectedLabelStyle: selectedLabelStyle ?? bottomTheme.selectedLabelStyle,
|
||||||
unselectedLabelStyle: unselectedLabelStyle,
|
unselectedLabelStyle: unselectedLabelStyle ?? bottomTheme.unselectedLabelStyle,
|
||||||
showSelectedLabels: showSelectedLabels ?? bottomTheme.showUnselectedLabels!,
|
showSelectedLabels: showSelectedLabels ?? bottomTheme.showUnselectedLabels,
|
||||||
showUnselectedLabels: showUnselectedLabels ?? bottomTheme.showUnselectedLabels!,
|
showUnselectedLabels: showUnselectedLabels ?? bottomTheme.showUnselectedLabels,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -493,7 +495,7 @@ class _BottomNavigationTile extends StatelessWidget {
|
||||||
|
|
||||||
if (item.label != null) {
|
if (item.label != null) {
|
||||||
result = Tooltip(
|
result = Tooltip(
|
||||||
message: item.label!,
|
message: item.label,
|
||||||
preferBelow: false,
|
preferBelow: false,
|
||||||
verticalOffset: selectedIconSize + selectedFontSize,
|
verticalOffset: selectedIconSize + selectedFontSize,
|
||||||
child: result,
|
child: result,
|
||||||
|
@ -523,14 +525,14 @@ class _BottomNavigationTile extends StatelessWidget {
|
||||||
|
|
||||||
class _TileIcon extends StatelessWidget {
|
class _TileIcon extends StatelessWidget {
|
||||||
const _TileIcon({
|
const _TileIcon({
|
||||||
Key? key,
|
Key key,
|
||||||
required this.colorTween,
|
@required this.colorTween,
|
||||||
required this.animation,
|
@required this.animation,
|
||||||
required this.iconSize,
|
@required this.iconSize,
|
||||||
required this.selected,
|
@required this.selected,
|
||||||
required this.item,
|
@required this.item,
|
||||||
required this.selectedIconTheme,
|
@required this.selectedIconTheme,
|
||||||
required this.unselectedIconTheme,
|
@required this.unselectedIconTheme,
|
||||||
}) : assert(selected != null),
|
}) : assert(selected != null),
|
||||||
assert(item != null),
|
assert(item != null),
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
@ -540,12 +542,12 @@ class _TileIcon extends StatelessWidget {
|
||||||
final double iconSize;
|
final double iconSize;
|
||||||
final bool selected;
|
final bool selected;
|
||||||
final BottomNavigationBarItem item;
|
final BottomNavigationBarItem item;
|
||||||
final IconThemeData? selectedIconTheme;
|
final IconThemeData selectedIconTheme;
|
||||||
final IconThemeData? unselectedIconTheme;
|
final IconThemeData unselectedIconTheme;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final Color? iconColor = colorTween.evaluate(animation);
|
final Color iconColor = colorTween.evaluate(animation);
|
||||||
final IconThemeData defaultIconTheme = IconThemeData(
|
final IconThemeData defaultIconTheme = IconThemeData(
|
||||||
color: iconColor,
|
color: iconColor,
|
||||||
size: iconSize,
|
size: iconSize,
|
||||||
|
@ -571,14 +573,14 @@ class _TileIcon extends StatelessWidget {
|
||||||
|
|
||||||
class _Label extends StatelessWidget {
|
class _Label extends StatelessWidget {
|
||||||
const _Label({
|
const _Label({
|
||||||
Key? key,
|
Key key,
|
||||||
required this.colorTween,
|
@required this.colorTween,
|
||||||
required this.animation,
|
@required this.animation,
|
||||||
required this.item,
|
@required this.item,
|
||||||
required this.selectedLabelStyle,
|
@required this.selectedLabelStyle,
|
||||||
required this.unselectedLabelStyle,
|
@required this.unselectedLabelStyle,
|
||||||
required this.showSelectedLabels,
|
@required this.showSelectedLabels,
|
||||||
required this.showUnselectedLabels,
|
@required this.showUnselectedLabels,
|
||||||
}) : assert(colorTween != null),
|
}) : assert(colorTween != null),
|
||||||
assert(animation != null),
|
assert(animation != null),
|
||||||
assert(item != null),
|
assert(item != null),
|
||||||
|
@ -598,14 +600,14 @@ class _Label extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final double? selectedFontSize = selectedLabelStyle.fontSize;
|
final double selectedFontSize = selectedLabelStyle.fontSize;
|
||||||
final double? unselectedFontSize = unselectedLabelStyle.fontSize;
|
final double unselectedFontSize = unselectedLabelStyle.fontSize;
|
||||||
|
|
||||||
final TextStyle customStyle = TextStyle.lerp(
|
final TextStyle customStyle = TextStyle.lerp(
|
||||||
unselectedLabelStyle,
|
unselectedLabelStyle,
|
||||||
selectedLabelStyle,
|
selectedLabelStyle,
|
||||||
animation.value,
|
animation.value,
|
||||||
)!;
|
);
|
||||||
Widget text = DefaultTextStyle.merge(
|
Widget text = DefaultTextStyle.merge(
|
||||||
style: customStyle.copyWith(
|
style: customStyle.copyWith(
|
||||||
fontSize: selectedFontSize,
|
fontSize: selectedFontSize,
|
||||||
|
@ -618,13 +620,13 @@ class _Label extends StatelessWidget {
|
||||||
transform: Matrix4.diagonal3(
|
transform: Matrix4.diagonal3(
|
||||||
Vector3.all(
|
Vector3.all(
|
||||||
Tween<double>(
|
Tween<double>(
|
||||||
begin: unselectedFontSize! / selectedFontSize!,
|
begin: unselectedFontSize / selectedFontSize,
|
||||||
end: 1.0,
|
end: 1.0,
|
||||||
).evaluate(animation),
|
).evaluate(animation),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
alignment: Alignment.bottomCenter,
|
alignment: Alignment.bottomCenter,
|
||||||
child: item.title ?? Text(item.label!),
|
child: item.title ?? Text(item.label),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -660,7 +662,7 @@ class _Label extends StatelessWidget {
|
||||||
if (item.label != null) {
|
if (item.label != null) {
|
||||||
// Do not grow text in bottom navigation bar when we can show a tooltip
|
// Do not grow text in bottom navigation bar when we can show a tooltip
|
||||||
// instead.
|
// instead.
|
||||||
final MediaQueryData mediaQueryData = MediaQuery.of(context)!;
|
final MediaQueryData mediaQueryData = MediaQuery.of(context);
|
||||||
text = MediaQuery(
|
text = MediaQuery(
|
||||||
data: mediaQueryData.copyWith(
|
data: mediaQueryData.copyWith(
|
||||||
textScaleFactor: math.min(1.0, mediaQueryData.textScaleFactor),
|
textScaleFactor: math.min(1.0, mediaQueryData.textScaleFactor),
|
||||||
|
@ -675,14 +677,14 @@ class _Label extends StatelessWidget {
|
||||||
|
|
||||||
class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerProviderStateMixin {
|
class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerProviderStateMixin {
|
||||||
List<AnimationController> _controllers = <AnimationController>[];
|
List<AnimationController> _controllers = <AnimationController>[];
|
||||||
late List<CurvedAnimation> _animations;
|
List<CurvedAnimation> _animations;
|
||||||
|
|
||||||
// A queue of color splashes currently being animated.
|
// A queue of color splashes currently being animated.
|
||||||
final Queue<_Circle> _circles = Queue<_Circle>();
|
final Queue<_Circle> _circles = Queue<_Circle>();
|
||||||
|
|
||||||
// Last splash circle's color, and the final color of the control after
|
// Last splash circle's color, and the final color of the control after
|
||||||
// animation is complete.
|
// animation is complete.
|
||||||
Color? _backgroundColor;
|
Color _backgroundColor;
|
||||||
|
|
||||||
static final Animatable<double> _flexTween = Tween<double>(begin: 1.0, end: 1.5);
|
static final Animatable<double> _flexTween = Tween<double>(begin: 1.0, end: 1.5);
|
||||||
|
|
||||||
|
@ -733,6 +735,8 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr
|
||||||
case BottomNavigationBarType.fixed:
|
case BottomNavigationBarType.fixed:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
assert(false);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -765,7 +769,7 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr
|
||||||
_Circle(
|
_Circle(
|
||||||
state: this,
|
state: this,
|
||||||
index: index,
|
index: index,
|
||||||
color: widget.items[index].backgroundColor!,
|
color: widget.items[index].backgroundColor,
|
||||||
vsync: this,
|
vsync: this,
|
||||||
)..controller.addStatusListener(
|
)..controller.addStatusListener(
|
||||||
(AnimationStatus status) {
|
(AnimationStatus status) {
|
||||||
|
@ -816,17 +820,17 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr
|
||||||
|
|
||||||
// If the given [TextStyle] has a non-null `fontSize`, it should be used.
|
// If the given [TextStyle] has a non-null `fontSize`, it should be used.
|
||||||
// Otherwise, the [selectedFontSize] parameter should be used.
|
// Otherwise, the [selectedFontSize] parameter should be used.
|
||||||
static TextStyle _effectiveTextStyle(TextStyle? textStyle, double fontSize) {
|
static TextStyle _effectiveTextStyle(TextStyle textStyle, double fontSize) {
|
||||||
textStyle ??= const TextStyle();
|
textStyle ??= const TextStyle();
|
||||||
// Prefer the font size on textStyle if present.
|
// Prefer the font size on textStyle if present.
|
||||||
return textStyle.fontSize == null ? textStyle.copyWith(fontSize: fontSize) : textStyle;
|
return textStyle.fontSize == null ? textStyle.copyWith(fontSize: fontSize) : textStyle;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Widget> _createTiles() {
|
List<Widget> _createTiles() {
|
||||||
final MaterialLocalizations localizations = MaterialLocalizations.of(context)!;
|
final MaterialLocalizations localizations = MaterialLocalizations.of(context);
|
||||||
assert(localizations != null);
|
assert(localizations != null);
|
||||||
|
|
||||||
final ThemeData themeData = Theme.of(context)!;
|
final ThemeData themeData = Theme.of(context);
|
||||||
final BottomNavigationBarThemeData bottomTheme = BottomNavigationBarTheme.of(context);
|
final BottomNavigationBarThemeData bottomTheme = BottomNavigationBarTheme.of(context);
|
||||||
|
|
||||||
final TextStyle effectiveSelectedLabelStyle =
|
final TextStyle effectiveSelectedLabelStyle =
|
||||||
|
@ -856,7 +860,7 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr
|
||||||
colorTween = ColorTween(
|
colorTween = ColorTween(
|
||||||
begin: widget.unselectedItemColor
|
begin: widget.unselectedItemColor
|
||||||
?? bottomTheme.unselectedItemColor
|
?? bottomTheme.unselectedItemColor
|
||||||
?? themeData.textTheme.caption!.color,
|
?? themeData.textTheme.caption.color,
|
||||||
end: widget.selectedItemColor
|
end: widget.selectedItemColor
|
||||||
?? bottomTheme.selectedItemColor
|
?? bottomTheme.selectedItemColor
|
||||||
?? widget.fixedColor
|
?? widget.fixedColor
|
||||||
|
@ -889,12 +893,12 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr
|
||||||
unselectedLabelStyle: effectiveUnselectedLabelStyle,
|
unselectedLabelStyle: effectiveUnselectedLabelStyle,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (widget.onTap != null)
|
if (widget.onTap != null)
|
||||||
widget.onTap!(i);
|
widget.onTap(i);
|
||||||
},
|
},
|
||||||
colorTween: colorTween,
|
colorTween: colorTween,
|
||||||
flex: _evaluateFlex(_animations[i]),
|
flex: _evaluateFlex(_animations[i]),
|
||||||
selected: i == widget.currentIndex,
|
selected: i == widget.currentIndex,
|
||||||
showSelectedLabels: widget.showSelectedLabels,
|
showSelectedLabels: widget.showSelectedLabels ?? bottomTheme.showSelectedLabels,
|
||||||
showUnselectedLabels: widget.showUnselectedLabels ?? bottomTheme.showUnselectedLabels ?? _defaultShowUnselected,
|
showUnselectedLabels: widget.showUnselectedLabels ?? bottomTheme.showUnselectedLabels ?? _defaultShowUnselected,
|
||||||
indexLabel: localizations.tabLabel(tabIndex: i + 1, tabCount: widget.items.length),
|
indexLabel: localizations.tabLabel(tabIndex: i + 1, tabCount: widget.items.length),
|
||||||
mouseCursor: effectiveMouseCursor,
|
mouseCursor: effectiveMouseCursor,
|
||||||
|
@ -923,8 +927,8 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr
|
||||||
final BottomNavigationBarThemeData bottomTheme = BottomNavigationBarTheme.of(context);
|
final BottomNavigationBarThemeData bottomTheme = BottomNavigationBarTheme.of(context);
|
||||||
|
|
||||||
// Labels apply up to _bottomMargin padding. Remainder is media padding.
|
// Labels apply up to _bottomMargin padding. Remainder is media padding.
|
||||||
final double additionalBottomPadding = math.max(MediaQuery.of(context)!.padding.bottom - widget.selectedFontSize / 2.0, 0.0);
|
final double additionalBottomPadding = math.max(MediaQuery.of(context).padding.bottom - widget.selectedFontSize / 2.0, 0.0);
|
||||||
Color? backgroundColor;
|
Color backgroundColor;
|
||||||
switch (_effectiveType) {
|
switch (_effectiveType) {
|
||||||
case BottomNavigationBarType.fixed:
|
case BottomNavigationBarType.fixed:
|
||||||
backgroundColor = widget.backgroundColor ?? bottomTheme.backgroundColor;
|
backgroundColor = widget.backgroundColor ?? bottomTheme.backgroundColor;
|
||||||
|
@ -943,7 +947,7 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr
|
||||||
child: CustomPaint(
|
child: CustomPaint(
|
||||||
painter: _RadialPainter(
|
painter: _RadialPainter(
|
||||||
circles: _circles.toList(),
|
circles: _circles.toList(),
|
||||||
textDirection: Directionality.of(context)!,
|
textDirection: Directionality.of(context),
|
||||||
),
|
),
|
||||||
child: Material( // Splashes.
|
child: Material( // Splashes.
|
||||||
type: MaterialType.transparency,
|
type: MaterialType.transparency,
|
||||||
|
@ -966,10 +970,10 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr
|
||||||
// Describes an animating color splash circle.
|
// Describes an animating color splash circle.
|
||||||
class _Circle {
|
class _Circle {
|
||||||
_Circle({
|
_Circle({
|
||||||
required this.state,
|
@required this.state,
|
||||||
required this.index,
|
@required this.index,
|
||||||
required this.color,
|
@required this.color,
|
||||||
required TickerProvider vsync,
|
@required TickerProvider vsync,
|
||||||
}) : assert(state != null),
|
}) : assert(state != null),
|
||||||
assert(index != null),
|
assert(index != null),
|
||||||
assert(color != null) {
|
assert(color != null) {
|
||||||
|
@ -987,8 +991,8 @@ class _Circle {
|
||||||
final _BottomNavigationBarState state;
|
final _BottomNavigationBarState state;
|
||||||
final int index;
|
final int index;
|
||||||
final Color color;
|
final Color color;
|
||||||
late AnimationController controller;
|
AnimationController controller;
|
||||||
late CurvedAnimation animation;
|
CurvedAnimation animation;
|
||||||
|
|
||||||
double get horizontalLeadingOffset {
|
double get horizontalLeadingOffset {
|
||||||
double weightSum(Iterable<Animation<double>> animations) {
|
double weightSum(Iterable<Animation<double>> animations) {
|
||||||
|
@ -1013,8 +1017,8 @@ class _Circle {
|
||||||
// Paints the animating color splash circles.
|
// Paints the animating color splash circles.
|
||||||
class _RadialPainter extends CustomPainter {
|
class _RadialPainter extends CustomPainter {
|
||||||
_RadialPainter({
|
_RadialPainter({
|
||||||
required this.circles,
|
@required this.circles,
|
||||||
required this.textDirection,
|
@required this.textDirection,
|
||||||
}) : assert(circles != null),
|
}) : assert(circles != null),
|
||||||
assert(textDirection != null);
|
assert(textDirection != null);
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
// @dart = 2.8
|
||||||
|
|
||||||
import 'dart:ui' show lerpDouble;
|
import 'dart:ui' show lerpDouble;
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
@ -48,78 +50,78 @@ class BottomNavigationBarThemeData with Diagnosticable {
|
||||||
/// The color of the [BottomNavigationBar] itself.
|
/// The color of the [BottomNavigationBar] itself.
|
||||||
///
|
///
|
||||||
/// See [BottomNavigationBar.backgroundColor].
|
/// See [BottomNavigationBar.backgroundColor].
|
||||||
final Color? backgroundColor;
|
final Color backgroundColor;
|
||||||
|
|
||||||
/// The z-coordinate of the [BottomNavigationBar].
|
/// The z-coordinate of the [BottomNavigationBar].
|
||||||
///
|
///
|
||||||
/// See [BottomNavigationBar.elevation].
|
/// See [BottomNavigationBar.elevation].
|
||||||
final double? elevation;
|
final double elevation;
|
||||||
|
|
||||||
/// The size, opacity, and color of the icon in the currently selected
|
/// The size, opacity, and color of the icon in the currently selected
|
||||||
/// [BottomNavigationBarItem.icon].
|
/// [BottomNavigationBarItem.icon].
|
||||||
///
|
///
|
||||||
/// See [BottomNavigationBar.selectedIconTheme].
|
/// See [BottomNavigationBar.selectedIconTheme].
|
||||||
final IconThemeData? selectedIconTheme;
|
final IconThemeData selectedIconTheme;
|
||||||
|
|
||||||
/// The size, opacity, and color of the icon in the currently unselected
|
/// The size, opacity, and color of the icon in the currently unselected
|
||||||
/// [BottomNavigationBarItem.icon]s.
|
/// [BottomNavigationBarItem.icon]s.
|
||||||
///
|
///
|
||||||
/// See [BottomNavigationBar.unselectedIconTheme].
|
/// See [BottomNavigationBar.unselectedIconTheme].
|
||||||
final IconThemeData? unselectedIconTheme;
|
final IconThemeData unselectedIconTheme;
|
||||||
|
|
||||||
/// The color of the selected [BottomNavigationBarItem.icon] and
|
/// The color of the selected [BottomNavigationBarItem.icon] and
|
||||||
/// [BottomNavigationBarItem.title].
|
/// [BottomNavigationBarItem.title].
|
||||||
///
|
///
|
||||||
/// See [BottomNavigationBar.selectedItemColor].
|
/// See [BottomNavigationBar.selectedItemColor].
|
||||||
final Color? selectedItemColor;
|
final Color selectedItemColor;
|
||||||
|
|
||||||
/// The color of the unselected [BottomNavigationBarItem.icon] and
|
/// The color of the unselected [BottomNavigationBarItem.icon] and
|
||||||
/// [BottomNavigationBarItem.title]s.
|
/// [BottomNavigationBarItem.title]s.
|
||||||
///
|
///
|
||||||
/// See [BottomNavigationBar.unselectedItemColor].
|
/// See [BottomNavigationBar.unselectedItemColor].
|
||||||
final Color? unselectedItemColor;
|
final Color unselectedItemColor;
|
||||||
|
|
||||||
/// The [TextStyle] of the [BottomNavigationBarItem] labels when they are
|
/// The [TextStyle] of the [BottomNavigationBarItem] labels when they are
|
||||||
/// selected.
|
/// selected.
|
||||||
///
|
///
|
||||||
/// See [BottomNavigationBar.selectedLabelStyle].
|
/// See [BottomNavigationBar.selectedLabelStyle].
|
||||||
final TextStyle? selectedLabelStyle;
|
final TextStyle selectedLabelStyle;
|
||||||
|
|
||||||
/// The [TextStyle] of the [BottomNavigationBarItem] labels when they are not
|
/// The [TextStyle] of the [BottomNavigationBarItem] labels when they are not
|
||||||
/// selected.
|
/// selected.
|
||||||
///
|
///
|
||||||
/// See [BottomNavigationBar.unselectedLabelStyle].
|
/// See [BottomNavigationBar.unselectedLabelStyle].
|
||||||
final TextStyle? unselectedLabelStyle;
|
final TextStyle unselectedLabelStyle;
|
||||||
|
|
||||||
/// Whether the labels are shown for the unselected [BottomNavigationBarItem]s.
|
/// Whether the labels are shown for the unselected [BottomNavigationBarItem]s.
|
||||||
///
|
///
|
||||||
/// See [BottomNavigationBar.showSelectedLabels].
|
/// See [BottomNavigationBar.showSelectedLabels].
|
||||||
final bool? showSelectedLabels;
|
final bool showSelectedLabels;
|
||||||
|
|
||||||
/// Whether the labels are shown for the selected [BottomNavigationBarItem].
|
/// Whether the labels are shown for the selected [BottomNavigationBarItem].
|
||||||
///
|
///
|
||||||
/// See [BottomNavigationBar.showUnselectedLabels].
|
/// See [BottomNavigationBar.showUnselectedLabels].
|
||||||
final bool? showUnselectedLabels;
|
final bool showUnselectedLabels;
|
||||||
|
|
||||||
/// Defines the layout and behavior of a [BottomNavigationBar].
|
/// Defines the layout and behavior of a [BottomNavigationBar].
|
||||||
///
|
///
|
||||||
/// See [BottomNavigationBar.type].
|
/// See [BottomNavigationBar.type].
|
||||||
final BottomNavigationBarType? type;
|
final BottomNavigationBarType type;
|
||||||
|
|
||||||
/// Creates a copy of this object but with the given fields replaced with the
|
/// Creates a copy of this object but with the given fields replaced with the
|
||||||
/// new values.
|
/// new values.
|
||||||
BottomNavigationBarThemeData copyWith({
|
BottomNavigationBarThemeData copyWith({
|
||||||
Color? backgroundColor,
|
Color backgroundColor,
|
||||||
double? elevation,
|
double elevation,
|
||||||
IconThemeData? selectedIconTheme,
|
IconThemeData selectedIconTheme,
|
||||||
IconThemeData? unselectedIconTheme,
|
IconThemeData unselectedIconTheme,
|
||||||
Color? selectedItemColor,
|
Color selectedItemColor,
|
||||||
Color? unselectedItemColor,
|
Color unselectedItemColor,
|
||||||
TextStyle? selectedLabelStyle,
|
TextStyle selectedLabelStyle,
|
||||||
TextStyle? unselectedLabelStyle,
|
TextStyle unselectedLabelStyle,
|
||||||
bool? showSelectedLabels,
|
bool showSelectedLabels,
|
||||||
bool? showUnselectedLabels,
|
bool showUnselectedLabels,
|
||||||
BottomNavigationBarType? type,
|
BottomNavigationBarType type,
|
||||||
}) {
|
}) {
|
||||||
return BottomNavigationBarThemeData(
|
return BottomNavigationBarThemeData(
|
||||||
backgroundColor: backgroundColor ?? this.backgroundColor,
|
backgroundColor: backgroundColor ?? this.backgroundColor,
|
||||||
|
@ -141,7 +143,7 @@ class BottomNavigationBarThemeData with Diagnosticable {
|
||||||
/// The argument `t` must not be null.
|
/// The argument `t` must not be null.
|
||||||
///
|
///
|
||||||
/// {@macro dart.ui.shadow.lerp}
|
/// {@macro dart.ui.shadow.lerp}
|
||||||
static BottomNavigationBarThemeData lerp(BottomNavigationBarThemeData? a, BottomNavigationBarThemeData? b, double t) {
|
static BottomNavigationBarThemeData lerp(BottomNavigationBarThemeData a, BottomNavigationBarThemeData b, double t) {
|
||||||
assert(t != null);
|
assert(t != null);
|
||||||
return BottomNavigationBarThemeData(
|
return BottomNavigationBarThemeData(
|
||||||
backgroundColor: Color.lerp(a?.backgroundColor, b?.backgroundColor, t),
|
backgroundColor: Color.lerp(a?.backgroundColor, b?.backgroundColor, t),
|
||||||
|
@ -233,9 +235,9 @@ class BottomNavigationBarTheme extends InheritedWidget {
|
||||||
///
|
///
|
||||||
/// The [data] must not be null.
|
/// The [data] must not be null.
|
||||||
const BottomNavigationBarTheme({
|
const BottomNavigationBarTheme({
|
||||||
Key? key,
|
Key key,
|
||||||
required this.data,
|
@required this.data,
|
||||||
required Widget child,
|
Widget child,
|
||||||
}) : assert(data != null), super(key: key, child: child);
|
}) : assert(data != null), super(key: key, child: child);
|
||||||
|
|
||||||
/// The properties used for all descendant [BottomNavigationBar] widgets.
|
/// The properties used for all descendant [BottomNavigationBar] widgets.
|
||||||
|
@ -252,8 +254,8 @@ class BottomNavigationBarTheme extends InheritedWidget {
|
||||||
/// BottomNavigationBarThemeData theme = BottomNavigationBarTheme.of(context);
|
/// BottomNavigationBarThemeData theme = BottomNavigationBarTheme.of(context);
|
||||||
/// ```
|
/// ```
|
||||||
static BottomNavigationBarThemeData of(BuildContext context) {
|
static BottomNavigationBarThemeData of(BuildContext context) {
|
||||||
final BottomNavigationBarTheme? bottomNavTheme = context.dependOnInheritedWidgetOfExactType<BottomNavigationBarTheme>();
|
final BottomNavigationBarTheme bottomNavTheme = context.dependOnInheritedWidgetOfExactType<BottomNavigationBarTheme>();
|
||||||
return bottomNavTheme?.data ?? Theme.of(context)!.bottomNavigationBarTheme;
|
return bottomNavTheme?.data ?? Theme.of(context).bottomNavigationBarTheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
// @dart = 2.8
|
||||||
|
|
||||||
import 'dart:ui' show lerpDouble;
|
import 'dart:ui' show lerpDouble;
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
@ -33,7 +35,7 @@ typedef BottomSheetDragStartHandler = void Function(DragStartDetails details);
|
||||||
/// Used by [BottomSheet.onDragEnd].
|
/// Used by [BottomSheet.onDragEnd].
|
||||||
typedef BottomSheetDragEndHandler = void Function(
|
typedef BottomSheetDragEndHandler = void Function(
|
||||||
DragEndDetails details, {
|
DragEndDetails details, {
|
||||||
required bool isClosing,
|
bool isClosing,
|
||||||
});
|
});
|
||||||
|
|
||||||
/// A material design bottom sheet.
|
/// A material design bottom sheet.
|
||||||
|
@ -70,7 +72,7 @@ class BottomSheet extends StatefulWidget {
|
||||||
/// [ScaffoldState.showBottomSheet], for persistent bottom sheets, or by
|
/// [ScaffoldState.showBottomSheet], for persistent bottom sheets, or by
|
||||||
/// [showModalBottomSheet], for modal bottom sheets.
|
/// [showModalBottomSheet], for modal bottom sheets.
|
||||||
const BottomSheet({
|
const BottomSheet({
|
||||||
Key? key,
|
Key key,
|
||||||
this.animationController,
|
this.animationController,
|
||||||
this.enableDrag = true,
|
this.enableDrag = true,
|
||||||
this.onDragStart,
|
this.onDragStart,
|
||||||
|
@ -79,8 +81,8 @@ class BottomSheet extends StatefulWidget {
|
||||||
this.elevation,
|
this.elevation,
|
||||||
this.shape,
|
this.shape,
|
||||||
this.clipBehavior,
|
this.clipBehavior,
|
||||||
required this.onClosing,
|
@required this.onClosing,
|
||||||
required this.builder,
|
@required this.builder,
|
||||||
}) : assert(enableDrag != null),
|
}) : assert(enableDrag != null),
|
||||||
assert(onClosing != null),
|
assert(onClosing != null),
|
||||||
assert(builder != null),
|
assert(builder != null),
|
||||||
|
@ -92,7 +94,7 @@ class BottomSheet extends StatefulWidget {
|
||||||
///
|
///
|
||||||
/// The BottomSheet widget will manipulate the position of this animation, it
|
/// The BottomSheet widget will manipulate the position of this animation, it
|
||||||
/// is not just a passive observer.
|
/// is not just a passive observer.
|
||||||
final AnimationController? animationController;
|
final AnimationController animationController;
|
||||||
|
|
||||||
/// Called when the bottom sheet begins to close.
|
/// Called when the bottom sheet begins to close.
|
||||||
///
|
///
|
||||||
|
@ -118,7 +120,7 @@ class BottomSheet extends StatefulWidget {
|
||||||
///
|
///
|
||||||
/// Would typically be used to change the bottom sheet animation curve so
|
/// Would typically be used to change the bottom sheet animation curve so
|
||||||
/// that it tracks the user's finger accurately.
|
/// that it tracks the user's finger accurately.
|
||||||
final BottomSheetDragStartHandler? onDragStart;
|
final BottomSheetDragStartHandler onDragStart;
|
||||||
|
|
||||||
/// Called when the user stops dragging the bottom sheet, if [enableDrag]
|
/// Called when the user stops dragging the bottom sheet, if [enableDrag]
|
||||||
/// is true.
|
/// is true.
|
||||||
|
@ -126,28 +128,28 @@ class BottomSheet extends StatefulWidget {
|
||||||
/// Would typically be used to reset the bottom sheet animation curve, so
|
/// Would typically be used to reset the bottom sheet animation curve, so
|
||||||
/// that it animates non-linearly. Called before [onClosing] if the bottom
|
/// that it animates non-linearly. Called before [onClosing] if the bottom
|
||||||
/// sheet is closing.
|
/// sheet is closing.
|
||||||
final BottomSheetDragEndHandler? onDragEnd;
|
final BottomSheetDragEndHandler onDragEnd;
|
||||||
|
|
||||||
/// The bottom sheet's background color.
|
/// The bottom sheet's background color.
|
||||||
///
|
///
|
||||||
/// Defines the bottom sheet's [Material.color].
|
/// Defines the bottom sheet's [Material.color].
|
||||||
///
|
///
|
||||||
/// Defaults to null and falls back to [Material]'s default.
|
/// Defaults to null and falls back to [Material]'s default.
|
||||||
final Color? backgroundColor;
|
final Color backgroundColor;
|
||||||
|
|
||||||
/// The z-coordinate at which to place this material relative to its parent.
|
/// The z-coordinate at which to place this material relative to its parent.
|
||||||
///
|
///
|
||||||
/// This controls the size of the shadow below the material.
|
/// This controls the size of the shadow below the material.
|
||||||
///
|
///
|
||||||
/// Defaults to 0. The value is non-negative.
|
/// Defaults to 0. The value is non-negative.
|
||||||
final double? elevation;
|
final double elevation;
|
||||||
|
|
||||||
/// The shape of the bottom sheet.
|
/// The shape of the bottom sheet.
|
||||||
///
|
///
|
||||||
/// Defines the bottom sheet's [Material.shape].
|
/// Defines the bottom sheet's [Material.shape].
|
||||||
///
|
///
|
||||||
/// Defaults to null and falls back to [Material]'s default.
|
/// Defaults to null and falls back to [Material]'s default.
|
||||||
final ShapeBorder? shape;
|
final ShapeBorder shape;
|
||||||
|
|
||||||
/// {@macro flutter.widgets.Clip}
|
/// {@macro flutter.widgets.Clip}
|
||||||
///
|
///
|
||||||
|
@ -161,7 +163,7 @@ class BottomSheet extends StatefulWidget {
|
||||||
/// If this property is null then [BottomSheetThemeData.clipBehavior] of
|
/// If this property is null then [BottomSheetThemeData.clipBehavior] of
|
||||||
/// [ThemeData.bottomSheetTheme] is used. If that's null then the behavior
|
/// [ThemeData.bottomSheetTheme] is used. If that's null then the behavior
|
||||||
/// will be [Clip.none].
|
/// will be [Clip.none].
|
||||||
final Clip? clipBehavior;
|
final Clip clipBehavior;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_BottomSheetState createState() => _BottomSheetState();
|
_BottomSheetState createState() => _BottomSheetState();
|
||||||
|
@ -187,15 +189,15 @@ class _BottomSheetState extends State<BottomSheet> {
|
||||||
final GlobalKey _childKey = GlobalKey(debugLabel: 'BottomSheet child');
|
final GlobalKey _childKey = GlobalKey(debugLabel: 'BottomSheet child');
|
||||||
|
|
||||||
double get _childHeight {
|
double get _childHeight {
|
||||||
final RenderBox renderBox = _childKey.currentContext!.findRenderObject() as RenderBox;
|
final RenderBox renderBox = _childKey.currentContext.findRenderObject() as RenderBox;
|
||||||
return renderBox.size.height;
|
return renderBox.size.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool get _dismissUnderway => widget.animationController!.status == AnimationStatus.reverse;
|
bool get _dismissUnderway => widget.animationController.status == AnimationStatus.reverse;
|
||||||
|
|
||||||
void _handleDragStart(DragStartDetails details) {
|
void _handleDragStart(DragStartDetails details) {
|
||||||
if (widget.onDragStart != null) {
|
if (widget.onDragStart != null) {
|
||||||
widget.onDragStart!(details);
|
widget.onDragStart(details);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,7 +205,7 @@ class _BottomSheetState extends State<BottomSheet> {
|
||||||
assert(widget.enableDrag);
|
assert(widget.enableDrag);
|
||||||
if (_dismissUnderway)
|
if (_dismissUnderway)
|
||||||
return;
|
return;
|
||||||
widget.animationController!.value -= details.primaryDelta! / _childHeight;
|
widget.animationController.value -= details.primaryDelta / (_childHeight ?? details.primaryDelta);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handleDragEnd(DragEndDetails details) {
|
void _handleDragEnd(DragEndDetails details) {
|
||||||
|
@ -213,22 +215,22 @@ class _BottomSheetState extends State<BottomSheet> {
|
||||||
bool isClosing = false;
|
bool isClosing = false;
|
||||||
if (details.velocity.pixelsPerSecond.dy > _minFlingVelocity) {
|
if (details.velocity.pixelsPerSecond.dy > _minFlingVelocity) {
|
||||||
final double flingVelocity = -details.velocity.pixelsPerSecond.dy / _childHeight;
|
final double flingVelocity = -details.velocity.pixelsPerSecond.dy / _childHeight;
|
||||||
if (widget.animationController!.value > 0.0) {
|
if (widget.animationController.value > 0.0) {
|
||||||
widget.animationController!.fling(velocity: flingVelocity);
|
widget.animationController.fling(velocity: flingVelocity);
|
||||||
}
|
}
|
||||||
if (flingVelocity < 0.0) {
|
if (flingVelocity < 0.0) {
|
||||||
isClosing = true;
|
isClosing = true;
|
||||||
}
|
}
|
||||||
} else if (widget.animationController!.value < _closeProgressThreshold) {
|
} else if (widget.animationController.value < _closeProgressThreshold) {
|
||||||
if (widget.animationController!.value > 0.0)
|
if (widget.animationController.value > 0.0)
|
||||||
widget.animationController!.fling(velocity: -1.0);
|
widget.animationController.fling(velocity: -1.0);
|
||||||
isClosing = true;
|
isClosing = true;
|
||||||
} else {
|
} else {
|
||||||
widget.animationController!.forward();
|
widget.animationController.forward();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (widget.onDragEnd != null) {
|
if (widget.onDragEnd != null) {
|
||||||
widget.onDragEnd!(
|
widget.onDragEnd(
|
||||||
details,
|
details,
|
||||||
isClosing: isClosing,
|
isClosing: isClosing,
|
||||||
);
|
);
|
||||||
|
@ -248,10 +250,10 @@ class _BottomSheetState extends State<BottomSheet> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final BottomSheetThemeData bottomSheetTheme = Theme.of(context)!.bottomSheetTheme;
|
final BottomSheetThemeData bottomSheetTheme = Theme.of(context).bottomSheetTheme;
|
||||||
final Color? color = widget.backgroundColor ?? bottomSheetTheme.backgroundColor;
|
final Color color = widget.backgroundColor ?? bottomSheetTheme.backgroundColor;
|
||||||
final double elevation = widget.elevation ?? bottomSheetTheme.elevation ?? 0;
|
final double elevation = widget.elevation ?? bottomSheetTheme.elevation ?? 0;
|
||||||
final ShapeBorder? shape = widget.shape ?? bottomSheetTheme.shape;
|
final ShapeBorder shape = widget.shape ?? bottomSheetTheme.shape;
|
||||||
final Clip clipBehavior = widget.clipBehavior ?? bottomSheetTheme.clipBehavior ?? Clip.none;
|
final Clip clipBehavior = widget.clipBehavior ?? bottomSheetTheme.clipBehavior ?? Clip.none;
|
||||||
|
|
||||||
final Widget bottomSheet = Material(
|
final Widget bottomSheet = Material(
|
||||||
|
@ -312,7 +314,7 @@ class _ModalBottomSheetLayout extends SingleChildLayoutDelegate {
|
||||||
|
|
||||||
class _ModalBottomSheet<T> extends StatefulWidget {
|
class _ModalBottomSheet<T> extends StatefulWidget {
|
||||||
const _ModalBottomSheet({
|
const _ModalBottomSheet({
|
||||||
Key? key,
|
Key key,
|
||||||
this.route,
|
this.route,
|
||||||
this.backgroundColor,
|
this.backgroundColor,
|
||||||
this.elevation,
|
this.elevation,
|
||||||
|
@ -324,12 +326,12 @@ class _ModalBottomSheet<T> extends StatefulWidget {
|
||||||
assert(enableDrag != null),
|
assert(enableDrag != null),
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
final _ModalBottomSheetRoute<T>? route;
|
final _ModalBottomSheetRoute<T> route;
|
||||||
final bool isScrollControlled;
|
final bool isScrollControlled;
|
||||||
final Color? backgroundColor;
|
final Color backgroundColor;
|
||||||
final double? elevation;
|
final double elevation;
|
||||||
final ShapeBorder? shape;
|
final ShapeBorder shape;
|
||||||
final Clip? clipBehavior;
|
final Clip clipBehavior;
|
||||||
final bool enableDrag;
|
final bool enableDrag;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -340,7 +342,7 @@ class _ModalBottomSheetState<T> extends State<_ModalBottomSheet<T>> {
|
||||||
ParametricCurve<double> animationCurve = _modalBottomSheetCurve;
|
ParametricCurve<double> animationCurve = _modalBottomSheetCurve;
|
||||||
|
|
||||||
String _getRouteLabel(MaterialLocalizations localizations) {
|
String _getRouteLabel(MaterialLocalizations localizations) {
|
||||||
switch (Theme.of(context)!.platform) {
|
switch (Theme.of(context).platform) {
|
||||||
case TargetPlatform.iOS:
|
case TargetPlatform.iOS:
|
||||||
case TargetPlatform.macOS:
|
case TargetPlatform.macOS:
|
||||||
return '';
|
return '';
|
||||||
|
@ -350,6 +352,7 @@ class _ModalBottomSheetState<T> extends State<_ModalBottomSheet<T>> {
|
||||||
case TargetPlatform.windows:
|
case TargetPlatform.windows:
|
||||||
return localizations.dialogLabel;
|
return localizations.dialogLabel;
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleDragStart(DragStartDetails details) {
|
void handleDragStart(DragStartDetails details) {
|
||||||
|
@ -357,10 +360,10 @@ class _ModalBottomSheetState<T> extends State<_ModalBottomSheet<T>> {
|
||||||
animationCurve = Curves.linear;
|
animationCurve = Curves.linear;
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleDragEnd(DragEndDetails details, {bool? isClosing}) {
|
void handleDragEnd(DragEndDetails details, {bool isClosing}) {
|
||||||
// Allow the bottom sheet to animate smoothly from its current position.
|
// Allow the bottom sheet to animate smoothly from its current position.
|
||||||
animationCurve = _BottomSheetSuspendedCurve(
|
animationCurve = _BottomSheetSuspendedCurve(
|
||||||
widget.route!.animation!.value,
|
widget.route.animation.value,
|
||||||
curve: _modalBottomSheetCurve,
|
curve: _modalBottomSheetCurve,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -369,20 +372,20 @@ class _ModalBottomSheetState<T> extends State<_ModalBottomSheet<T>> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
assert(debugCheckHasMediaQuery(context));
|
assert(debugCheckHasMediaQuery(context));
|
||||||
assert(debugCheckHasMaterialLocalizations(context));
|
assert(debugCheckHasMaterialLocalizations(context));
|
||||||
final MediaQueryData? mediaQuery = MediaQuery.of(context);
|
final MediaQueryData mediaQuery = MediaQuery.of(context);
|
||||||
final MaterialLocalizations localizations = MaterialLocalizations.of(context)!;
|
final MaterialLocalizations localizations = MaterialLocalizations.of(context);
|
||||||
final String routeLabel = _getRouteLabel(localizations);
|
final String routeLabel = _getRouteLabel(localizations);
|
||||||
|
|
||||||
return AnimatedBuilder(
|
return AnimatedBuilder(
|
||||||
animation: widget.route!.animation!,
|
animation: widget.route.animation,
|
||||||
child: BottomSheet(
|
child: BottomSheet(
|
||||||
animationController: widget.route!._animationController,
|
animationController: widget.route._animationController,
|
||||||
onClosing: () {
|
onClosing: () {
|
||||||
if (widget.route!.isCurrent) {
|
if (widget.route.isCurrent) {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
builder: widget.route!.builder!,
|
builder: widget.route.builder,
|
||||||
backgroundColor: widget.backgroundColor,
|
backgroundColor: widget.backgroundColor,
|
||||||
elevation: widget.elevation,
|
elevation: widget.elevation,
|
||||||
shape: widget.shape,
|
shape: widget.shape,
|
||||||
|
@ -391,11 +394,11 @@ class _ModalBottomSheetState<T> extends State<_ModalBottomSheet<T>> {
|
||||||
onDragStart: handleDragStart,
|
onDragStart: handleDragStart,
|
||||||
onDragEnd: handleDragEnd,
|
onDragEnd: handleDragEnd,
|
||||||
),
|
),
|
||||||
builder: (BuildContext context, Widget? child) {
|
builder: (BuildContext context, Widget child) {
|
||||||
// Disable the initial animation when accessible navigation is on so
|
// Disable the initial animation when accessible navigation is on so
|
||||||
// that the semantics are added to the tree at the correct time.
|
// that the semantics are added to the tree at the correct time.
|
||||||
final double animationValue = animationCurve.transform(
|
final double animationValue = animationCurve.transform(
|
||||||
mediaQuery!.accessibleNavigation ? 1.0 : widget.route!.animation!.value
|
mediaQuery.accessibleNavigation ? 1.0 : widget.route.animation.value
|
||||||
);
|
);
|
||||||
return Semantics(
|
return Semantics(
|
||||||
scopesRoute: true,
|
scopesRoute: true,
|
||||||
|
@ -426,21 +429,21 @@ class _ModalBottomSheetRoute<T> extends PopupRoute<T> {
|
||||||
this.modalBarrierColor,
|
this.modalBarrierColor,
|
||||||
this.isDismissible = true,
|
this.isDismissible = true,
|
||||||
this.enableDrag = true,
|
this.enableDrag = true,
|
||||||
required this.isScrollControlled,
|
@required this.isScrollControlled,
|
||||||
RouteSettings? settings,
|
RouteSettings settings,
|
||||||
}) : assert(isScrollControlled != null),
|
}) : assert(isScrollControlled != null),
|
||||||
assert(isDismissible != null),
|
assert(isDismissible != null),
|
||||||
assert(enableDrag != null),
|
assert(enableDrag != null),
|
||||||
super(settings: settings);
|
super(settings: settings);
|
||||||
|
|
||||||
final WidgetBuilder? builder;
|
final WidgetBuilder builder;
|
||||||
final ThemeData? theme;
|
final ThemeData theme;
|
||||||
final bool isScrollControlled;
|
final bool isScrollControlled;
|
||||||
final Color? backgroundColor;
|
final Color backgroundColor;
|
||||||
final double? elevation;
|
final double elevation;
|
||||||
final ShapeBorder? shape;
|
final ShapeBorder shape;
|
||||||
final Clip? clipBehavior;
|
final Clip clipBehavior;
|
||||||
final Color? modalBarrierColor;
|
final Color modalBarrierColor;
|
||||||
final bool isDismissible;
|
final bool isDismissible;
|
||||||
final bool enableDrag;
|
final bool enableDrag;
|
||||||
|
|
||||||
|
@ -454,23 +457,23 @@ class _ModalBottomSheetRoute<T> extends PopupRoute<T> {
|
||||||
bool get barrierDismissible => isDismissible;
|
bool get barrierDismissible => isDismissible;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final String? barrierLabel;
|
final String barrierLabel;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Color get barrierColor => modalBarrierColor ?? Colors.black54;
|
Color get barrierColor => modalBarrierColor ?? Colors.black54;
|
||||||
|
|
||||||
AnimationController? _animationController;
|
AnimationController _animationController;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
AnimationController createAnimationController() {
|
AnimationController createAnimationController() {
|
||||||
assert(_animationController == null);
|
assert(_animationController == null);
|
||||||
_animationController = BottomSheet.createAnimationController(navigator!.overlay!);
|
_animationController = BottomSheet.createAnimationController(navigator.overlay);
|
||||||
return _animationController!;
|
return _animationController;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
|
Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
|
||||||
final BottomSheetThemeData sheetTheme = theme?.bottomSheetTheme ?? Theme.of(context)!.bottomSheetTheme;
|
final BottomSheetThemeData sheetTheme = theme?.bottomSheetTheme ?? Theme.of(context).bottomSheetTheme;
|
||||||
// By definition, the bottom sheet is aligned to the bottom of the page
|
// By definition, the bottom sheet is aligned to the bottom of the page
|
||||||
// and isn't exposed to the top padding of the MediaQuery.
|
// and isn't exposed to the top padding of the MediaQuery.
|
||||||
Widget bottomSheet = MediaQuery.removePadding(
|
Widget bottomSheet = MediaQuery.removePadding(
|
||||||
|
@ -478,8 +481,8 @@ class _ModalBottomSheetRoute<T> extends PopupRoute<T> {
|
||||||
removeTop: true,
|
removeTop: true,
|
||||||
child: _ModalBottomSheet<T>(
|
child: _ModalBottomSheet<T>(
|
||||||
route: this,
|
route: this,
|
||||||
backgroundColor: backgroundColor ?? sheetTheme.modalBackgroundColor ?? sheetTheme.backgroundColor,
|
backgroundColor: backgroundColor ?? sheetTheme?.modalBackgroundColor ?? sheetTheme?.backgroundColor,
|
||||||
elevation: elevation ?? sheetTheme.modalElevation ?? sheetTheme.elevation,
|
elevation: elevation ?? sheetTheme?.modalElevation ?? sheetTheme?.elevation,
|
||||||
shape: shape,
|
shape: shape,
|
||||||
clipBehavior: clipBehavior,
|
clipBehavior: clipBehavior,
|
||||||
isScrollControlled: isScrollControlled,
|
isScrollControlled: isScrollControlled,
|
||||||
|
@ -487,7 +490,7 @@ class _ModalBottomSheetRoute<T> extends PopupRoute<T> {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
if (theme != null)
|
if (theme != null)
|
||||||
bottomSheet = Theme(data: theme!, child: bottomSheet);
|
bottomSheet = Theme(data: theme, child: bottomSheet);
|
||||||
return bottomSheet;
|
return bottomSheet;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -541,7 +544,7 @@ class _BottomSheetSuspendedCurve extends ParametricCurve<double> {
|
||||||
|
|
||||||
final double curveProgress = (t - startingPoint) / (1 - startingPoint);
|
final double curveProgress = (t - startingPoint) / (1 - startingPoint);
|
||||||
final double transformed = curve.transform(curveProgress);
|
final double transformed = curve.transform(curveProgress);
|
||||||
return lerpDouble(startingPoint, 1, transformed)!;
|
return lerpDouble(startingPoint, 1, transformed);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -645,18 +648,18 @@ class _BottomSheetSuspendedCurve extends ParametricCurve<double> {
|
||||||
/// that grows and then becomes scrollable once it reaches its maximum size.
|
/// that grows and then becomes scrollable once it reaches its maximum size.
|
||||||
/// * <https://material.io/design/components/sheets-bottom.html#modal-bottom-sheet>
|
/// * <https://material.io/design/components/sheets-bottom.html#modal-bottom-sheet>
|
||||||
Future<T> showModalBottomSheet<T>({
|
Future<T> showModalBottomSheet<T>({
|
||||||
required BuildContext context,
|
@required BuildContext context,
|
||||||
required WidgetBuilder builder,
|
@required WidgetBuilder builder,
|
||||||
Color? backgroundColor,
|
Color backgroundColor,
|
||||||
double? elevation,
|
double elevation,
|
||||||
ShapeBorder? shape,
|
ShapeBorder shape,
|
||||||
Clip? clipBehavior,
|
Clip clipBehavior,
|
||||||
Color? barrierColor,
|
Color barrierColor,
|
||||||
bool isScrollControlled = false,
|
bool isScrollControlled = false,
|
||||||
bool useRootNavigator = false,
|
bool useRootNavigator = false,
|
||||||
bool isDismissible = true,
|
bool isDismissible = true,
|
||||||
bool enableDrag = true,
|
bool enableDrag = true,
|
||||||
RouteSettings? routeSettings,
|
RouteSettings routeSettings,
|
||||||
}) {
|
}) {
|
||||||
assert(context != null);
|
assert(context != null);
|
||||||
assert(builder != null);
|
assert(builder != null);
|
||||||
|
@ -667,11 +670,11 @@ Future<T> showModalBottomSheet<T>({
|
||||||
assert(debugCheckHasMediaQuery(context));
|
assert(debugCheckHasMediaQuery(context));
|
||||||
assert(debugCheckHasMaterialLocalizations(context));
|
assert(debugCheckHasMaterialLocalizations(context));
|
||||||
|
|
||||||
return Navigator.of(context, rootNavigator: useRootNavigator)!.push(_ModalBottomSheetRoute<T>(
|
return Navigator.of(context, rootNavigator: useRootNavigator).push(_ModalBottomSheetRoute<T>(
|
||||||
builder: builder,
|
builder: builder,
|
||||||
theme: Theme.of(context, shadowThemeOnly: true),
|
theme: Theme.of(context, shadowThemeOnly: true),
|
||||||
isScrollControlled: isScrollControlled,
|
isScrollControlled: isScrollControlled,
|
||||||
barrierLabel: MaterialLocalizations.of(context)!.modalBarrierDismissLabel,
|
barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
|
||||||
backgroundColor: backgroundColor,
|
backgroundColor: backgroundColor,
|
||||||
elevation: elevation,
|
elevation: elevation,
|
||||||
shape: shape,
|
shape: shape,
|
||||||
|
@ -723,18 +726,18 @@ Future<T> showModalBottomSheet<T>({
|
||||||
/// * [Scaffold.of], for information about how to obtain the [BuildContext].
|
/// * [Scaffold.of], for information about how to obtain the [BuildContext].
|
||||||
/// * <https://material.io/design/components/sheets-bottom.html#standard-bottom-sheet>
|
/// * <https://material.io/design/components/sheets-bottom.html#standard-bottom-sheet>
|
||||||
PersistentBottomSheetController<T> showBottomSheet<T>({
|
PersistentBottomSheetController<T> showBottomSheet<T>({
|
||||||
required BuildContext context,
|
@required BuildContext context,
|
||||||
required WidgetBuilder builder,
|
@required WidgetBuilder builder,
|
||||||
Color? backgroundColor,
|
Color backgroundColor,
|
||||||
double? elevation,
|
double elevation,
|
||||||
ShapeBorder? shape,
|
ShapeBorder shape,
|
||||||
Clip? clipBehavior,
|
Clip clipBehavior,
|
||||||
}) {
|
}) {
|
||||||
assert(context != null);
|
assert(context != null);
|
||||||
assert(builder != null);
|
assert(builder != null);
|
||||||
assert(debugCheckHasScaffold(context));
|
assert(debugCheckHasScaffold(context));
|
||||||
|
|
||||||
return Scaffold.of(context)!.showBottomSheet<T>(
|
return Scaffold.of(context).showBottomSheet<T>(
|
||||||
builder,
|
builder,
|
||||||
backgroundColor: backgroundColor,
|
backgroundColor: backgroundColor,
|
||||||
elevation: elevation,
|
elevation: elevation,
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
// @dart = 2.8
|
||||||
|
|
||||||
import 'dart:math' as math;
|
import 'dart:math' as math;
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
@ -49,8 +51,8 @@ class RawMaterialButton extends StatefulWidget {
|
||||||
/// [elevation], [focusElevation], [hoverElevation], [highlightElevation], and
|
/// [elevation], [focusElevation], [hoverElevation], [highlightElevation], and
|
||||||
/// [disabledElevation] must be non-negative.
|
/// [disabledElevation] must be non-negative.
|
||||||
const RawMaterialButton({
|
const RawMaterialButton({
|
||||||
Key? key,
|
Key key,
|
||||||
required this.onPressed,
|
@required this.onPressed,
|
||||||
this.onLongPress,
|
this.onLongPress,
|
||||||
this.onHighlightChanged,
|
this.onHighlightChanged,
|
||||||
this.mouseCursor,
|
this.mouseCursor,
|
||||||
|
@ -73,7 +75,7 @@ class RawMaterialButton extends StatefulWidget {
|
||||||
this.clipBehavior = Clip.none,
|
this.clipBehavior = Clip.none,
|
||||||
this.focusNode,
|
this.focusNode,
|
||||||
this.autofocus = false,
|
this.autofocus = false,
|
||||||
MaterialTapTargetSize? materialTapTargetSize,
|
MaterialTapTargetSize materialTapTargetSize,
|
||||||
this.child,
|
this.child,
|
||||||
this.enableFeedback = true,
|
this.enableFeedback = true,
|
||||||
}) : materialTapTargetSize = materialTapTargetSize ?? MaterialTapTargetSize.padded,
|
}) : materialTapTargetSize = materialTapTargetSize ?? MaterialTapTargetSize.padded,
|
||||||
|
@ -97,7 +99,7 @@ class RawMaterialButton extends StatefulWidget {
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [enabled], which is true if the button is enabled.
|
/// * [enabled], which is true if the button is enabled.
|
||||||
final VoidCallback? onPressed;
|
final VoidCallback onPressed;
|
||||||
|
|
||||||
/// Called when the button is long-pressed.
|
/// Called when the button is long-pressed.
|
||||||
///
|
///
|
||||||
|
@ -106,7 +108,7 @@ class RawMaterialButton extends StatefulWidget {
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [enabled], which is true if the button is enabled.
|
/// * [enabled], which is true if the button is enabled.
|
||||||
final VoidCallback? onLongPress;
|
final VoidCallback onLongPress;
|
||||||
|
|
||||||
/// Called by the underlying [InkWell] widget's [InkWell.onHighlightChanged]
|
/// Called by the underlying [InkWell] widget's [InkWell.onHighlightChanged]
|
||||||
/// callback.
|
/// callback.
|
||||||
|
@ -114,7 +116,7 @@ class RawMaterialButton extends StatefulWidget {
|
||||||
/// If [onPressed] changes from null to non-null while a gesture is ongoing,
|
/// If [onPressed] changes from null to non-null while a gesture is ongoing,
|
||||||
/// this can fire during the build phase (in which case calling
|
/// this can fire during the build phase (in which case calling
|
||||||
/// [State.setState] is not allowed).
|
/// [State.setState] is not allowed).
|
||||||
final ValueChanged<bool>? onHighlightChanged;
|
final ValueChanged<bool> onHighlightChanged;
|
||||||
|
|
||||||
/// {@template flutter.material.button.mouseCursor}
|
/// {@template flutter.material.button.mouseCursor}
|
||||||
/// The cursor for a mouse pointer when it enters or is hovering over the
|
/// The cursor for a mouse pointer when it enters or is hovering over the
|
||||||
|
@ -130,7 +132,7 @@ class RawMaterialButton extends StatefulWidget {
|
||||||
///
|
///
|
||||||
/// If this property is null, [MaterialStateMouseCursor.clickable] will be used.
|
/// If this property is null, [MaterialStateMouseCursor.clickable] will be used.
|
||||||
/// {@endtemplate}
|
/// {@endtemplate}
|
||||||
final MouseCursor? mouseCursor;
|
final MouseCursor mouseCursor;
|
||||||
|
|
||||||
/// Defines the default text style, with [Material.textStyle], for the
|
/// Defines the default text style, with [Material.textStyle], for the
|
||||||
/// button's [child].
|
/// button's [child].
|
||||||
|
@ -142,22 +144,22 @@ class RawMaterialButton extends StatefulWidget {
|
||||||
/// * [MaterialState.hovered].
|
/// * [MaterialState.hovered].
|
||||||
/// * [MaterialState.focused].
|
/// * [MaterialState.focused].
|
||||||
/// * [MaterialState.disabled].
|
/// * [MaterialState.disabled].
|
||||||
final TextStyle? textStyle;
|
final TextStyle textStyle;
|
||||||
|
|
||||||
/// The color of the button's [Material].
|
/// The color of the button's [Material].
|
||||||
final Color? fillColor;
|
final Color fillColor;
|
||||||
|
|
||||||
/// The color for the button's [Material] when it has the input focus.
|
/// The color for the button's [Material] when it has the input focus.
|
||||||
final Color? focusColor;
|
final Color focusColor;
|
||||||
|
|
||||||
/// The color for the button's [Material] when a pointer is hovering over it.
|
/// The color for the button's [Material] when a pointer is hovering over it.
|
||||||
final Color? hoverColor;
|
final Color hoverColor;
|
||||||
|
|
||||||
/// The highlight color for the button's [InkWell].
|
/// The highlight color for the button's [InkWell].
|
||||||
final Color? highlightColor;
|
final Color highlightColor;
|
||||||
|
|
||||||
/// The splash color for the button's [InkWell].
|
/// The splash color for the button's [InkWell].
|
||||||
final Color? splashColor;
|
final Color splashColor;
|
||||||
|
|
||||||
/// The elevation for the button's [Material] when the button
|
/// The elevation for the button's [Material] when the button
|
||||||
/// is [enabled] but not pressed.
|
/// is [enabled] but not pressed.
|
||||||
|
@ -273,7 +275,7 @@ class RawMaterialButton extends StatefulWidget {
|
||||||
final Duration animationDuration;
|
final Duration animationDuration;
|
||||||
|
|
||||||
/// Typically the button's label.
|
/// Typically the button's label.
|
||||||
final Widget? child;
|
final Widget child;
|
||||||
|
|
||||||
/// Whether the button is enabled or disabled.
|
/// Whether the button is enabled or disabled.
|
||||||
///
|
///
|
||||||
|
@ -291,7 +293,7 @@ class RawMaterialButton extends StatefulWidget {
|
||||||
final MaterialTapTargetSize materialTapTargetSize;
|
final MaterialTapTargetSize materialTapTargetSize;
|
||||||
|
|
||||||
/// {@macro flutter.widgets.Focus.focusNode}
|
/// {@macro flutter.widgets.Focus.focusNode}
|
||||||
final FocusNode? focusNode;
|
final FocusNode focusNode;
|
||||||
|
|
||||||
/// {@macro flutter.widgets.Focus.autofocus}
|
/// {@macro flutter.widgets.Focus.autofocus}
|
||||||
final bool autofocus;
|
final bool autofocus;
|
||||||
|
@ -332,7 +334,7 @@ class _RawMaterialButtonState extends State<RawMaterialButton> {
|
||||||
setState(() {
|
setState(() {
|
||||||
_updateState(MaterialState.pressed, value);
|
_updateState(MaterialState.pressed, value);
|
||||||
if (widget.onHighlightChanged != null) {
|
if (widget.onHighlightChanged != null) {
|
||||||
widget.onHighlightChanged!(value);
|
widget.onHighlightChanged(value);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -393,11 +395,11 @@ class _RawMaterialButtonState extends State<RawMaterialButton> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final Color? effectiveTextColor = MaterialStateProperty.resolveAs<Color>(widget.textStyle?.color, _states);
|
final Color effectiveTextColor = MaterialStateProperty.resolveAs<Color>(widget.textStyle?.color, _states);
|
||||||
final ShapeBorder? effectiveShape = MaterialStateProperty.resolveAs<ShapeBorder>(widget.shape, _states);
|
final ShapeBorder effectiveShape = MaterialStateProperty.resolveAs<ShapeBorder>(widget.shape, _states);
|
||||||
final Offset densityAdjustment = widget.visualDensity.baseSizeAdjustment;
|
final Offset densityAdjustment = widget.visualDensity.baseSizeAdjustment;
|
||||||
final BoxConstraints effectiveConstraints = widget.visualDensity.effectiveConstraints(widget.constraints);
|
final BoxConstraints effectiveConstraints = widget.visualDensity.effectiveConstraints(widget.constraints);
|
||||||
final MouseCursor? effectiveMouseCursor = MaterialStateProperty.resolveAs<MouseCursor>(
|
final MouseCursor effectiveMouseCursor = MaterialStateProperty.resolveAs<MouseCursor>(
|
||||||
widget.mouseCursor ?? MaterialStateMouseCursor.clickable,
|
widget.mouseCursor ?? MaterialStateMouseCursor.clickable,
|
||||||
_states,
|
_states,
|
||||||
);
|
);
|
||||||
|
@ -485,9 +487,9 @@ class _RawMaterialButtonState extends State<RawMaterialButton> {
|
||||||
/// "tap target", but not its material or its ink splashes.
|
/// "tap target", but not its material or its ink splashes.
|
||||||
class _InputPadding extends SingleChildRenderObjectWidget {
|
class _InputPadding extends SingleChildRenderObjectWidget {
|
||||||
const _InputPadding({
|
const _InputPadding({
|
||||||
Key? key,
|
Key key,
|
||||||
Widget? child,
|
Widget child,
|
||||||
required this.minSize,
|
this.minSize,
|
||||||
}) : super(key: key, child: child);
|
}) : super(key: key, child: child);
|
||||||
|
|
||||||
final Size minSize;
|
final Size minSize;
|
||||||
|
@ -504,7 +506,7 @@ class _InputPadding extends SingleChildRenderObjectWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _RenderInputPadding extends RenderShiftedBox {
|
class _RenderInputPadding extends RenderShiftedBox {
|
||||||
_RenderInputPadding(this._minSize, [RenderBox? child]) : super(child);
|
_RenderInputPadding(this._minSize, [RenderBox child]) : super(child);
|
||||||
|
|
||||||
Size get minSize => _minSize;
|
Size get minSize => _minSize;
|
||||||
Size _minSize;
|
Size _minSize;
|
||||||
|
@ -518,57 +520,58 @@ class _RenderInputPadding extends RenderShiftedBox {
|
||||||
@override
|
@override
|
||||||
double computeMinIntrinsicWidth(double height) {
|
double computeMinIntrinsicWidth(double height) {
|
||||||
if (child != null)
|
if (child != null)
|
||||||
return math.max(child!.getMinIntrinsicWidth(height), minSize.width);
|
return math.max(child.getMinIntrinsicWidth(height), minSize.width);
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
double computeMinIntrinsicHeight(double width) {
|
double computeMinIntrinsicHeight(double width) {
|
||||||
if (child != null)
|
if (child != null)
|
||||||
return math.max(child!.getMinIntrinsicHeight(width), minSize.height);
|
return math.max(child.getMinIntrinsicHeight(width), minSize.height);
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
double computeMaxIntrinsicWidth(double height) {
|
double computeMaxIntrinsicWidth(double height) {
|
||||||
if (child != null)
|
if (child != null)
|
||||||
return math.max(child!.getMaxIntrinsicWidth(height), minSize.width);
|
return math.max(child.getMaxIntrinsicWidth(height), minSize.width);
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
double computeMaxIntrinsicHeight(double width) {
|
double computeMaxIntrinsicHeight(double width) {
|
||||||
if (child != null)
|
if (child != null)
|
||||||
return math.max(child!.getMaxIntrinsicHeight(width), minSize.height);
|
return math.max(child.getMaxIntrinsicHeight(width), minSize.height);
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void performLayout() {
|
void performLayout() {
|
||||||
|
final BoxConstraints constraints = this.constraints;
|
||||||
if (child != null) {
|
if (child != null) {
|
||||||
child!.layout(constraints, parentUsesSize: true);
|
child.layout(constraints, parentUsesSize: true);
|
||||||
final double height = math.max(child!.size.width, minSize.width);
|
final double height = math.max(child.size.width, minSize.width);
|
||||||
final double width = math.max(child!.size.height, minSize.height);
|
final double width = math.max(child.size.height, minSize.height);
|
||||||
size = constraints.constrain(Size(height, width));
|
size = constraints.constrain(Size(height, width));
|
||||||
final BoxParentData childParentData = child!.parentData as BoxParentData;
|
final BoxParentData childParentData = child.parentData as BoxParentData;
|
||||||
childParentData.offset = Alignment.center.alongOffset(size - child!.size as Offset);
|
childParentData.offset = Alignment.center.alongOffset(size - child.size as Offset);
|
||||||
} else {
|
} else {
|
||||||
size = Size.zero;
|
size = Size.zero;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool hitTest(BoxHitTestResult result, { required Offset position }) {
|
bool hitTest(BoxHitTestResult result, { Offset position }) {
|
||||||
if (super.hitTest(result, position: position)) {
|
if (super.hitTest(result, position: position)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
final Offset center = child!.size.center(Offset.zero);
|
final Offset center = child.size.center(Offset.zero);
|
||||||
return result.addWithRawTransform(
|
return result.addWithRawTransform(
|
||||||
transform: MatrixUtils.forceToPoint(center),
|
transform: MatrixUtils.forceToPoint(center),
|
||||||
position: center,
|
position: center,
|
||||||
hitTest: (BoxHitTestResult result, Offset? position) {
|
hitTest: (BoxHitTestResult result, Offset position) {
|
||||||
assert(position == center);
|
assert(position == center);
|
||||||
return child!.hitTest(result, position: center);
|
return child.hitTest(result, position: center);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
// @dart = 2.8
|
||||||
|
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
|
|
||||||
|
@ -54,7 +56,7 @@ class ButtonBar extends StatelessWidget {
|
||||||
/// Both [buttonMinWidth] and [buttonHeight] must be non-negative if they
|
/// Both [buttonMinWidth] and [buttonHeight] must be non-negative if they
|
||||||
/// are not null.
|
/// are not null.
|
||||||
const ButtonBar({
|
const ButtonBar({
|
||||||
Key? key,
|
Key key,
|
||||||
this.alignment,
|
this.alignment,
|
||||||
this.mainAxisSize,
|
this.mainAxisSize,
|
||||||
this.buttonTextTheme,
|
this.buttonTextTheme,
|
||||||
|
@ -75,13 +77,13 @@ class ButtonBar extends StatelessWidget {
|
||||||
///
|
///
|
||||||
/// If null then it will use [ButtonBarThemeData.alignment]. If that is null,
|
/// If null then it will use [ButtonBarThemeData.alignment]. If that is null,
|
||||||
/// it will default to [MainAxisAlignment.end].
|
/// it will default to [MainAxisAlignment.end].
|
||||||
final MainAxisAlignment? alignment;
|
final MainAxisAlignment alignment;
|
||||||
|
|
||||||
/// How much horizontal space is available. See [Row.mainAxisSize].
|
/// How much horizontal space is available. See [Row.mainAxisSize].
|
||||||
///
|
///
|
||||||
/// If null then it will use the surrounding [ButtonBarThemeData.mainAxisSize].
|
/// If null then it will use the surrounding [ButtonBarThemeData.mainAxisSize].
|
||||||
/// If that is null, it will default to [MainAxisSize.max].
|
/// If that is null, it will default to [MainAxisSize.max].
|
||||||
final MainAxisSize? mainAxisSize;
|
final MainAxisSize mainAxisSize;
|
||||||
|
|
||||||
/// Overrides the surrounding [ButtonBarThemeData.buttonTextTheme] to define a
|
/// Overrides the surrounding [ButtonBarThemeData.buttonTextTheme] to define a
|
||||||
/// button's base colors, size, internal padding and shape.
|
/// button's base colors, size, internal padding and shape.
|
||||||
|
@ -89,21 +91,21 @@ class ButtonBar extends StatelessWidget {
|
||||||
/// If null then it will use the surrounding
|
/// If null then it will use the surrounding
|
||||||
/// [ButtonBarThemeData.buttonTextTheme]. If that is null, it will default to
|
/// [ButtonBarThemeData.buttonTextTheme]. If that is null, it will default to
|
||||||
/// [ButtonTextTheme.primary].
|
/// [ButtonTextTheme.primary].
|
||||||
final ButtonTextTheme? buttonTextTheme;
|
final ButtonTextTheme buttonTextTheme;
|
||||||
|
|
||||||
/// Overrides the surrounding [ButtonThemeData.minWidth] to define a button's
|
/// Overrides the surrounding [ButtonThemeData.minWidth] to define a button's
|
||||||
/// minimum width.
|
/// minimum width.
|
||||||
///
|
///
|
||||||
/// If null then it will use the surrounding [ButtonBarThemeData.buttonMinWidth].
|
/// If null then it will use the surrounding [ButtonBarThemeData.buttonMinWidth].
|
||||||
/// If that is null, it will default to 64.0 logical pixels.
|
/// If that is null, it will default to 64.0 logical pixels.
|
||||||
final double? buttonMinWidth;
|
final double buttonMinWidth;
|
||||||
|
|
||||||
/// Overrides the surrounding [ButtonThemeData.height] to define a button's
|
/// Overrides the surrounding [ButtonThemeData.height] to define a button's
|
||||||
/// minimum height.
|
/// minimum height.
|
||||||
///
|
///
|
||||||
/// If null then it will use the surrounding [ButtonBarThemeData.buttonHeight].
|
/// If null then it will use the surrounding [ButtonBarThemeData.buttonHeight].
|
||||||
/// If that is null, it will default to 36.0 logical pixels.
|
/// If that is null, it will default to 36.0 logical pixels.
|
||||||
final double? buttonHeight;
|
final double buttonHeight;
|
||||||
|
|
||||||
/// Overrides the surrounding [ButtonThemeData.padding] to define the padding
|
/// Overrides the surrounding [ButtonThemeData.padding] to define the padding
|
||||||
/// for a button's child (typically the button's label).
|
/// for a button's child (typically the button's label).
|
||||||
|
@ -111,14 +113,14 @@ class ButtonBar extends StatelessWidget {
|
||||||
/// If null then it will use the surrounding [ButtonBarThemeData.buttonPadding].
|
/// If null then it will use the surrounding [ButtonBarThemeData.buttonPadding].
|
||||||
/// If that is null, it will default to 8.0 logical pixels on the left
|
/// If that is null, it will default to 8.0 logical pixels on the left
|
||||||
/// and right.
|
/// and right.
|
||||||
final EdgeInsetsGeometry? buttonPadding;
|
final EdgeInsetsGeometry buttonPadding;
|
||||||
|
|
||||||
/// Overrides the surrounding [ButtonThemeData.alignedDropdown] to define whether
|
/// Overrides the surrounding [ButtonThemeData.alignedDropdown] to define whether
|
||||||
/// a [DropdownButton] menu's width will match the button's width.
|
/// a [DropdownButton] menu's width will match the button's width.
|
||||||
///
|
///
|
||||||
/// If null then it will use the surrounding [ButtonBarThemeData.buttonAlignedDropdown].
|
/// If null then it will use the surrounding [ButtonBarThemeData.buttonAlignedDropdown].
|
||||||
/// If that is null, it will default to false.
|
/// If that is null, it will default to false.
|
||||||
final bool? buttonAlignedDropdown;
|
final bool buttonAlignedDropdown;
|
||||||
|
|
||||||
/// Defines whether a [ButtonBar] should size itself with a minimum size
|
/// Defines whether a [ButtonBar] should size itself with a minimum size
|
||||||
/// constraint or with padding.
|
/// constraint or with padding.
|
||||||
|
@ -127,7 +129,7 @@ class ButtonBar extends StatelessWidget {
|
||||||
///
|
///
|
||||||
/// If null then it will use the surrounding [ButtonBarThemeData.layoutBehavior].
|
/// If null then it will use the surrounding [ButtonBarThemeData.layoutBehavior].
|
||||||
/// If that is null, it will default [ButtonBarLayoutBehavior.padded].
|
/// If that is null, it will default [ButtonBarLayoutBehavior.padded].
|
||||||
final ButtonBarLayoutBehavior? layoutBehavior;
|
final ButtonBarLayoutBehavior layoutBehavior;
|
||||||
|
|
||||||
/// Defines the vertical direction of a [ButtonBar]'s children if it
|
/// Defines the vertical direction of a [ButtonBar]'s children if it
|
||||||
/// overflows.
|
/// overflows.
|
||||||
|
@ -143,7 +145,7 @@ class ButtonBar extends StatelessWidget {
|
||||||
/// If null then it will use the surrounding
|
/// If null then it will use the surrounding
|
||||||
/// [ButtonBarThemeData.overflowDirection]. If that is null, it will
|
/// [ButtonBarThemeData.overflowDirection]. If that is null, it will
|
||||||
/// default to [VerticalDirection.down].
|
/// default to [VerticalDirection.down].
|
||||||
final VerticalDirection? overflowDirection;
|
final VerticalDirection overflowDirection;
|
||||||
|
|
||||||
/// The spacing between buttons when the button bar overflows.
|
/// The spacing between buttons when the button bar overflows.
|
||||||
///
|
///
|
||||||
|
@ -159,7 +161,7 @@ class ButtonBar extends StatelessWidget {
|
||||||
///
|
///
|
||||||
/// If null then no spacing will be added in between buttons in
|
/// If null then no spacing will be added in between buttons in
|
||||||
/// an overflow state.
|
/// an overflow state.
|
||||||
final double? overflowButtonSpacing;
|
final double overflowButtonSpacing;
|
||||||
|
|
||||||
/// The buttons to arrange horizontally.
|
/// The buttons to arrange horizontally.
|
||||||
///
|
///
|
||||||
|
@ -214,6 +216,8 @@ class ButtonBar extends StatelessWidget {
|
||||||
child: child,
|
child: child,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
assert(false);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,14 +239,14 @@ class _ButtonBarRow extends Flex {
|
||||||
/// Creates a button bar that attempts to display in a row, but displays in
|
/// Creates a button bar that attempts to display in a row, but displays in
|
||||||
/// a column if there is insufficient horizontal space.
|
/// a column if there is insufficient horizontal space.
|
||||||
_ButtonBarRow({
|
_ButtonBarRow({
|
||||||
required List<Widget> children,
|
List<Widget> children,
|
||||||
Axis direction = Axis.horizontal,
|
Axis direction = Axis.horizontal,
|
||||||
MainAxisSize mainAxisSize = MainAxisSize.max,
|
MainAxisSize mainAxisSize = MainAxisSize.max,
|
||||||
MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
|
MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
|
||||||
CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
|
CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
|
||||||
TextDirection? textDirection,
|
TextDirection textDirection,
|
||||||
VerticalDirection overflowDirection = VerticalDirection.down,
|
VerticalDirection overflowDirection = VerticalDirection.down,
|
||||||
TextBaseline? textBaseline,
|
TextBaseline textBaseline,
|
||||||
this.overflowButtonSpacing,
|
this.overflowButtonSpacing,
|
||||||
}) : super(
|
}) : super(
|
||||||
children: children,
|
children: children,
|
||||||
|
@ -255,7 +259,7 @@ class _ButtonBarRow extends Flex {
|
||||||
textBaseline: textBaseline,
|
textBaseline: textBaseline,
|
||||||
);
|
);
|
||||||
|
|
||||||
final double? overflowButtonSpacing;
|
final double overflowButtonSpacing;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_RenderButtonBarRow createRenderObject(BuildContext context) {
|
_RenderButtonBarRow createRenderObject(BuildContext context) {
|
||||||
|
@ -264,7 +268,7 @@ class _ButtonBarRow extends Flex {
|
||||||
mainAxisAlignment: mainAxisAlignment,
|
mainAxisAlignment: mainAxisAlignment,
|
||||||
mainAxisSize: mainAxisSize,
|
mainAxisSize: mainAxisSize,
|
||||||
crossAxisAlignment: crossAxisAlignment,
|
crossAxisAlignment: crossAxisAlignment,
|
||||||
textDirection: getEffectiveTextDirection(context)!,
|
textDirection: getEffectiveTextDirection(context),
|
||||||
verticalDirection: verticalDirection,
|
verticalDirection: verticalDirection,
|
||||||
textBaseline: textBaseline,
|
textBaseline: textBaseline,
|
||||||
overflowButtonSpacing: overflowButtonSpacing,
|
overflowButtonSpacing: overflowButtonSpacing,
|
||||||
|
@ -303,14 +307,14 @@ class _RenderButtonBarRow extends RenderFlex {
|
||||||
/// Creates a button bar that attempts to display in a row, but displays in
|
/// Creates a button bar that attempts to display in a row, but displays in
|
||||||
/// a column if there is insufficient horizontal space.
|
/// a column if there is insufficient horizontal space.
|
||||||
_RenderButtonBarRow({
|
_RenderButtonBarRow({
|
||||||
List<RenderBox>? children,
|
List<RenderBox> children,
|
||||||
Axis direction = Axis.horizontal,
|
Axis direction = Axis.horizontal,
|
||||||
MainAxisSize mainAxisSize = MainAxisSize.max,
|
MainAxisSize mainAxisSize = MainAxisSize.max,
|
||||||
MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
|
MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
|
||||||
CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
|
CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
|
||||||
required TextDirection textDirection,
|
@required TextDirection textDirection,
|
||||||
VerticalDirection verticalDirection = VerticalDirection.down,
|
VerticalDirection verticalDirection = VerticalDirection.down,
|
||||||
TextBaseline? textBaseline,
|
TextBaseline textBaseline,
|
||||||
this.overflowButtonSpacing,
|
this.overflowButtonSpacing,
|
||||||
}) : assert(textDirection != null),
|
}) : assert(textDirection != null),
|
||||||
assert(overflowButtonSpacing == null || overflowButtonSpacing >= 0),
|
assert(overflowButtonSpacing == null || overflowButtonSpacing >= 0),
|
||||||
|
@ -326,13 +330,13 @@ class _RenderButtonBarRow extends RenderFlex {
|
||||||
);
|
);
|
||||||
|
|
||||||
bool _hasCheckedLayoutWidth = false;
|
bool _hasCheckedLayoutWidth = false;
|
||||||
double? overflowButtonSpacing;
|
double overflowButtonSpacing;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
BoxConstraints get constraints {
|
BoxConstraints get constraints {
|
||||||
if (_hasCheckedLayoutWidth)
|
if (_hasCheckedLayoutWidth)
|
||||||
return super.constraints;
|
return super.constraints;
|
||||||
return super.constraints.copyWith(maxWidth: double.infinity);
|
return super.constraints?.copyWith(maxWidth: double.infinity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -355,7 +359,7 @@ class _RenderButtonBarRow extends RenderFlex {
|
||||||
super.performLayout();
|
super.performLayout();
|
||||||
} else {
|
} else {
|
||||||
final BoxConstraints childConstraints = constraints.copyWith(minWidth: 0.0);
|
final BoxConstraints childConstraints = constraints.copyWith(minWidth: 0.0);
|
||||||
RenderBox? child;
|
RenderBox child;
|
||||||
double currentHeight = 0.0;
|
double currentHeight = 0.0;
|
||||||
switch (verticalDirection) {
|
switch (verticalDirection) {
|
||||||
case VerticalDirection.down:
|
case VerticalDirection.down:
|
||||||
|
@ -377,7 +381,7 @@ class _RenderButtonBarRow extends RenderFlex {
|
||||||
// alignment for a row. For [MainAxisAlignment.spaceAround],
|
// alignment for a row. For [MainAxisAlignment.spaceAround],
|
||||||
// [MainAxisAlignment.spaceBetween] and [MainAxisAlignment.spaceEvenly]
|
// [MainAxisAlignment.spaceBetween] and [MainAxisAlignment.spaceEvenly]
|
||||||
// cases, use [MainAxisAlignment.start].
|
// cases, use [MainAxisAlignment.start].
|
||||||
switch (textDirection!) {
|
switch (textDirection) {
|
||||||
case TextDirection.ltr:
|
case TextDirection.ltr:
|
||||||
switch (mainAxisAlignment) {
|
switch (mainAxisAlignment) {
|
||||||
case MainAxisAlignment.center:
|
case MainAxisAlignment.center:
|
||||||
|
@ -418,7 +422,7 @@ class _RenderButtonBarRow extends RenderFlex {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (overflowButtonSpacing != null && child != null)
|
if (overflowButtonSpacing != null && child != null)
|
||||||
currentHeight += overflowButtonSpacing!;
|
currentHeight += overflowButtonSpacing;
|
||||||
}
|
}
|
||||||
size = constraints.constrain(Size(constraints.maxWidth, currentHeight));
|
size = constraints.constrain(Size(constraints.maxWidth, currentHeight));
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
// @dart = 2.8
|
||||||
|
|
||||||
import 'dart:ui' show lerpDouble;
|
import 'dart:ui' show lerpDouble;
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
@ -44,10 +46,10 @@ class ButtonBarThemeData with Diagnosticable {
|
||||||
assert(buttonHeight == null || buttonHeight >= 0.0);
|
assert(buttonHeight == null || buttonHeight >= 0.0);
|
||||||
|
|
||||||
/// How the children should be placed along the horizontal axis.
|
/// How the children should be placed along the horizontal axis.
|
||||||
final MainAxisAlignment? alignment;
|
final MainAxisAlignment alignment;
|
||||||
|
|
||||||
/// How much horizontal space is available. See [Row.mainAxisSize].
|
/// How much horizontal space is available. See [Row.mainAxisSize].
|
||||||
final MainAxisSize? mainAxisSize;
|
final MainAxisSize mainAxisSize;
|
||||||
|
|
||||||
/// Defines a [ButtonBar] button's base colors, and the defaults for
|
/// Defines a [ButtonBar] button's base colors, and the defaults for
|
||||||
/// the button's minimum size, internal padding, and shape.
|
/// the button's minimum size, internal padding, and shape.
|
||||||
|
@ -57,7 +59,7 @@ class ButtonBarThemeData with Diagnosticable {
|
||||||
///
|
///
|
||||||
/// Despite the name, this property is not a [TextTheme], its value is not a
|
/// Despite the name, this property is not a [TextTheme], its value is not a
|
||||||
/// collection of [TextStyle]s.
|
/// collection of [TextStyle]s.
|
||||||
final ButtonTextTheme? buttonTextTheme;
|
final ButtonTextTheme buttonTextTheme;
|
||||||
|
|
||||||
/// The minimum width for [ButtonBar] buttons.
|
/// The minimum width for [ButtonBar] buttons.
|
||||||
///
|
///
|
||||||
|
@ -66,19 +68,19 @@ class ButtonBarThemeData with Diagnosticable {
|
||||||
///
|
///
|
||||||
/// The actual horizontal space allocated for a button's child is
|
/// The actual horizontal space allocated for a button's child is
|
||||||
/// at least this value less the theme's horizontal [ButtonThemeData.padding].
|
/// at least this value less the theme's horizontal [ButtonThemeData.padding].
|
||||||
final double? buttonMinWidth;
|
final double buttonMinWidth;
|
||||||
|
|
||||||
/// The minimum height for [ButtonBar] buttons.
|
/// The minimum height for [ButtonBar] buttons.
|
||||||
///
|
///
|
||||||
/// This will override the surrounding [ButtonThemeData.height] setting
|
/// This will override the surrounding [ButtonThemeData.height] setting
|
||||||
/// for buttons contained in the [ButtonBar].
|
/// for buttons contained in the [ButtonBar].
|
||||||
final double? buttonHeight;
|
final double buttonHeight;
|
||||||
|
|
||||||
/// Padding for a [ButtonBar] button's child (typically the button's label).
|
/// Padding for a [ButtonBar] button's child (typically the button's label).
|
||||||
///
|
///
|
||||||
/// This will override the surrounding [ButtonThemeData.padding] setting
|
/// This will override the surrounding [ButtonThemeData.padding] setting
|
||||||
/// for buttons contained in the [ButtonBar].
|
/// for buttons contained in the [ButtonBar].
|
||||||
final EdgeInsetsGeometry? buttonPadding;
|
final EdgeInsetsGeometry buttonPadding;
|
||||||
|
|
||||||
/// If true, then a [DropdownButton] menu's width will match the [ButtonBar]
|
/// If true, then a [DropdownButton] menu's width will match the [ButtonBar]
|
||||||
/// button's width.
|
/// button's width.
|
||||||
|
@ -93,11 +95,11 @@ class ButtonBarThemeData with Diagnosticable {
|
||||||
///
|
///
|
||||||
/// This property only affects [DropdownButton] contained in a [ButtonBar]
|
/// This property only affects [DropdownButton] contained in a [ButtonBar]
|
||||||
/// and its menu.
|
/// and its menu.
|
||||||
final bool? buttonAlignedDropdown;
|
final bool buttonAlignedDropdown;
|
||||||
|
|
||||||
/// Defines whether a [ButtonBar] should size itself with a minimum size
|
/// Defines whether a [ButtonBar] should size itself with a minimum size
|
||||||
/// constraint or with padding.
|
/// constraint or with padding.
|
||||||
final ButtonBarLayoutBehavior? layoutBehavior;
|
final ButtonBarLayoutBehavior layoutBehavior;
|
||||||
|
|
||||||
/// Defines the vertical direction of a [ButtonBar]'s children if it
|
/// Defines the vertical direction of a [ButtonBar]'s children if it
|
||||||
/// overflows.
|
/// overflows.
|
||||||
|
@ -109,20 +111,20 @@ class ButtonBarThemeData with Diagnosticable {
|
||||||
/// the first action will be at the bottom of the column if this
|
/// the first action will be at the bottom of the column if this
|
||||||
/// property is set to [VerticalDirection.up], since it "starts" at the
|
/// property is set to [VerticalDirection.up], since it "starts" at the
|
||||||
/// bottom and "ends" at the top.
|
/// bottom and "ends" at the top.
|
||||||
final VerticalDirection? overflowDirection;
|
final VerticalDirection overflowDirection;
|
||||||
|
|
||||||
/// Creates a copy of this object but with the given fields replaced with the
|
/// Creates a copy of this object but with the given fields replaced with the
|
||||||
/// new values.
|
/// new values.
|
||||||
ButtonBarThemeData copyWith({
|
ButtonBarThemeData copyWith({
|
||||||
MainAxisAlignment? alignment,
|
MainAxisAlignment alignment,
|
||||||
MainAxisSize? mainAxisSize,
|
MainAxisSize mainAxisSize,
|
||||||
ButtonTextTheme? buttonTextTheme,
|
ButtonTextTheme buttonTextTheme,
|
||||||
double? buttonMinWidth,
|
double buttonMinWidth,
|
||||||
double? buttonHeight,
|
double buttonHeight,
|
||||||
EdgeInsetsGeometry? buttonPadding,
|
EdgeInsetsGeometry buttonPadding,
|
||||||
bool? buttonAlignedDropdown,
|
bool buttonAlignedDropdown,
|
||||||
ButtonBarLayoutBehavior? layoutBehavior,
|
ButtonBarLayoutBehavior layoutBehavior,
|
||||||
VerticalDirection? overflowDirection,
|
VerticalDirection overflowDirection,
|
||||||
}) {
|
}) {
|
||||||
return ButtonBarThemeData(
|
return ButtonBarThemeData(
|
||||||
alignment: alignment ?? this.alignment,
|
alignment: alignment ?? this.alignment,
|
||||||
|
@ -142,20 +144,20 @@ class ButtonBarThemeData with Diagnosticable {
|
||||||
/// If both arguments are null, then null is returned.
|
/// If both arguments are null, then null is returned.
|
||||||
///
|
///
|
||||||
/// {@macro dart.ui.shadow.lerp}
|
/// {@macro dart.ui.shadow.lerp}
|
||||||
static ButtonBarThemeData? lerp(ButtonBarThemeData? a, ButtonBarThemeData? b, double t) {
|
static ButtonBarThemeData lerp(ButtonBarThemeData a, ButtonBarThemeData b, double t) {
|
||||||
assert(t != null);
|
assert(t != null);
|
||||||
if (a == null && b == null)
|
if (a == null && b == null)
|
||||||
return null;
|
return null;
|
||||||
return ButtonBarThemeData(
|
return ButtonBarThemeData(
|
||||||
alignment: t < 0.5 ? a?.alignment : b?.alignment,
|
alignment: t < 0.5 ? a.alignment : b.alignment,
|
||||||
mainAxisSize: t < 0.5 ? a?.mainAxisSize : b?.mainAxisSize,
|
mainAxisSize: t < 0.5 ? a.mainAxisSize : b.mainAxisSize,
|
||||||
buttonTextTheme: t < 0.5 ? a?.buttonTextTheme : b?.buttonTextTheme,
|
buttonTextTheme: t < 0.5 ? a.buttonTextTheme : b.buttonTextTheme,
|
||||||
buttonMinWidth: lerpDouble(a?.buttonMinWidth, b?.buttonMinWidth, t),
|
buttonMinWidth: lerpDouble(a?.buttonMinWidth, b?.buttonMinWidth, t),
|
||||||
buttonHeight: lerpDouble(a?.buttonHeight, b?.buttonHeight, t),
|
buttonHeight: lerpDouble(a?.buttonHeight, b?.buttonHeight, t),
|
||||||
buttonPadding: EdgeInsetsGeometry.lerp(a?.buttonPadding, b?.buttonPadding, t),
|
buttonPadding: EdgeInsetsGeometry.lerp(a?.buttonPadding, b?.buttonPadding, t),
|
||||||
buttonAlignedDropdown: t < 0.5 ? a?.buttonAlignedDropdown : b?.buttonAlignedDropdown,
|
buttonAlignedDropdown: t < 0.5 ? a.buttonAlignedDropdown : b.buttonAlignedDropdown,
|
||||||
layoutBehavior: t < 0.5 ? a?.layoutBehavior : b?.layoutBehavior,
|
layoutBehavior: t < 0.5 ? a.layoutBehavior : b.layoutBehavior,
|
||||||
overflowDirection: t < 0.5 ? a?.overflowDirection : b?.overflowDirection,
|
overflowDirection: t < 0.5 ? a.overflowDirection : b.overflowDirection,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,9 +235,9 @@ class ButtonBarTheme extends InheritedWidget {
|
||||||
///
|
///
|
||||||
/// The [data] must not be null.
|
/// The [data] must not be null.
|
||||||
const ButtonBarTheme({
|
const ButtonBarTheme({
|
||||||
Key? key,
|
Key key,
|
||||||
required this.data,
|
@required this.data,
|
||||||
required Widget child,
|
Widget child,
|
||||||
}) : assert(data != null), super(key: key, child: child);
|
}) : assert(data != null), super(key: key, child: child);
|
||||||
|
|
||||||
/// The properties used for all descendant [ButtonBar] widgets.
|
/// The properties used for all descendant [ButtonBar] widgets.
|
||||||
|
@ -251,8 +253,8 @@ class ButtonBarTheme extends InheritedWidget {
|
||||||
/// ButtonBarThemeData theme = ButtonBarTheme.of(context);
|
/// ButtonBarThemeData theme = ButtonBarTheme.of(context);
|
||||||
/// ```
|
/// ```
|
||||||
static ButtonBarThemeData of(BuildContext context) {
|
static ButtonBarThemeData of(BuildContext context) {
|
||||||
final ButtonBarTheme? buttonBarTheme = context.dependOnInheritedWidgetOfExactType<ButtonBarTheme>();
|
final ButtonBarTheme buttonBarTheme = context.dependOnInheritedWidgetOfExactType<ButtonBarTheme>();
|
||||||
return buttonBarTheme?.data ?? Theme.of(context)!.buttonBarTheme;
|
return buttonBarTheme?.data ?? Theme.of(context).buttonBarTheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
// @dart = 2.8
|
||||||
|
|
||||||
import 'dart:ui' show lerpDouble;
|
import 'dart:ui' show lerpDouble;
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
@ -120,10 +122,10 @@ class ButtonStyle with Diagnosticable {
|
||||||
///
|
///
|
||||||
/// The color of the [textStyle] is typically not used directly, the
|
/// The color of the [textStyle] is typically not used directly, the
|
||||||
/// [foregroundColor] is used instead.
|
/// [foregroundColor] is used instead.
|
||||||
final MaterialStateProperty<TextStyle>? textStyle;
|
final MaterialStateProperty<TextStyle> textStyle;
|
||||||
|
|
||||||
/// The button's background fill color.
|
/// The button's background fill color.
|
||||||
final MaterialStateProperty<Color>? backgroundColor;
|
final MaterialStateProperty<Color> backgroundColor;
|
||||||
|
|
||||||
/// The color for the button's [Text] and [Icon] widget descendants.
|
/// The color for the button's [Text] and [Icon] widget descendants.
|
||||||
///
|
///
|
||||||
|
@ -131,11 +133,11 @@ class ButtonStyle with Diagnosticable {
|
||||||
/// of the components that compute defaults from [ButtonStyle] values
|
/// of the components that compute defaults from [ButtonStyle] values
|
||||||
/// compute a default [foregroundColor] and use that instead of the
|
/// compute a default [foregroundColor] and use that instead of the
|
||||||
/// [textStyle]'s color.
|
/// [textStyle]'s color.
|
||||||
final MaterialStateProperty<Color>? foregroundColor;
|
final MaterialStateProperty<Color> foregroundColor;
|
||||||
|
|
||||||
/// The highlight color that's typically used to indicate that
|
/// The highlight color that's typically used to indicate that
|
||||||
/// the button is focused, hovered, or pressed.
|
/// the button is focused, hovered, or pressed.
|
||||||
final MaterialStateProperty<Color>? overlayColor;
|
final MaterialStateProperty<Color> overlayColor;
|
||||||
|
|
||||||
/// The shadow color of the button's [Material].
|
/// The shadow color of the button's [Material].
|
||||||
///
|
///
|
||||||
|
@ -143,35 +145,35 @@ class ButtonStyle with Diagnosticable {
|
||||||
/// dark themes, so by default the button classes add a
|
/// dark themes, so by default the button classes add a
|
||||||
/// semi-transparent overlay to indicate elevation. See
|
/// semi-transparent overlay to indicate elevation. See
|
||||||
/// [ThemeData.applyElevationOverlayColor].
|
/// [ThemeData.applyElevationOverlayColor].
|
||||||
final MaterialStateProperty<Color>? shadowColor;
|
final MaterialStateProperty<Color> shadowColor;
|
||||||
|
|
||||||
/// The elevation of the button's [Material].
|
/// The elevation of the button's [Material].
|
||||||
final MaterialStateProperty<double>? elevation;
|
final MaterialStateProperty<double> elevation;
|
||||||
|
|
||||||
/// The padding between the button's boundary and its child.
|
/// The padding between the button's boundary and its child.
|
||||||
final MaterialStateProperty<EdgeInsetsGeometry>? padding;
|
final MaterialStateProperty<EdgeInsetsGeometry> padding;
|
||||||
|
|
||||||
/// The minimum size of the button itself.
|
/// The minimum size of the button itself.
|
||||||
///
|
///
|
||||||
/// The size of the rectangle the button lies within may be larger
|
/// The size of the rectangle the button lies within may be larger
|
||||||
/// per [tapTargetSize].
|
/// per [tapTargetSize].
|
||||||
final MaterialStateProperty<Size>? minimumSize;
|
final MaterialStateProperty<Size> minimumSize;
|
||||||
|
|
||||||
/// The color and weight of the button's outline.
|
/// The color and weight of the button's outline.
|
||||||
///
|
///
|
||||||
/// This value is combined with [shape] to create a shape decorated
|
/// This value is combined with [shape] to create a shape decorated
|
||||||
/// with an outline.
|
/// with an outline.
|
||||||
final MaterialStateProperty<BorderSide>? side;
|
final MaterialStateProperty<BorderSide> side;
|
||||||
|
|
||||||
/// The shape of the button's underlying [Material].
|
/// The shape of the button's underlying [Material].
|
||||||
///
|
///
|
||||||
/// This shape is combined with [side] to create a shape decorated
|
/// This shape is combined with [side] to create a shape decorated
|
||||||
/// with an outline.
|
/// with an outline.
|
||||||
final MaterialStateProperty<OutlinedBorder>? shape;
|
final MaterialStateProperty<OutlinedBorder> shape;
|
||||||
|
|
||||||
/// The cursor for a mouse pointer when it enters or is hovering over
|
/// The cursor for a mouse pointer when it enters or is hovering over
|
||||||
/// this button's [InkWell].
|
/// this button's [InkWell].
|
||||||
final MaterialStateProperty<MouseCursor>? mouseCursor;
|
final MaterialStateProperty<MouseCursor> mouseCursor;
|
||||||
|
|
||||||
/// Defines how compact the button's layout will be.
|
/// Defines how compact the button's layout will be.
|
||||||
///
|
///
|
||||||
|
@ -181,7 +183,7 @@ class ButtonStyle with Diagnosticable {
|
||||||
///
|
///
|
||||||
/// * [ThemeData.visualDensity], which specifies the [visualDensity] for all widgets
|
/// * [ThemeData.visualDensity], which specifies the [visualDensity] for all widgets
|
||||||
/// within a [Theme].
|
/// within a [Theme].
|
||||||
final VisualDensity? visualDensity;
|
final VisualDensity visualDensity;
|
||||||
|
|
||||||
/// Configures the minimum size of the area within which the button may be pressed.
|
/// Configures the minimum size of the area within which the button may be pressed.
|
||||||
///
|
///
|
||||||
|
@ -189,12 +191,12 @@ class ButtonStyle with Diagnosticable {
|
||||||
/// a transparent margin that responds to taps.
|
/// a transparent margin that responds to taps.
|
||||||
///
|
///
|
||||||
/// Always defaults to [ThemeData.materialTapTargetSize].
|
/// Always defaults to [ThemeData.materialTapTargetSize].
|
||||||
final MaterialTapTargetSize? tapTargetSize;
|
final MaterialTapTargetSize tapTargetSize;
|
||||||
|
|
||||||
/// Defines the duration of animated changes for [shape] and [elevation].
|
/// Defines the duration of animated changes for [shape] and [elevation].
|
||||||
///
|
///
|
||||||
/// Typically the component default value is [kThemeChangeDuration].
|
/// Typically the component default value is [kThemeChangeDuration].
|
||||||
final Duration? animationDuration;
|
final Duration animationDuration;
|
||||||
|
|
||||||
/// Whether detected gestures should provide acoustic and/or haptic feedback.
|
/// Whether detected gestures should provide acoustic and/or haptic feedback.
|
||||||
///
|
///
|
||||||
|
@ -206,26 +208,26 @@ class ButtonStyle with Diagnosticable {
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [Feedback] for providing platform-specific feedback to certain actions.
|
/// * [Feedback] for providing platform-specific feedback to certain actions.
|
||||||
final bool? enableFeedback;
|
final bool enableFeedback;
|
||||||
|
|
||||||
/// Returns a copy of this ButtonStyle with the given fields replaced with
|
/// Returns a copy of this ButtonStyle with the given fields replaced with
|
||||||
/// the new values.
|
/// the new values.
|
||||||
ButtonStyle copyWith({
|
ButtonStyle copyWith({
|
||||||
MaterialStateProperty<TextStyle>? textStyle,
|
MaterialStateProperty<TextStyle> textStyle,
|
||||||
MaterialStateProperty<Color>? backgroundColor,
|
MaterialStateProperty<Color> backgroundColor,
|
||||||
MaterialStateProperty<Color>? foregroundColor,
|
MaterialStateProperty<Color> foregroundColor,
|
||||||
MaterialStateProperty<Color>? overlayColor,
|
MaterialStateProperty<Color> overlayColor,
|
||||||
MaterialStateProperty<Color>? shadowColor,
|
MaterialStateProperty<Color> shadowColor,
|
||||||
MaterialStateProperty<double>? elevation,
|
MaterialStateProperty<double> elevation,
|
||||||
MaterialStateProperty<EdgeInsetsGeometry>? padding,
|
MaterialStateProperty<EdgeInsetsGeometry> padding,
|
||||||
MaterialStateProperty<Size>? minimumSize,
|
MaterialStateProperty<Size> minimumSize,
|
||||||
MaterialStateProperty<BorderSide>? side,
|
MaterialStateProperty<BorderSide> side,
|
||||||
MaterialStateProperty<OutlinedBorder>? shape,
|
MaterialStateProperty<OutlinedBorder> shape,
|
||||||
MaterialStateProperty<MouseCursor>? mouseCursor,
|
MaterialStateProperty<MouseCursor> mouseCursor,
|
||||||
VisualDensity? visualDensity,
|
VisualDensity visualDensity,
|
||||||
MaterialTapTargetSize? tapTargetSize,
|
MaterialTapTargetSize tapTargetSize,
|
||||||
Duration? animationDuration,
|
Duration animationDuration,
|
||||||
bool? enableFeedback,
|
bool enableFeedback,
|
||||||
}) {
|
}) {
|
||||||
return ButtonStyle(
|
return ButtonStyle(
|
||||||
textStyle: textStyle ?? this.textStyle,
|
textStyle: textStyle ?? this.textStyle,
|
||||||
|
@ -251,7 +253,7 @@ class ButtonStyle with Diagnosticable {
|
||||||
///
|
///
|
||||||
/// In other words, [style] is used to fill in unspecified (null) fields
|
/// In other words, [style] is used to fill in unspecified (null) fields
|
||||||
/// this ButtonStyle.
|
/// this ButtonStyle.
|
||||||
ButtonStyle merge(ButtonStyle? style) {
|
ButtonStyle merge(ButtonStyle style) {
|
||||||
if (style == null)
|
if (style == null)
|
||||||
return this;
|
return this;
|
||||||
return copyWith(
|
return copyWith(
|
||||||
|
@ -339,7 +341,7 @@ class ButtonStyle with Diagnosticable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Linearly interpolate between two [ButtonStyle]s.
|
/// Linearly interpolate between two [ButtonStyle]s.
|
||||||
static ButtonStyle? lerp(ButtonStyle? a, ButtonStyle? b, double t) {
|
static ButtonStyle lerp(ButtonStyle a, ButtonStyle b, double t) {
|
||||||
assert (t != null);
|
assert (t != null);
|
||||||
if (a == null && b == null)
|
if (a == null && b == null)
|
||||||
return null;
|
return null;
|
||||||
|
@ -354,15 +356,15 @@ class ButtonStyle with Diagnosticable {
|
||||||
minimumSize: _lerpProperties<Size>(a?.minimumSize, b?.minimumSize, t, Size.lerp),
|
minimumSize: _lerpProperties<Size>(a?.minimumSize, b?.minimumSize, t, Size.lerp),
|
||||||
side: _lerpSides(a?.side, b?.side, t),
|
side: _lerpSides(a?.side, b?.side, t),
|
||||||
shape: _lerpShapes(a?.shape, b?.shape, t),
|
shape: _lerpShapes(a?.shape, b?.shape, t),
|
||||||
mouseCursor: t < 0.5 ? a?.mouseCursor : b?.mouseCursor,
|
mouseCursor: t < 0.5 ? a.mouseCursor : b.mouseCursor,
|
||||||
visualDensity: t < 0.5 ? a?.visualDensity : b?.visualDensity,
|
visualDensity: t < 0.5 ? a.visualDensity : b.visualDensity,
|
||||||
tapTargetSize: t < 0.5 ? a?.tapTargetSize : b?.tapTargetSize,
|
tapTargetSize: t < 0.5 ? a.tapTargetSize : b.tapTargetSize,
|
||||||
animationDuration: t < 0.5 ? a?.animationDuration : b?.animationDuration,
|
animationDuration: t < 0.5 ? a.animationDuration : b.animationDuration,
|
||||||
enableFeedback: t < 0.5 ? a?.enableFeedback : b?.enableFeedback,
|
enableFeedback: t < 0.5 ? a.enableFeedback : b.enableFeedback,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static MaterialStateProperty<T>? _lerpProperties<T>(MaterialStateProperty<T>? a, MaterialStateProperty<T>? b, double t, T? Function(T?, T?, double) lerpFunction ) {
|
static MaterialStateProperty<T> _lerpProperties<T>(MaterialStateProperty<T> a, MaterialStateProperty<T> b, double t, T Function(T, T, double) lerpFunction ) {
|
||||||
// Avoid creating a _LerpProperties object for a common case.
|
// Avoid creating a _LerpProperties object for a common case.
|
||||||
if (a == null && b == null)
|
if (a == null && b == null)
|
||||||
return null;
|
return null;
|
||||||
|
@ -370,14 +372,14 @@ class ButtonStyle with Diagnosticable {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special case because BorderSide.lerp() doesn't support null arguments
|
// Special case because BorderSide.lerp() doesn't support null arguments
|
||||||
static MaterialStateProperty<BorderSide>? _lerpSides(MaterialStateProperty<BorderSide>? a, MaterialStateProperty<BorderSide>? b, double t) {
|
static MaterialStateProperty<BorderSide> _lerpSides(MaterialStateProperty<BorderSide> a, MaterialStateProperty<BorderSide> b, double t) {
|
||||||
if (a == null && b == null)
|
if (a == null && b == null)
|
||||||
return null;
|
return null;
|
||||||
return _LerpSides(a, b, t);
|
return _LerpSides(a, b, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(hansmuller): OutlinedBorder needs a lerp method - https://github.com/flutter/flutter/issues/60555.
|
// TODO(hansmuller): OutlinedBorder needs a lerp method - https://github.com/flutter/flutter/issues/60555.
|
||||||
static MaterialStateProperty<OutlinedBorder>? _lerpShapes(MaterialStateProperty<OutlinedBorder>? a, MaterialStateProperty<OutlinedBorder>? b, double t) {
|
static MaterialStateProperty<OutlinedBorder> _lerpShapes(MaterialStateProperty<OutlinedBorder> a, MaterialStateProperty<OutlinedBorder> b, double t) {
|
||||||
if (a == null && b == null)
|
if (a == null && b == null)
|
||||||
return null;
|
return null;
|
||||||
return _LerpShapes(a, b, t);
|
return _LerpShapes(a, b, t);
|
||||||
|
@ -387,15 +389,15 @@ class ButtonStyle with Diagnosticable {
|
||||||
class _LerpProperties<T> implements MaterialStateProperty<T> {
|
class _LerpProperties<T> implements MaterialStateProperty<T> {
|
||||||
const _LerpProperties(this.a, this.b, this.t, this.lerpFunction);
|
const _LerpProperties(this.a, this.b, this.t, this.lerpFunction);
|
||||||
|
|
||||||
final MaterialStateProperty<T>? a;
|
final MaterialStateProperty<T> a;
|
||||||
final MaterialStateProperty<T>? b;
|
final MaterialStateProperty<T> b;
|
||||||
final double t;
|
final double t;
|
||||||
final T? Function(T?, T?, double) lerpFunction;
|
final T Function(T, T, double) lerpFunction;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
T? resolve(Set<MaterialState> states) {
|
T resolve(Set<MaterialState> states) {
|
||||||
final T? resolvedA = a?.resolve(states);
|
final T resolvedA = a?.resolve(states);
|
||||||
final T? resolvedB = b?.resolve(states);
|
final T resolvedB = b?.resolve(states);
|
||||||
return lerpFunction(resolvedA, resolvedB, t);
|
return lerpFunction(resolvedA, resolvedB, t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -403,18 +405,18 @@ class _LerpProperties<T> implements MaterialStateProperty<T> {
|
||||||
class _LerpSides implements MaterialStateProperty<BorderSide> {
|
class _LerpSides implements MaterialStateProperty<BorderSide> {
|
||||||
const _LerpSides(this.a, this.b, this.t);
|
const _LerpSides(this.a, this.b, this.t);
|
||||||
|
|
||||||
final MaterialStateProperty<BorderSide>? a;
|
final MaterialStateProperty<BorderSide> a;
|
||||||
final MaterialStateProperty<BorderSide>? b;
|
final MaterialStateProperty<BorderSide> b;
|
||||||
final double t;
|
final double t;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
BorderSide? resolve(Set<MaterialState> states) {
|
BorderSide resolve(Set<MaterialState> states) {
|
||||||
final BorderSide? resolvedA = a?.resolve(states);
|
final BorderSide resolvedA = a?.resolve(states);
|
||||||
final BorderSide? resolvedB = b?.resolve(states);
|
final BorderSide resolvedB = b?.resolve(states);
|
||||||
if (resolvedA == null && resolvedB == null)
|
if (resolvedA == null && resolvedB == null)
|
||||||
return null;
|
return null;
|
||||||
if (resolvedA == null)
|
if (resolvedA == null)
|
||||||
return BorderSide.lerp(BorderSide(width: 0, color: resolvedB!.color.withAlpha(0)), resolvedB, t);
|
return BorderSide.lerp(BorderSide(width: 0, color: resolvedB.color.withAlpha(0)), resolvedB, t);
|
||||||
if (resolvedB == null)
|
if (resolvedB == null)
|
||||||
return BorderSide.lerp(BorderSide(width: 0, color: resolvedA.color.withAlpha(0)), resolvedA, t);
|
return BorderSide.lerp(BorderSide(width: 0, color: resolvedA.color.withAlpha(0)), resolvedA, t);
|
||||||
return BorderSide.lerp(resolvedA, resolvedB, t);
|
return BorderSide.lerp(resolvedA, resolvedB, t);
|
||||||
|
@ -424,14 +426,14 @@ class _LerpSides implements MaterialStateProperty<BorderSide> {
|
||||||
class _LerpShapes implements MaterialStateProperty<OutlinedBorder> {
|
class _LerpShapes implements MaterialStateProperty<OutlinedBorder> {
|
||||||
const _LerpShapes(this.a, this.b, this.t);
|
const _LerpShapes(this.a, this.b, this.t);
|
||||||
|
|
||||||
final MaterialStateProperty<OutlinedBorder>? a;
|
final MaterialStateProperty<OutlinedBorder> a;
|
||||||
final MaterialStateProperty<OutlinedBorder>? b;
|
final MaterialStateProperty<OutlinedBorder> b;
|
||||||
final double t;
|
final double t;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
OutlinedBorder? resolve(Set<MaterialState> states) {
|
OutlinedBorder resolve(Set<MaterialState> states) {
|
||||||
final OutlinedBorder? resolvedA = a?.resolve(states);
|
final OutlinedBorder resolvedA = a?.resolve(states);
|
||||||
final OutlinedBorder? resolvedB = b?.resolve(states);
|
final OutlinedBorder resolvedB = b?.resolve(states);
|
||||||
return ShapeBorder.lerp(resolvedA, resolvedB, t) as OutlinedBorder?;
|
return ShapeBorder.lerp(resolvedA, resolvedB, t) as OutlinedBorder;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
// @dart = 2.8
|
||||||
|
|
||||||
import 'dart:math' as math;
|
import 'dart:math' as math;
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
@ -30,14 +32,14 @@ import 'theme_data.dart';
|
||||||
abstract class ButtonStyleButton extends StatefulWidget {
|
abstract class ButtonStyleButton extends StatefulWidget {
|
||||||
/// Create a [ButtonStyleButton].
|
/// Create a [ButtonStyleButton].
|
||||||
const ButtonStyleButton({
|
const ButtonStyleButton({
|
||||||
Key? key,
|
Key key,
|
||||||
required this.onPressed,
|
@required this.onPressed,
|
||||||
required this.onLongPress,
|
@required this.onLongPress,
|
||||||
required this.style,
|
@required this.style,
|
||||||
required this.focusNode,
|
@required this.focusNode,
|
||||||
required this.autofocus,
|
@required this.autofocus,
|
||||||
required this.clipBehavior,
|
@required this.clipBehavior,
|
||||||
required this.child,
|
@required this.child,
|
||||||
}) : assert(autofocus != null),
|
}) : assert(autofocus != null),
|
||||||
assert(clipBehavior != null),
|
assert(clipBehavior != null),
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
@ -49,7 +51,7 @@ abstract class ButtonStyleButton extends StatefulWidget {
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [enabled], which is true if the button is enabled.
|
/// * [enabled], which is true if the button is enabled.
|
||||||
final VoidCallback? onPressed;
|
final VoidCallback onPressed;
|
||||||
|
|
||||||
/// Called when the button is long-pressed.
|
/// Called when the button is long-pressed.
|
||||||
///
|
///
|
||||||
|
@ -58,7 +60,7 @@ abstract class ButtonStyleButton extends StatefulWidget {
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [enabled], which is true if the button is enabled.
|
/// * [enabled], which is true if the button is enabled.
|
||||||
final VoidCallback? onLongPress;
|
final VoidCallback onLongPress;
|
||||||
|
|
||||||
/// Customizes this button's appearance.
|
/// Customizes this button's appearance.
|
||||||
///
|
///
|
||||||
|
@ -68,7 +70,7 @@ abstract class ButtonStyleButton extends StatefulWidget {
|
||||||
/// [MaterialStateProperty]s in [themeStyleOf] and [defaultStyleOf].
|
/// [MaterialStateProperty]s in [themeStyleOf] and [defaultStyleOf].
|
||||||
///
|
///
|
||||||
/// Null by default.
|
/// Null by default.
|
||||||
final ButtonStyle? style;
|
final ButtonStyle style;
|
||||||
|
|
||||||
/// {@macro flutter.widgets.Clip}
|
/// {@macro flutter.widgets.Clip}
|
||||||
///
|
///
|
||||||
|
@ -76,13 +78,13 @@ abstract class ButtonStyleButton extends StatefulWidget {
|
||||||
final Clip clipBehavior;
|
final Clip clipBehavior;
|
||||||
|
|
||||||
/// {@macro flutter.widgets.Focus.focusNode}
|
/// {@macro flutter.widgets.Focus.focusNode}
|
||||||
final FocusNode? focusNode;
|
final FocusNode focusNode;
|
||||||
|
|
||||||
/// {@macro flutter.widgets.Focus.autofocus}
|
/// {@macro flutter.widgets.Focus.autofocus}
|
||||||
final bool autofocus;
|
final bool autofocus;
|
||||||
|
|
||||||
/// Typically the button's label.
|
/// Typically the button's label.
|
||||||
final Widget? child;
|
final Widget child;
|
||||||
|
|
||||||
/// Returns a non-null [ButtonStyle] that's based primarily on the [Theme]'s
|
/// Returns a non-null [ButtonStyle] that's based primarily on the [Theme]'s
|
||||||
/// [ThemeData.textTheme] and [ThemeData.colorScheme].
|
/// [ThemeData.textTheme] and [ThemeData.colorScheme].
|
||||||
|
@ -115,7 +117,7 @@ abstract class ButtonStyleButton extends StatefulWidget {
|
||||||
///
|
///
|
||||||
/// * [defaultStyleOf], Returns the default [ButtonStyle] for this button.
|
/// * [defaultStyleOf], Returns the default [ButtonStyle] for this button.
|
||||||
@protected
|
@protected
|
||||||
ButtonStyle? themeStyleOf(BuildContext context);
|
ButtonStyle themeStyleOf(BuildContext context);
|
||||||
|
|
||||||
/// Whether the button is enabled or disabled.
|
/// Whether the button is enabled or disabled.
|
||||||
///
|
///
|
||||||
|
@ -137,7 +139,7 @@ abstract class ButtonStyleButton extends StatefulWidget {
|
||||||
/// Returns null if [value] is null, otherwise `MaterialStateProperty.all<T>(value)`.
|
/// Returns null if [value] is null, otherwise `MaterialStateProperty.all<T>(value)`.
|
||||||
///
|
///
|
||||||
/// A convenience method for subclasses.
|
/// A convenience method for subclasses.
|
||||||
static MaterialStateProperty<T>? allOrNull<T>(T? value) => value == null ? null : MaterialStateProperty.all<T>(value);
|
static MaterialStateProperty<T> allOrNull<T>(T value) => value == null ? null : MaterialStateProperty.all<T>(value);
|
||||||
|
|
||||||
/// Returns an interpolated value based on the [textScaleFactor] parameter:
|
/// Returns an interpolated value based on the [textScaleFactor] parameter:
|
||||||
///
|
///
|
||||||
|
@ -163,9 +165,9 @@ abstract class ButtonStyleButton extends StatefulWidget {
|
||||||
} else if (textScaleFactor >= 3) {
|
} else if (textScaleFactor >= 3) {
|
||||||
return geometry3x;
|
return geometry3x;
|
||||||
} else if (textScaleFactor <= 2) {
|
} else if (textScaleFactor <= 2) {
|
||||||
return EdgeInsetsGeometry.lerp(geometry1x, geometry2x, textScaleFactor - 1)!;
|
return EdgeInsetsGeometry.lerp(geometry1x, geometry2x, textScaleFactor - 1);
|
||||||
}
|
}
|
||||||
return EdgeInsetsGeometry.lerp(geometry2x, geometry3x, textScaleFactor - 2)!;
|
return EdgeInsetsGeometry.lerp(geometry2x, geometry3x, textScaleFactor - 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,9 +180,9 @@ abstract class ButtonStyleButton extends StatefulWidget {
|
||||||
/// * [ElevatedButton], a filled button whose material elevates when pressed.
|
/// * [ElevatedButton], a filled button whose material elevates when pressed.
|
||||||
/// * [OutlinedButton], similar to [TextButton], but with an outline.
|
/// * [OutlinedButton], similar to [TextButton], but with an outline.
|
||||||
class _ButtonStyleState extends State<ButtonStyleButton> with TickerProviderStateMixin {
|
class _ButtonStyleState extends State<ButtonStyleButton> with TickerProviderStateMixin {
|
||||||
AnimationController? _controller;
|
AnimationController _controller;
|
||||||
double? _elevation;
|
double _elevation;
|
||||||
Color? _backgroundColor;
|
Color _backgroundColor;
|
||||||
final Set<MaterialState> _states = <MaterialState>{};
|
final Set<MaterialState> _states = <MaterialState>{};
|
||||||
|
|
||||||
bool get _hovered => _states.contains(MaterialState.hovered);
|
bool get _hovered => _states.contains(MaterialState.hovered);
|
||||||
|
@ -243,54 +245,54 @@ class _ButtonStyleState extends State<ButtonStyleButton> with TickerProviderStat
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final ButtonStyle? widgetStyle = widget.style;
|
final ButtonStyle widgetStyle = widget.style;
|
||||||
final ButtonStyle? themeStyle = widget.themeStyleOf(context);
|
final ButtonStyle themeStyle = widget.themeStyleOf(context);
|
||||||
final ButtonStyle defaultStyle = widget.defaultStyleOf(context);
|
final ButtonStyle defaultStyle = widget.defaultStyleOf(context);
|
||||||
assert(defaultStyle != null);
|
assert(defaultStyle != null);
|
||||||
|
|
||||||
T? effectiveValue<T>(T? Function(ButtonStyle? style) getProperty) {
|
T effectiveValue<T>(T Function(ButtonStyle style) getProperty) {
|
||||||
final T? widgetValue = getProperty(widgetStyle);
|
final T widgetValue = getProperty(widgetStyle);
|
||||||
final T? themeValue = getProperty(themeStyle);
|
final T themeValue = getProperty(themeStyle);
|
||||||
final T? defaultValue = getProperty(defaultStyle);
|
final T defaultValue = getProperty(defaultStyle);
|
||||||
return widgetValue ?? themeValue ?? defaultValue;
|
return widgetValue ?? themeValue ?? defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
T? resolve<T>(MaterialStateProperty<T>? Function(ButtonStyle? style) getProperty) {
|
T resolve<T>(MaterialStateProperty<T> Function(ButtonStyle style) getProperty) {
|
||||||
return effectiveValue(
|
return effectiveValue(
|
||||||
(ButtonStyle? style) => getProperty(style)?.resolve(_states),
|
(ButtonStyle style) => getProperty(style)?.resolve(_states),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final double? resolvedElevation = resolve<double>((ButtonStyle? style) => style?.elevation);
|
final double resolvedElevation = resolve<double>((ButtonStyle style) => style?.elevation);
|
||||||
final TextStyle? resolvedTextStyle = resolve<TextStyle>((ButtonStyle? style) => style?.textStyle);
|
final TextStyle resolvedTextStyle = resolve<TextStyle>((ButtonStyle style) => style?.textStyle);
|
||||||
Color? resolvedBackgroundColor = resolve<Color>((ButtonStyle? style) => style?.backgroundColor);
|
Color resolvedBackgroundColor = resolve<Color>((ButtonStyle style) => style?.backgroundColor);
|
||||||
final Color? resolvedForegroundColor = resolve<Color>((ButtonStyle? style) => style?.foregroundColor);
|
final Color resolvedForegroundColor = resolve<Color>((ButtonStyle style) => style?.foregroundColor);
|
||||||
final Color? resolvedShadowColor = resolve<Color>((ButtonStyle? style) => style?.shadowColor);
|
final Color resolvedShadowColor = resolve<Color>((ButtonStyle style) => style?.shadowColor);
|
||||||
final EdgeInsetsGeometry? resolvedPadding = resolve<EdgeInsetsGeometry>((ButtonStyle? style) => style?.padding);
|
final EdgeInsetsGeometry resolvedPadding = resolve<EdgeInsetsGeometry>((ButtonStyle style) => style?.padding);
|
||||||
final Size? resolvedMinimumSize = resolve<Size>((ButtonStyle? style) => style?.minimumSize);
|
final Size resolvedMinimumSize = resolve<Size>((ButtonStyle style) => style?.minimumSize);
|
||||||
final BorderSide? resolvedSide = resolve<BorderSide>((ButtonStyle? style) => style?.side);
|
final BorderSide resolvedSide = resolve<BorderSide>((ButtonStyle style) => style?.side);
|
||||||
final OutlinedBorder? resolvedShape = resolve<OutlinedBorder>((ButtonStyle? style) => style?.shape);
|
final OutlinedBorder resolvedShape = resolve<OutlinedBorder>((ButtonStyle style) => style?.shape);
|
||||||
|
|
||||||
final MaterialStateMouseCursor resolvedMouseCursor = _MouseCursor(
|
final MaterialStateMouseCursor resolvedMouseCursor = _MouseCursor(
|
||||||
(Set<MaterialState> states) => effectiveValue((ButtonStyle? style) => style?.mouseCursor?.resolve(states)),
|
(Set<MaterialState> states) => effectiveValue((ButtonStyle style) => style?.mouseCursor?.resolve(states)),
|
||||||
);
|
);
|
||||||
|
|
||||||
final MaterialStateProperty<Color> overlayColor = MaterialStateProperty.resolveWith<Color>(
|
final MaterialStateProperty<Color> overlayColor = MaterialStateProperty.resolveWith<Color>(
|
||||||
(Set<MaterialState> states) => effectiveValue((ButtonStyle? style) => style?.overlayColor?.resolve(states)),
|
(Set<MaterialState> states) => effectiveValue((ButtonStyle style) => style?.overlayColor?.resolve(states)),
|
||||||
);
|
);
|
||||||
|
|
||||||
final VisualDensity? resolvedVisualDensity = effectiveValue((ButtonStyle? style) => style?.visualDensity);
|
final VisualDensity resolvedVisualDensity = effectiveValue((ButtonStyle style) => style?.visualDensity);
|
||||||
final MaterialTapTargetSize? resolvedTapTargetSize = effectiveValue((ButtonStyle? style) => style?.tapTargetSize);
|
final MaterialTapTargetSize resolvedTapTargetSize = effectiveValue((ButtonStyle style) => style?.tapTargetSize);
|
||||||
final Duration? resolvedAnimationDuration = effectiveValue((ButtonStyle? style) => style?.animationDuration);
|
final Duration resolvedAnimationDuration = effectiveValue((ButtonStyle style) => style?.animationDuration);
|
||||||
final bool? resolvedEnableFeedback = effectiveValue((ButtonStyle? style) => style?.enableFeedback);
|
final bool resolvedEnableFeedback = effectiveValue((ButtonStyle style) => style?.enableFeedback);
|
||||||
final Offset densityAdjustment = resolvedVisualDensity!.baseSizeAdjustment;
|
final Offset densityAdjustment = resolvedVisualDensity.baseSizeAdjustment;
|
||||||
final BoxConstraints effectiveConstraints = resolvedVisualDensity.effectiveConstraints(
|
final BoxConstraints effectiveConstraints = resolvedVisualDensity.effectiveConstraints(
|
||||||
BoxConstraints(
|
BoxConstraints(
|
||||||
minWidth: resolvedMinimumSize!.width,
|
minWidth: resolvedMinimumSize.width,
|
||||||
minHeight: resolvedMinimumSize.height,
|
minHeight: resolvedMinimumSize.height,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
final EdgeInsetsGeometry padding = resolvedPadding!.add(
|
final EdgeInsetsGeometry padding = resolvedPadding.add(
|
||||||
EdgeInsets.only(
|
EdgeInsets.only(
|
||||||
left: densityAdjustment.dx,
|
left: densityAdjustment.dx,
|
||||||
top: densityAdjustment.dy,
|
top: densityAdjustment.dy,
|
||||||
|
@ -303,12 +305,12 @@ class _ButtonStyleState extends State<ButtonStyleButton> with TickerProviderStat
|
||||||
// elevation is changing, change the elevation first. Material implicitly
|
// elevation is changing, change the elevation first. Material implicitly
|
||||||
// animates its elevation but not its color. SKIA renders non-zero
|
// animates its elevation but not its color. SKIA renders non-zero
|
||||||
// elevations as a shadow colored fill behind the Material's background.
|
// elevations as a shadow colored fill behind the Material's background.
|
||||||
if (resolvedAnimationDuration! > Duration.zero
|
if (resolvedAnimationDuration > Duration.zero
|
||||||
&& _elevation != null
|
&& _elevation != null
|
||||||
&& _backgroundColor != null
|
&& _backgroundColor != null
|
||||||
&& _elevation != resolvedElevation
|
&& _elevation != resolvedElevation
|
||||||
&& _backgroundColor!.value != resolvedBackgroundColor!.value
|
&& _backgroundColor.value != resolvedBackgroundColor.value
|
||||||
&& _backgroundColor!.opacity == 1
|
&& _backgroundColor.opacity == 1
|
||||||
&& resolvedBackgroundColor.opacity < 1
|
&& resolvedBackgroundColor.opacity < 1
|
||||||
&& resolvedElevation == 0) {
|
&& resolvedElevation == 0) {
|
||||||
if (_controller?.duration != resolvedAnimationDuration) {
|
if (_controller?.duration != resolvedAnimationDuration) {
|
||||||
|
@ -324,8 +326,8 @@ class _ButtonStyleState extends State<ButtonStyleButton> with TickerProviderStat
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
resolvedBackgroundColor = _backgroundColor; // Defer changing the background color.
|
resolvedBackgroundColor = _backgroundColor; // Defer changing the background color.
|
||||||
_controller!.value = 0;
|
_controller.value = 0;
|
||||||
_controller!.forward();
|
_controller.forward();
|
||||||
}
|
}
|
||||||
_elevation = resolvedElevation;
|
_elevation = resolvedElevation;
|
||||||
_backgroundColor = resolvedBackgroundColor;
|
_backgroundColor = resolvedBackgroundColor;
|
||||||
|
@ -333,9 +335,9 @@ class _ButtonStyleState extends State<ButtonStyleButton> with TickerProviderStat
|
||||||
final Widget result = ConstrainedBox(
|
final Widget result = ConstrainedBox(
|
||||||
constraints: effectiveConstraints,
|
constraints: effectiveConstraints,
|
||||||
child: Material(
|
child: Material(
|
||||||
elevation: resolvedElevation!,
|
elevation: resolvedElevation,
|
||||||
textStyle: resolvedTextStyle?.copyWith(color: resolvedForegroundColor),
|
textStyle: resolvedTextStyle?.copyWith(color: resolvedForegroundColor),
|
||||||
shape: resolvedShape!.copyWith(side: resolvedSide),
|
shape: resolvedShape.copyWith(side: resolvedSide),
|
||||||
color: resolvedBackgroundColor,
|
color: resolvedBackgroundColor,
|
||||||
shadowColor: resolvedShadowColor,
|
shadowColor: resolvedShadowColor,
|
||||||
type: resolvedBackgroundColor == null ? MaterialType.transparency : MaterialType.button,
|
type: resolvedBackgroundColor == null ? MaterialType.transparency : MaterialType.button,
|
||||||
|
@ -372,7 +374,7 @@ class _ButtonStyleState extends State<ButtonStyleButton> with TickerProviderStat
|
||||||
);
|
);
|
||||||
|
|
||||||
Size minSize;
|
Size minSize;
|
||||||
switch (resolvedTapTargetSize!) {
|
switch (resolvedTapTargetSize) {
|
||||||
case MaterialTapTargetSize.padded:
|
case MaterialTapTargetSize.padded:
|
||||||
minSize = Size(
|
minSize = Size(
|
||||||
kMinInteractiveDimension + densityAdjustment.dx,
|
kMinInteractiveDimension + densityAdjustment.dx,
|
||||||
|
@ -404,7 +406,7 @@ class _MouseCursor extends MaterialStateMouseCursor {
|
||||||
final MaterialPropertyResolver<MouseCursor> resolveCallback;
|
final MaterialPropertyResolver<MouseCursor> resolveCallback;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
MouseCursor? resolve(Set<MaterialState> states) => resolveCallback(states);
|
MouseCursor resolve(Set<MaterialState> states) => resolveCallback(states);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get debugDescription => 'ButtonStyleButton_MouseCursor';
|
String get debugDescription => 'ButtonStyleButton_MouseCursor';
|
||||||
|
@ -417,9 +419,9 @@ class _MouseCursor extends MaterialStateMouseCursor {
|
||||||
/// "tap target", but not its material or its ink splashes.
|
/// "tap target", but not its material or its ink splashes.
|
||||||
class _InputPadding extends SingleChildRenderObjectWidget {
|
class _InputPadding extends SingleChildRenderObjectWidget {
|
||||||
const _InputPadding({
|
const _InputPadding({
|
||||||
Key? key,
|
Key key,
|
||||||
Widget? child,
|
Widget child,
|
||||||
required this.minSize,
|
this.minSize,
|
||||||
}) : super(key: key, child: child);
|
}) : super(key: key, child: child);
|
||||||
|
|
||||||
final Size minSize;
|
final Size minSize;
|
||||||
|
@ -436,7 +438,7 @@ class _InputPadding extends SingleChildRenderObjectWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _RenderInputPadding extends RenderShiftedBox {
|
class _RenderInputPadding extends RenderShiftedBox {
|
||||||
_RenderInputPadding(this._minSize, [RenderBox? child]) : super(child);
|
_RenderInputPadding(this._minSize, [RenderBox child]) : super(child);
|
||||||
|
|
||||||
Size get minSize => _minSize;
|
Size get minSize => _minSize;
|
||||||
Size _minSize;
|
Size _minSize;
|
||||||
|
@ -450,28 +452,28 @@ class _RenderInputPadding extends RenderShiftedBox {
|
||||||
@override
|
@override
|
||||||
double computeMinIntrinsicWidth(double height) {
|
double computeMinIntrinsicWidth(double height) {
|
||||||
if (child != null)
|
if (child != null)
|
||||||
return math.max(child!.getMinIntrinsicWidth(height), minSize.width);
|
return math.max(child.getMinIntrinsicWidth(height), minSize.width);
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
double computeMinIntrinsicHeight(double width) {
|
double computeMinIntrinsicHeight(double width) {
|
||||||
if (child != null)
|
if (child != null)
|
||||||
return math.max(child!.getMinIntrinsicHeight(width), minSize.height);
|
return math.max(child.getMinIntrinsicHeight(width), minSize.height);
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
double computeMaxIntrinsicWidth(double height) {
|
double computeMaxIntrinsicWidth(double height) {
|
||||||
if (child != null)
|
if (child != null)
|
||||||
return math.max(child!.getMaxIntrinsicWidth(height), minSize.width);
|
return math.max(child.getMaxIntrinsicWidth(height), minSize.width);
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
double computeMaxIntrinsicHeight(double width) {
|
double computeMaxIntrinsicHeight(double width) {
|
||||||
if (child != null)
|
if (child != null)
|
||||||
return math.max(child!.getMaxIntrinsicHeight(width), minSize.height);
|
return math.max(child.getMaxIntrinsicHeight(width), minSize.height);
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -479,29 +481,29 @@ class _RenderInputPadding extends RenderShiftedBox {
|
||||||
void performLayout() {
|
void performLayout() {
|
||||||
final BoxConstraints constraints = this.constraints;
|
final BoxConstraints constraints = this.constraints;
|
||||||
if (child != null) {
|
if (child != null) {
|
||||||
child!.layout(constraints, parentUsesSize: true);
|
child.layout(constraints, parentUsesSize: true);
|
||||||
final double height = math.max(child!.size.width, minSize.width);
|
final double height = math.max(child.size.width, minSize.width);
|
||||||
final double width = math.max(child!.size.height, minSize.height);
|
final double width = math.max(child.size.height, minSize.height);
|
||||||
size = constraints.constrain(Size(height, width));
|
size = constraints.constrain(Size(height, width));
|
||||||
final BoxParentData childParentData = child!.parentData as BoxParentData;
|
final BoxParentData childParentData = child.parentData as BoxParentData;
|
||||||
childParentData.offset = Alignment.center.alongOffset(size - child!.size as Offset);
|
childParentData.offset = Alignment.center.alongOffset(size - child.size as Offset);
|
||||||
} else {
|
} else {
|
||||||
size = Size.zero;
|
size = Size.zero;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool hitTest(BoxHitTestResult result, { required Offset position }) {
|
bool hitTest(BoxHitTestResult result, { Offset position }) {
|
||||||
if (super.hitTest(result, position: position)) {
|
if (super.hitTest(result, position: position)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
final Offset center = child!.size.center(Offset.zero);
|
final Offset center = child.size.center(Offset.zero);
|
||||||
return result.addWithRawTransform(
|
return result.addWithRawTransform(
|
||||||
transform: MatrixUtils.forceToPoint(center),
|
transform: MatrixUtils.forceToPoint(center),
|
||||||
position: center,
|
position: center,
|
||||||
hitTest: (BoxHitTestResult result, Offset? position) {
|
hitTest: (BoxHitTestResult result, Offset position) {
|
||||||
assert(position == center);
|
assert(position == center);
|
||||||
return child!.hitTest(result, position: center);
|
return child.hitTest(result, position: center);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
// @dart = 2.8
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
|
@ -79,23 +81,23 @@ class ButtonTheme extends InheritedTheme {
|
||||||
/// The [textTheme], [minWidth], [height], and [colorScheme] arguments
|
/// The [textTheme], [minWidth], [height], and [colorScheme] arguments
|
||||||
/// must not be null.
|
/// must not be null.
|
||||||
ButtonTheme({
|
ButtonTheme({
|
||||||
Key? key,
|
Key key,
|
||||||
ButtonTextTheme textTheme = ButtonTextTheme.normal,
|
ButtonTextTheme textTheme = ButtonTextTheme.normal,
|
||||||
ButtonBarLayoutBehavior layoutBehavior = ButtonBarLayoutBehavior.padded,
|
ButtonBarLayoutBehavior layoutBehavior = ButtonBarLayoutBehavior.padded,
|
||||||
double minWidth = 88.0,
|
double minWidth = 88.0,
|
||||||
double height = 36.0,
|
double height = 36.0,
|
||||||
EdgeInsetsGeometry? padding,
|
EdgeInsetsGeometry padding,
|
||||||
ShapeBorder? shape,
|
ShapeBorder shape,
|
||||||
bool alignedDropdown = false,
|
bool alignedDropdown = false,
|
||||||
Color? buttonColor,
|
Color buttonColor,
|
||||||
Color? disabledColor,
|
Color disabledColor,
|
||||||
Color? focusColor,
|
Color focusColor,
|
||||||
Color? hoverColor,
|
Color hoverColor,
|
||||||
Color? highlightColor,
|
Color highlightColor,
|
||||||
Color? splashColor,
|
Color splashColor,
|
||||||
ColorScheme? colorScheme,
|
ColorScheme colorScheme,
|
||||||
MaterialTapTargetSize? materialTapTargetSize,
|
MaterialTapTargetSize materialTapTargetSize,
|
||||||
required Widget child,
|
Widget child,
|
||||||
}) : assert(textTheme != null),
|
}) : assert(textTheme != null),
|
||||||
assert(minWidth != null && minWidth >= 0.0),
|
assert(minWidth != null && minWidth >= 0.0),
|
||||||
assert(height != null && height >= 0.0),
|
assert(height != null && height >= 0.0),
|
||||||
|
@ -124,9 +126,9 @@ class ButtonTheme extends InheritedTheme {
|
||||||
///
|
///
|
||||||
/// The [data] argument must not be null.
|
/// The [data] argument must not be null.
|
||||||
const ButtonTheme.fromButtonThemeData({
|
const ButtonTheme.fromButtonThemeData({
|
||||||
Key? key,
|
Key key,
|
||||||
required this.data,
|
@required this.data,
|
||||||
required Widget child,
|
Widget child,
|
||||||
}) : assert(data != null),
|
}) : assert(data != null),
|
||||||
super(key: key, child: child);
|
super(key: key, child: child);
|
||||||
|
|
||||||
|
@ -175,21 +177,21 @@ class ButtonTheme extends InheritedTheme {
|
||||||
'This feature was deprecated after v1.9.1.'
|
'This feature was deprecated after v1.9.1.'
|
||||||
)
|
)
|
||||||
ButtonTheme.bar({
|
ButtonTheme.bar({
|
||||||
Key? key,
|
Key key,
|
||||||
ButtonTextTheme textTheme = ButtonTextTheme.accent,
|
ButtonTextTheme textTheme = ButtonTextTheme.accent,
|
||||||
double minWidth = 64.0,
|
double minWidth = 64.0,
|
||||||
double height = 36.0,
|
double height = 36.0,
|
||||||
EdgeInsetsGeometry padding = const EdgeInsets.symmetric(horizontal: 8.0),
|
EdgeInsetsGeometry padding = const EdgeInsets.symmetric(horizontal: 8.0),
|
||||||
ShapeBorder? shape,
|
ShapeBorder shape,
|
||||||
bool alignedDropdown = false,
|
bool alignedDropdown = false,
|
||||||
Color? buttonColor,
|
Color buttonColor,
|
||||||
Color? disabledColor,
|
Color disabledColor,
|
||||||
Color? focusColor,
|
Color focusColor,
|
||||||
Color? hoverColor,
|
Color hoverColor,
|
||||||
Color? highlightColor,
|
Color highlightColor,
|
||||||
Color? splashColor,
|
Color splashColor,
|
||||||
ColorScheme? colorScheme,
|
ColorScheme colorScheme,
|
||||||
required Widget child,
|
Widget child,
|
||||||
ButtonBarLayoutBehavior layoutBehavior = ButtonBarLayoutBehavior.padded,
|
ButtonBarLayoutBehavior layoutBehavior = ButtonBarLayoutBehavior.padded,
|
||||||
}) : assert(textTheme != null),
|
}) : assert(textTheme != null),
|
||||||
assert(minWidth != null && minWidth >= 0.0),
|
assert(minWidth != null && minWidth >= 0.0),
|
||||||
|
@ -224,10 +226,10 @@ class ButtonTheme extends InheritedTheme {
|
||||||
/// ButtonThemeData theme = ButtonTheme.of(context);
|
/// ButtonThemeData theme = ButtonTheme.of(context);
|
||||||
/// ```
|
/// ```
|
||||||
static ButtonThemeData of(BuildContext context) {
|
static ButtonThemeData of(BuildContext context) {
|
||||||
final ButtonTheme? inheritedButtonTheme = context.dependOnInheritedWidgetOfExactType<ButtonTheme>();
|
final ButtonTheme inheritedButtonTheme = context.dependOnInheritedWidgetOfExactType<ButtonTheme>();
|
||||||
ButtonThemeData? buttonTheme = inheritedButtonTheme?.data;
|
ButtonThemeData buttonTheme = inheritedButtonTheme?.data;
|
||||||
if (buttonTheme?.colorScheme == null) { // if buttonTheme or buttonTheme.colorScheme is null
|
if (buttonTheme?.colorScheme == null) { // if buttonTheme or buttonTheme.colorScheme is null
|
||||||
final ThemeData theme = Theme.of(context)!;
|
final ThemeData theme = Theme.of(context);
|
||||||
buttonTheme ??= theme.buttonTheme;
|
buttonTheme ??= theme.buttonTheme;
|
||||||
if (buttonTheme.colorScheme == null) {
|
if (buttonTheme.colorScheme == null) {
|
||||||
buttonTheme = buttonTheme.copyWith(
|
buttonTheme = buttonTheme.copyWith(
|
||||||
|
@ -236,12 +238,12 @@ class ButtonTheme extends InheritedTheme {
|
||||||
assert(buttonTheme.colorScheme != null);
|
assert(buttonTheme.colorScheme != null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return buttonTheme!;
|
return buttonTheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget wrap(BuildContext context, Widget child) {
|
Widget wrap(BuildContext context, Widget child) {
|
||||||
final ButtonTheme? ancestorTheme = context.findAncestorWidgetOfExactType<ButtonTheme>();
|
final ButtonTheme ancestorTheme = context.findAncestorWidgetOfExactType<ButtonTheme>();
|
||||||
return identical(this, ancestorTheme) ? child : ButtonTheme.fromButtonThemeData(data: data, child: child);
|
return identical(this, ancestorTheme) ? child : ButtonTheme.fromButtonThemeData(data: data, child: child);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,18 +289,18 @@ class ButtonThemeData with Diagnosticable {
|
||||||
this.textTheme = ButtonTextTheme.normal,
|
this.textTheme = ButtonTextTheme.normal,
|
||||||
this.minWidth = 88.0,
|
this.minWidth = 88.0,
|
||||||
this.height = 36.0,
|
this.height = 36.0,
|
||||||
EdgeInsetsGeometry? padding,
|
EdgeInsetsGeometry padding,
|
||||||
ShapeBorder? shape,
|
ShapeBorder shape,
|
||||||
this.layoutBehavior = ButtonBarLayoutBehavior.padded,
|
this.layoutBehavior = ButtonBarLayoutBehavior.padded,
|
||||||
this.alignedDropdown = false,
|
this.alignedDropdown = false,
|
||||||
Color? buttonColor,
|
Color buttonColor,
|
||||||
Color? disabledColor,
|
Color disabledColor,
|
||||||
Color? focusColor,
|
Color focusColor,
|
||||||
Color? hoverColor,
|
Color hoverColor,
|
||||||
Color? highlightColor,
|
Color highlightColor,
|
||||||
Color? splashColor,
|
Color splashColor,
|
||||||
this.colorScheme,
|
this.colorScheme,
|
||||||
MaterialTapTargetSize? materialTapTargetSize,
|
MaterialTapTargetSize materialTapTargetSize,
|
||||||
}) : assert(textTheme != null),
|
}) : assert(textTheme != null),
|
||||||
assert(minWidth != null && minWidth >= 0.0),
|
assert(minWidth != null && minWidth >= 0.0),
|
||||||
assert(height != null && height >= 0.0),
|
assert(height != null && height >= 0.0),
|
||||||
|
@ -367,7 +369,7 @@ class ButtonThemeData with Diagnosticable {
|
||||||
/// and [FlatButton].
|
/// and [FlatButton].
|
||||||
EdgeInsetsGeometry get padding {
|
EdgeInsetsGeometry get padding {
|
||||||
if (_padding != null)
|
if (_padding != null)
|
||||||
return _padding!;
|
return _padding;
|
||||||
switch (textTheme) {
|
switch (textTheme) {
|
||||||
case ButtonTextTheme.normal:
|
case ButtonTextTheme.normal:
|
||||||
case ButtonTextTheme.accent:
|
case ButtonTextTheme.accent:
|
||||||
|
@ -375,8 +377,10 @@ class ButtonThemeData with Diagnosticable {
|
||||||
case ButtonTextTheme.primary:
|
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;
|
final EdgeInsetsGeometry _padding;
|
||||||
|
|
||||||
/// The shape of a button's material.
|
/// The shape of a button's material.
|
||||||
///
|
///
|
||||||
|
@ -394,7 +398,7 @@ class ButtonThemeData with Diagnosticable {
|
||||||
/// and [FlatButton].
|
/// and [FlatButton].
|
||||||
ShapeBorder get shape {
|
ShapeBorder get shape {
|
||||||
if (_shape != null)
|
if (_shape != null)
|
||||||
return _shape!;
|
return _shape;
|
||||||
switch (textTheme) {
|
switch (textTheme) {
|
||||||
case ButtonTextTheme.normal:
|
case ButtonTextTheme.normal:
|
||||||
case ButtonTextTheme.accent:
|
case ButtonTextTheme.accent:
|
||||||
|
@ -406,8 +410,9 @@ class ButtonThemeData with Diagnosticable {
|
||||||
borderRadius: BorderRadius.all(Radius.circular(4.0)),
|
borderRadius: BorderRadius.all(Radius.circular(4.0)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
return const RoundedRectangleBorder();
|
||||||
}
|
}
|
||||||
final ShapeBorder? _shape;
|
final ShapeBorder _shape;
|
||||||
|
|
||||||
/// If true, then a [DropdownButton] menu's width will match the button's
|
/// If true, then a [DropdownButton] menu's width will match the button's
|
||||||
/// width.
|
/// width.
|
||||||
|
@ -432,7 +437,7 @@ class ButtonThemeData with Diagnosticable {
|
||||||
///
|
///
|
||||||
/// * [getFillColor], which is used by [RaisedButton] to compute its
|
/// * [getFillColor], which is used by [RaisedButton] to compute its
|
||||||
/// background fill color.
|
/// background fill color.
|
||||||
final Color? _buttonColor;
|
final Color _buttonColor;
|
||||||
|
|
||||||
/// The background fill color for disabled [RaisedButton]s.
|
/// The background fill color for disabled [RaisedButton]s.
|
||||||
///
|
///
|
||||||
|
@ -442,7 +447,7 @@ class ButtonThemeData with Diagnosticable {
|
||||||
///
|
///
|
||||||
/// * [getDisabledFillColor], which is used by [RaisedButton] to compute its
|
/// * [getDisabledFillColor], which is used by [RaisedButton] to compute its
|
||||||
/// background fill color.
|
/// background fill color.
|
||||||
final Color? _disabledColor;
|
final Color _disabledColor;
|
||||||
|
|
||||||
/// The fill color of the button when it has the input focus.
|
/// The fill color of the button when it has the input focus.
|
||||||
///
|
///
|
||||||
|
@ -455,7 +460,7 @@ class ButtonThemeData with Diagnosticable {
|
||||||
///
|
///
|
||||||
/// * [getFocusColor], which is used by [RaisedButton], [OutlineButton]
|
/// * [getFocusColor], which is used by [RaisedButton], [OutlineButton]
|
||||||
/// and [FlatButton].
|
/// and [FlatButton].
|
||||||
final Color? _focusColor;
|
final Color _focusColor;
|
||||||
|
|
||||||
/// The fill color of the button when a pointer is hovering over it.
|
/// The fill color of the button when a pointer is hovering over it.
|
||||||
///
|
///
|
||||||
|
@ -468,7 +473,7 @@ class ButtonThemeData with Diagnosticable {
|
||||||
///
|
///
|
||||||
/// * [getHoverColor], which is used by [RaisedButton], [OutlineButton]
|
/// * [getHoverColor], which is used by [RaisedButton], [OutlineButton]
|
||||||
/// and [FlatButton].
|
/// and [FlatButton].
|
||||||
final Color? _hoverColor;
|
final Color _hoverColor;
|
||||||
|
|
||||||
/// The color of the overlay that appears when a button is pressed.
|
/// The color of the overlay that appears when a button is pressed.
|
||||||
///
|
///
|
||||||
|
@ -478,7 +483,7 @@ class ButtonThemeData with Diagnosticable {
|
||||||
///
|
///
|
||||||
/// * [getHighlightColor], which is used by [RaisedButton], [OutlineButton]
|
/// * [getHighlightColor], which is used by [RaisedButton], [OutlineButton]
|
||||||
/// and [FlatButton].
|
/// and [FlatButton].
|
||||||
final Color? _highlightColor;
|
final Color _highlightColor;
|
||||||
|
|
||||||
/// The color of the ink "splash" overlay that appears when a button is tapped.
|
/// The color of the ink "splash" overlay that appears when a button is tapped.
|
||||||
///
|
///
|
||||||
|
@ -488,7 +493,7 @@ class ButtonThemeData with Diagnosticable {
|
||||||
///
|
///
|
||||||
/// * [getSplashColor], which is used by [RaisedButton], [OutlineButton]
|
/// * [getSplashColor], which is used by [RaisedButton], [OutlineButton]
|
||||||
/// and [FlatButton].
|
/// and [FlatButton].
|
||||||
final Color? _splashColor;
|
final Color _splashColor;
|
||||||
|
|
||||||
/// A set of thirteen colors that can be used to derive the button theme's
|
/// A set of thirteen colors that can be used to derive the button theme's
|
||||||
/// colors.
|
/// colors.
|
||||||
|
@ -500,7 +505,7 @@ class ButtonThemeData with Diagnosticable {
|
||||||
/// The colors for new button classes can be defined exclusively in terms
|
/// The colors for new button classes can be defined exclusively in terms
|
||||||
/// of [colorScheme]. When it's possible, the existing buttons will
|
/// of [colorScheme]. When it's possible, the existing buttons will
|
||||||
/// (continue to) gradually migrate to it.
|
/// (continue to) gradually migrate to it.
|
||||||
final ColorScheme? colorScheme;
|
final ColorScheme colorScheme;
|
||||||
|
|
||||||
// The minimum size of a button's tap target.
|
// The minimum size of a button's tap target.
|
||||||
//
|
//
|
||||||
|
@ -510,14 +515,14 @@ class ButtonThemeData with Diagnosticable {
|
||||||
//
|
//
|
||||||
// * [getMaterialTargetTapSize], which is used by [RaisedButton],
|
// * [getMaterialTargetTapSize], which is used by [RaisedButton],
|
||||||
// [OutlineButton] and [FlatButton].
|
// [OutlineButton] and [FlatButton].
|
||||||
final MaterialTapTargetSize? _materialTapTargetSize;
|
final MaterialTapTargetSize _materialTapTargetSize;
|
||||||
|
|
||||||
/// The [button]'s overall brightness.
|
/// The [button]'s overall brightness.
|
||||||
///
|
///
|
||||||
/// Returns the button's [MaterialButton.colorBrightness] if it is non-null,
|
/// Returns the button's [MaterialButton.colorBrightness] if it is non-null,
|
||||||
/// otherwise the color scheme's [ColorScheme.brightness] is returned.
|
/// otherwise the color scheme's [ColorScheme.brightness] is returned.
|
||||||
Brightness getBrightness(MaterialButton button) {
|
Brightness getBrightness(MaterialButton button) {
|
||||||
return button.colorBrightness ?? colorScheme!.brightness;
|
return button.colorBrightness ?? colorScheme.brightness;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Defines the [button]'s base colors, and the defaults for the button's
|
/// Defines the [button]'s base colors, and the defaults for the button's
|
||||||
|
@ -540,10 +545,10 @@ class ButtonThemeData with Diagnosticable {
|
||||||
/// used as the `disabledTextColor`. It will be resolved in the [MaterialState.disabled] state.
|
/// used as the `disabledTextColor`. It will be resolved in the [MaterialState.disabled] state.
|
||||||
Color getDisabledTextColor(MaterialButton button) {
|
Color getDisabledTextColor(MaterialButton button) {
|
||||||
if (button.textColor is MaterialStateProperty<Color>)
|
if (button.textColor is MaterialStateProperty<Color>)
|
||||||
return button.textColor!;
|
return button.textColor;
|
||||||
if (button.disabledTextColor != null)
|
if (button.disabledTextColor != null)
|
||||||
return button.disabledTextColor!;
|
return button.disabledTextColor;
|
||||||
return colorScheme!.onSurface.withOpacity(0.38);
|
return colorScheme.onSurface.withOpacity(0.38);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The [button]'s background color when [MaterialButton.onPressed] is null
|
/// The [button]'s background color when [MaterialButton.onPressed] is null
|
||||||
|
@ -558,10 +563,10 @@ class ButtonThemeData with Diagnosticable {
|
||||||
/// with its opacity set to 0.38.
|
/// with its opacity set to 0.38.
|
||||||
Color getDisabledFillColor(MaterialButton button) {
|
Color getDisabledFillColor(MaterialButton button) {
|
||||||
if (button.disabledColor != null)
|
if (button.disabledColor != null)
|
||||||
return button.disabledColor!;
|
return button.disabledColor;
|
||||||
if (_disabledColor != null)
|
if (_disabledColor != null)
|
||||||
return _disabledColor!;
|
return _disabledColor;
|
||||||
return colorScheme!.onSurface.withOpacity(0.38);
|
return colorScheme.onSurface.withOpacity(0.38);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The button's background fill color or null for buttons that don't have
|
/// The button's background fill color or null for buttons that don't have
|
||||||
|
@ -589,8 +594,8 @@ class ButtonThemeData with Diagnosticable {
|
||||||
/// otherwise the color scheme's ColorScheme.primary color. If the button
|
/// otherwise the color scheme's ColorScheme.primary color. If the button
|
||||||
/// is not enabled then the colorScheme's [ColorScheme.onSurface] color
|
/// is not enabled then the colorScheme's [ColorScheme.onSurface] color
|
||||||
/// with opacity 0.12.
|
/// with opacity 0.12.
|
||||||
Color? getFillColor(MaterialButton button) {
|
Color getFillColor(MaterialButton button) {
|
||||||
final Color? fillColor = button.enabled ? button.color : button.disabledColor;
|
final Color fillColor = button.enabled ? button.color : button.disabledColor;
|
||||||
if (fillColor != null)
|
if (fillColor != null)
|
||||||
return fillColor;
|
return fillColor;
|
||||||
|
|
||||||
|
@ -603,12 +608,15 @@ class ButtonThemeData with Diagnosticable {
|
||||||
switch (getTextTheme(button)) {
|
switch (getTextTheme(button)) {
|
||||||
case ButtonTextTheme.normal:
|
case ButtonTextTheme.normal:
|
||||||
case ButtonTextTheme.accent:
|
case ButtonTextTheme.accent:
|
||||||
return button.enabled ? colorScheme!.primary : getDisabledFillColor(button);
|
return button.enabled ? colorScheme.primary : getDisabledFillColor(button);
|
||||||
case ButtonTextTheme.primary:
|
case ButtonTextTheme.primary:
|
||||||
return button.enabled
|
return button.enabled
|
||||||
? _buttonColor ?? colorScheme!.primary
|
? _buttonColor ?? colorScheme.primary
|
||||||
: colorScheme!.onSurface.withOpacity(0.12);
|
: colorScheme.onSurface.withOpacity(0.12);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(false);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The foreground color of the [button]'s text and icon.
|
/// The foreground color of the [button]'s text and icon.
|
||||||
|
@ -633,26 +641,29 @@ class ButtonThemeData with Diagnosticable {
|
||||||
return getDisabledTextColor(button);
|
return getDisabledTextColor(button);
|
||||||
|
|
||||||
if (button.textColor != null)
|
if (button.textColor != null)
|
||||||
return button.textColor!;
|
return button.textColor;
|
||||||
|
|
||||||
switch (getTextTheme(button)) {
|
switch (getTextTheme(button)) {
|
||||||
case ButtonTextTheme.normal:
|
case ButtonTextTheme.normal:
|
||||||
return getBrightness(button) == Brightness.dark ? Colors.white : Colors.black87;
|
return getBrightness(button) == Brightness.dark ? Colors.white : Colors.black87;
|
||||||
|
|
||||||
case ButtonTextTheme.accent:
|
case ButtonTextTheme.accent:
|
||||||
return colorScheme!.secondary;
|
return colorScheme.secondary;
|
||||||
|
|
||||||
case ButtonTextTheme.primary:
|
case ButtonTextTheme.primary:
|
||||||
final Color? fillColor = getFillColor(button);
|
final Color fillColor = getFillColor(button);
|
||||||
final bool fillIsDark = fillColor != null
|
final bool fillIsDark = fillColor != null
|
||||||
? ThemeData.estimateBrightnessForColor(fillColor) == Brightness.dark
|
? ThemeData.estimateBrightnessForColor(fillColor) == Brightness.dark
|
||||||
: getBrightness(button) == Brightness.dark;
|
: getBrightness(button) == Brightness.dark;
|
||||||
if (fillIsDark)
|
if (fillIsDark)
|
||||||
return Colors.white;
|
return Colors.white;
|
||||||
if (button is FlatButton || button is OutlineButton)
|
if (button is FlatButton || button is OutlineButton)
|
||||||
return colorScheme!.primary;
|
return colorScheme.primary;
|
||||||
return Colors.black;
|
return Colors.black;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(false);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The color of the ink "splash" overlay that appears when the (enabled)
|
/// The color of the ink "splash" overlay that appears when the (enabled)
|
||||||
|
@ -670,16 +681,16 @@ class ButtonThemeData with Diagnosticable {
|
||||||
/// Otherwise, returns [getTextColor] with an opacity of 0.12.
|
/// Otherwise, returns [getTextColor] with an opacity of 0.12.
|
||||||
Color getSplashColor(MaterialButton button) {
|
Color getSplashColor(MaterialButton button) {
|
||||||
if (button.splashColor != null)
|
if (button.splashColor != null)
|
||||||
return button.splashColor!;
|
return button.splashColor;
|
||||||
|
|
||||||
if (_splashColor != null && (button is RaisedButton || button is OutlineButton))
|
if (_splashColor != null && (button is RaisedButton || button is OutlineButton))
|
||||||
return _splashColor!;
|
return _splashColor;
|
||||||
|
|
||||||
if (_splashColor != null && button is FlatButton) {
|
if (_splashColor != null && button is FlatButton) {
|
||||||
switch (getTextTheme(button)) {
|
switch (getTextTheme(button)) {
|
||||||
case ButtonTextTheme.normal:
|
case ButtonTextTheme.normal:
|
||||||
case ButtonTextTheme.accent:
|
case ButtonTextTheme.accent:
|
||||||
return _splashColor!;
|
return _splashColor;
|
||||||
case ButtonTextTheme.primary:
|
case ButtonTextTheme.primary:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -725,7 +736,7 @@ class ButtonThemeData with Diagnosticable {
|
||||||
/// * [ButtonTextTheme.primary], returns [Colors.transparent].
|
/// * [ButtonTextTheme.primary], returns [Colors.transparent].
|
||||||
Color getHighlightColor(MaterialButton button) {
|
Color getHighlightColor(MaterialButton button) {
|
||||||
if (button.highlightColor != null)
|
if (button.highlightColor != null)
|
||||||
return button.highlightColor!;
|
return button.highlightColor;
|
||||||
|
|
||||||
switch (getTextTheme(button)) {
|
switch (getTextTheme(button)) {
|
||||||
case ButtonTextTheme.normal:
|
case ButtonTextTheme.normal:
|
||||||
|
@ -734,6 +745,9 @@ class ButtonThemeData with Diagnosticable {
|
||||||
case ButtonTextTheme.primary:
|
case ButtonTextTheme.primary:
|
||||||
return Colors.transparent;
|
return Colors.transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(false);
|
||||||
|
return Colors.transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The [button]'s elevation when it is enabled and has not been pressed.
|
/// The [button]'s elevation when it is enabled and has not been pressed.
|
||||||
|
@ -743,7 +757,7 @@ class ButtonThemeData with Diagnosticable {
|
||||||
/// If button is a [FlatButton] then elevation is 0.0, otherwise it is 2.0.
|
/// If button is a [FlatButton] then elevation is 0.0, otherwise it is 2.0.
|
||||||
double getElevation(MaterialButton button) {
|
double getElevation(MaterialButton button) {
|
||||||
if (button.elevation != null)
|
if (button.elevation != null)
|
||||||
return button.elevation!;
|
return button.elevation;
|
||||||
if (button is FlatButton)
|
if (button is FlatButton)
|
||||||
return 0.0;
|
return 0.0;
|
||||||
return 2.0;
|
return 2.0;
|
||||||
|
@ -757,7 +771,7 @@ class ButtonThemeData with Diagnosticable {
|
||||||
/// elevation is 0.0, otherwise the highlight elevation is 4.0.
|
/// elevation is 0.0, otherwise the highlight elevation is 4.0.
|
||||||
double getFocusElevation(MaterialButton button) {
|
double getFocusElevation(MaterialButton button) {
|
||||||
if (button.focusElevation != null)
|
if (button.focusElevation != null)
|
||||||
return button.focusElevation!;
|
return button.focusElevation;
|
||||||
if (button is FlatButton)
|
if (button is FlatButton)
|
||||||
return 0.0;
|
return 0.0;
|
||||||
if (button is OutlineButton)
|
if (button is OutlineButton)
|
||||||
|
@ -773,7 +787,7 @@ class ButtonThemeData with Diagnosticable {
|
||||||
/// elevation is 0.0, otherwise the highlight elevation is 4.0.
|
/// elevation is 0.0, otherwise the highlight elevation is 4.0.
|
||||||
double getHoverElevation(MaterialButton button) {
|
double getHoverElevation(MaterialButton button) {
|
||||||
if (button.hoverElevation != null)
|
if (button.hoverElevation != null)
|
||||||
return button.hoverElevation!;
|
return button.hoverElevation;
|
||||||
if (button is FlatButton)
|
if (button is FlatButton)
|
||||||
return 0.0;
|
return 0.0;
|
||||||
if (button is OutlineButton)
|
if (button is OutlineButton)
|
||||||
|
@ -789,7 +803,7 @@ class ButtonThemeData with Diagnosticable {
|
||||||
/// elevation is 0.0, otherwise the highlight elevation is 8.0.
|
/// elevation is 0.0, otherwise the highlight elevation is 8.0.
|
||||||
double getHighlightElevation(MaterialButton button) {
|
double getHighlightElevation(MaterialButton button) {
|
||||||
if (button.highlightElevation != null)
|
if (button.highlightElevation != null)
|
||||||
return button.highlightElevation!;
|
return button.highlightElevation;
|
||||||
if (button is FlatButton)
|
if (button is FlatButton)
|
||||||
return 0.0;
|
return 0.0;
|
||||||
if (button is OutlineButton)
|
if (button is OutlineButton)
|
||||||
|
@ -805,7 +819,7 @@ class ButtonThemeData with Diagnosticable {
|
||||||
/// Otherwise the disabled elevation is 0.0.
|
/// Otherwise the disabled elevation is 0.0.
|
||||||
double getDisabledElevation(MaterialButton button) {
|
double getDisabledElevation(MaterialButton button) {
|
||||||
if (button.disabledElevation != null)
|
if (button.disabledElevation != null)
|
||||||
return button.disabledElevation!;
|
return button.disabledElevation;
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -824,13 +838,13 @@ class ButtonThemeData with Diagnosticable {
|
||||||
/// otherwise.
|
/// otherwise.
|
||||||
EdgeInsetsGeometry getPadding(MaterialButton button) {
|
EdgeInsetsGeometry getPadding(MaterialButton button) {
|
||||||
if (button.padding != null)
|
if (button.padding != null)
|
||||||
return button.padding!;
|
return button.padding;
|
||||||
|
|
||||||
if (button is MaterialButtonWithIconMixin)
|
if (button is MaterialButtonWithIconMixin)
|
||||||
return const EdgeInsetsDirectional.only(start: 12.0, end: 16.0);
|
return const EdgeInsetsDirectional.only(start: 12.0, end: 16.0);
|
||||||
|
|
||||||
if (_padding != null)
|
if (_padding != null)
|
||||||
return _padding!;
|
return _padding;
|
||||||
|
|
||||||
switch (getTextTheme(button)) {
|
switch (getTextTheme(button)) {
|
||||||
case ButtonTextTheme.normal:
|
case ButtonTextTheme.normal:
|
||||||
|
@ -839,6 +853,8 @@ class ButtonThemeData with Diagnosticable {
|
||||||
case ButtonTextTheme.primary:
|
case ButtonTextTheme.primary:
|
||||||
return const EdgeInsets.symmetric(horizontal: 24.0);
|
return const EdgeInsets.symmetric(horizontal: 24.0);
|
||||||
}
|
}
|
||||||
|
assert(false);
|
||||||
|
return EdgeInsets.zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The shape of the [button]'s [Material].
|
/// The shape of the [button]'s [Material].
|
||||||
|
@ -879,21 +895,21 @@ class ButtonThemeData with Diagnosticable {
|
||||||
/// Creates a copy of this button theme data object with the matching fields
|
/// Creates a copy of this button theme data object with the matching fields
|
||||||
/// replaced with the non-null parameter values.
|
/// replaced with the non-null parameter values.
|
||||||
ButtonThemeData copyWith({
|
ButtonThemeData copyWith({
|
||||||
ButtonTextTheme? textTheme,
|
ButtonTextTheme textTheme,
|
||||||
ButtonBarLayoutBehavior? layoutBehavior,
|
ButtonBarLayoutBehavior layoutBehavior,
|
||||||
double? minWidth,
|
double minWidth,
|
||||||
double? height,
|
double height,
|
||||||
EdgeInsetsGeometry? padding,
|
EdgeInsetsGeometry padding,
|
||||||
ShapeBorder? shape,
|
ShapeBorder shape,
|
||||||
bool? alignedDropdown,
|
bool alignedDropdown,
|
||||||
Color? buttonColor,
|
Color buttonColor,
|
||||||
Color? disabledColor,
|
Color disabledColor,
|
||||||
Color? focusColor,
|
Color focusColor,
|
||||||
Color? hoverColor,
|
Color hoverColor,
|
||||||
Color? highlightColor,
|
Color highlightColor,
|
||||||
Color? splashColor,
|
Color splashColor,
|
||||||
ColorScheme? colorScheme,
|
ColorScheme colorScheme,
|
||||||
MaterialTapTargetSize? materialTapTargetSize,
|
MaterialTapTargetSize materialTapTargetSize,
|
||||||
}) {
|
}) {
|
||||||
return ButtonThemeData(
|
return ButtonThemeData(
|
||||||
textTheme: textTheme ?? this.textTheme,
|
textTheme: textTheme ?? this.textTheme,
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
// @dart = 2.8
|
||||||
|
|
||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
@ -63,8 +65,8 @@ class MaterialButton extends StatelessWidget {
|
||||||
/// [highlightElevation], and [disabledElevation] must be non-negative, if
|
/// [highlightElevation], and [disabledElevation] must be non-negative, if
|
||||||
/// specified.
|
/// specified.
|
||||||
const MaterialButton({
|
const MaterialButton({
|
||||||
Key? key,
|
Key key,
|
||||||
required this.onPressed,
|
@required this.onPressed,
|
||||||
this.onLongPress,
|
this.onLongPress,
|
||||||
this.onHighlightChanged,
|
this.onHighlightChanged,
|
||||||
this.mouseCursor,
|
this.mouseCursor,
|
||||||
|
@ -111,7 +113,7 @@ class MaterialButton extends StatelessWidget {
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [enabled], which is true if the button is enabled.
|
/// * [enabled], which is true if the button is enabled.
|
||||||
final VoidCallback? onPressed;
|
final VoidCallback onPressed;
|
||||||
|
|
||||||
/// The callback that is called when the button is long-pressed.
|
/// The callback that is called when the button is long-pressed.
|
||||||
///
|
///
|
||||||
|
@ -120,7 +122,7 @@ class MaterialButton extends StatelessWidget {
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [enabled], which is true if the button is enabled.
|
/// * [enabled], which is true if the button is enabled.
|
||||||
final VoidCallback? onLongPress;
|
final VoidCallback onLongPress;
|
||||||
|
|
||||||
/// Called by the underlying [InkWell] widget's [InkWell.onHighlightChanged]
|
/// Called by the underlying [InkWell] widget's [InkWell.onHighlightChanged]
|
||||||
/// callback.
|
/// callback.
|
||||||
|
@ -128,16 +130,16 @@ class MaterialButton extends StatelessWidget {
|
||||||
/// If [onPressed] changes from null to non-null while a gesture is ongoing,
|
/// If [onPressed] changes from null to non-null while a gesture is ongoing,
|
||||||
/// this can fire during the build phase (in which case calling
|
/// this can fire during the build phase (in which case calling
|
||||||
/// [State.setState] is not allowed).
|
/// [State.setState] is not allowed).
|
||||||
final ValueChanged<bool>? onHighlightChanged;
|
final ValueChanged<bool> onHighlightChanged;
|
||||||
|
|
||||||
/// {@macro flutter.material.button.mouseCursor}
|
/// {@macro flutter.material.button.mouseCursor}
|
||||||
final MouseCursor? mouseCursor;
|
final MouseCursor mouseCursor;
|
||||||
|
|
||||||
/// Defines the button's base colors, and the defaults for the button's minimum
|
/// Defines the button's base colors, and the defaults for the button's minimum
|
||||||
/// size, internal padding, and shape.
|
/// size, internal padding, and shape.
|
||||||
///
|
///
|
||||||
/// Defaults to `ButtonTheme.of(context).textTheme`.
|
/// Defaults to `ButtonTheme.of(context).textTheme`.
|
||||||
final ButtonTextTheme? textTheme;
|
final ButtonTextTheme textTheme;
|
||||||
|
|
||||||
/// The color to use for this button's text.
|
/// The color to use for this button's text.
|
||||||
///
|
///
|
||||||
|
@ -155,7 +157,7 @@ class MaterialButton extends StatelessWidget {
|
||||||
///
|
///
|
||||||
/// * [disabledTextColor], the text color to use when the button has been
|
/// * [disabledTextColor], the text color to use when the button has been
|
||||||
/// disabled.
|
/// disabled.
|
||||||
final Color? textColor;
|
final Color textColor;
|
||||||
|
|
||||||
/// The color to use for this button's text when the button is disabled.
|
/// The color to use for this button's text when the button is disabled.
|
||||||
///
|
///
|
||||||
|
@ -172,7 +174,7 @@ class MaterialButton extends StatelessWidget {
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [textColor] - The color to use for this button's text when the button is [enabled].
|
/// * [textColor] - The color to use for this button's text when the button is [enabled].
|
||||||
final Color? disabledTextColor;
|
final Color disabledTextColor;
|
||||||
|
|
||||||
/// The button's fill color, displayed by its [Material], while it
|
/// The button's fill color, displayed by its [Material], while it
|
||||||
/// is in its default (unpressed, [enabled]) state.
|
/// is in its default (unpressed, [enabled]) state.
|
||||||
|
@ -182,7 +184,7 @@ class MaterialButton extends StatelessWidget {
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [disabledColor] - the fill color of the button when the button is disabled.
|
/// * [disabledColor] - the fill color of the button when the button is disabled.
|
||||||
final Color? color;
|
final Color color;
|
||||||
|
|
||||||
/// The fill color of the button when the button is disabled.
|
/// The fill color of the button when the button is disabled.
|
||||||
///
|
///
|
||||||
|
@ -192,7 +194,7 @@ class MaterialButton extends StatelessWidget {
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [color] - the fill color of the button when the button is [enabled].
|
/// * [color] - the fill color of the button when the button is [enabled].
|
||||||
final Color? disabledColor;
|
final Color disabledColor;
|
||||||
|
|
||||||
/// The splash color of the button's [InkWell].
|
/// The splash color of the button's [InkWell].
|
||||||
///
|
///
|
||||||
|
@ -205,20 +207,20 @@ class MaterialButton extends StatelessWidget {
|
||||||
///
|
///
|
||||||
/// The appearance of the splash can be configured with the theme's splash
|
/// The appearance of the splash can be configured with the theme's splash
|
||||||
/// factory, [ThemeData.splashFactory].
|
/// factory, [ThemeData.splashFactory].
|
||||||
final Color? splashColor;
|
final Color splashColor;
|
||||||
|
|
||||||
/// The fill color of the button's [Material] when it has the input focus.
|
/// The fill color of the button's [Material] when it has the input focus.
|
||||||
///
|
///
|
||||||
/// The button changed focus color when the button has the input focus. It
|
/// The button changed focus color when the button has the input focus. It
|
||||||
/// appears behind the button's child.
|
/// appears behind the button's child.
|
||||||
final Color? focusColor;
|
final Color focusColor;
|
||||||
|
|
||||||
/// The fill color of the button's [Material] when a pointer is hovering over
|
/// The fill color of the button's [Material] when a pointer is hovering over
|
||||||
/// it.
|
/// it.
|
||||||
///
|
///
|
||||||
/// The button changes fill color when a pointer is hovering over the button.
|
/// The button changes fill color when a pointer is hovering over the button.
|
||||||
/// It appears behind the button's child.
|
/// It appears behind the button's child.
|
||||||
final Color? hoverColor;
|
final Color hoverColor;
|
||||||
|
|
||||||
/// The highlight color of the button's [InkWell].
|
/// The highlight color of the button's [InkWell].
|
||||||
///
|
///
|
||||||
|
@ -229,7 +231,7 @@ class MaterialButton extends StatelessWidget {
|
||||||
/// If [textTheme] is [ButtonTextTheme.primary], the default highlight color is
|
/// If [textTheme] is [ButtonTextTheme.primary], the default highlight color is
|
||||||
/// transparent (in other words the highlight doesn't appear). Otherwise it's
|
/// transparent (in other words the highlight doesn't appear). Otherwise it's
|
||||||
/// the current theme's highlight color, [ThemeData.highlightColor].
|
/// the current theme's highlight color, [ThemeData.highlightColor].
|
||||||
final Color? highlightColor;
|
final Color highlightColor;
|
||||||
|
|
||||||
/// The z-coordinate at which to place this button relative to its parent.
|
/// The z-coordinate at which to place this button relative to its parent.
|
||||||
///
|
///
|
||||||
|
@ -246,7 +248,7 @@ class MaterialButton extends StatelessWidget {
|
||||||
/// button.
|
/// button.
|
||||||
/// * [disabledElevation], the elevation when the button is disabled.
|
/// * [disabledElevation], the elevation when the button is disabled.
|
||||||
/// * [highlightElevation], the elevation when the button is pressed.
|
/// * [highlightElevation], the elevation when the button is pressed.
|
||||||
final double? elevation;
|
final double elevation;
|
||||||
|
|
||||||
/// The elevation for the button's [Material] when the button
|
/// The elevation for the button's [Material] when the button
|
||||||
/// is [enabled] and a pointer is hovering over it.
|
/// is [enabled] and a pointer is hovering over it.
|
||||||
|
@ -259,7 +261,7 @@ class MaterialButton extends StatelessWidget {
|
||||||
/// * [focusElevation], the elevation when the button is focused.
|
/// * [focusElevation], the elevation when the button is focused.
|
||||||
/// * [disabledElevation], the elevation when the button is disabled.
|
/// * [disabledElevation], the elevation when the button is disabled.
|
||||||
/// * [highlightElevation], the elevation when the button is pressed.
|
/// * [highlightElevation], the elevation when the button is pressed.
|
||||||
final double? hoverElevation;
|
final double hoverElevation;
|
||||||
|
|
||||||
/// The elevation for the button's [Material] when the button
|
/// The elevation for the button's [Material] when the button
|
||||||
/// is [enabled] and has the input focus.
|
/// is [enabled] and has the input focus.
|
||||||
|
@ -273,7 +275,7 @@ class MaterialButton extends StatelessWidget {
|
||||||
/// button.
|
/// button.
|
||||||
/// * [disabledElevation], the elevation when the button is disabled.
|
/// * [disabledElevation], the elevation when the button is disabled.
|
||||||
/// * [highlightElevation], the elevation when the button is pressed.
|
/// * [highlightElevation], the elevation when the button is pressed.
|
||||||
final double? focusElevation;
|
final double focusElevation;
|
||||||
|
|
||||||
/// The elevation for the button's [Material] relative to its parent when the
|
/// The elevation for the button's [Material] relative to its parent when the
|
||||||
/// button is [enabled] and pressed.
|
/// button is [enabled] and pressed.
|
||||||
|
@ -291,7 +293,7 @@ class MaterialButton extends StatelessWidget {
|
||||||
/// * [hoverElevation], the elevation when a pointer is hovering over the
|
/// * [hoverElevation], the elevation when a pointer is hovering over the
|
||||||
/// button.
|
/// button.
|
||||||
/// * [disabledElevation], the elevation when the button is disabled.
|
/// * [disabledElevation], the elevation when the button is disabled.
|
||||||
final double? highlightElevation;
|
final double highlightElevation;
|
||||||
|
|
||||||
/// The elevation for the button's [Material] relative to its parent when the
|
/// The elevation for the button's [Material] relative to its parent when the
|
||||||
/// button is not [enabled].
|
/// button is not [enabled].
|
||||||
|
@ -302,7 +304,7 @@ class MaterialButton extends StatelessWidget {
|
||||||
///
|
///
|
||||||
/// * [elevation], the default elevation.
|
/// * [elevation], the default elevation.
|
||||||
/// * [highlightElevation], the elevation when the button is pressed.
|
/// * [highlightElevation], the elevation when the button is pressed.
|
||||||
final double? disabledElevation;
|
final double disabledElevation;
|
||||||
|
|
||||||
/// The theme brightness to use for this button.
|
/// The theme brightness to use for this button.
|
||||||
///
|
///
|
||||||
|
@ -313,12 +315,12 @@ class MaterialButton extends StatelessWidget {
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [ButtonTextTheme], uses [Brightness] to determine text color.
|
/// * [ButtonTextTheme], uses [Brightness] to determine text color.
|
||||||
final Brightness? colorBrightness;
|
final Brightness colorBrightness;
|
||||||
|
|
||||||
/// The button's label.
|
/// The button's label.
|
||||||
///
|
///
|
||||||
/// Often a [Text] widget in all caps.
|
/// Often a [Text] widget in all caps.
|
||||||
final Widget? child;
|
final Widget child;
|
||||||
|
|
||||||
/// Whether the button is enabled or disabled.
|
/// Whether the button is enabled or disabled.
|
||||||
///
|
///
|
||||||
|
@ -330,7 +332,7 @@ class MaterialButton extends StatelessWidget {
|
||||||
///
|
///
|
||||||
/// Defaults to the value from the current [ButtonTheme],
|
/// Defaults to the value from the current [ButtonTheme],
|
||||||
/// [ButtonThemeData.padding].
|
/// [ButtonThemeData.padding].
|
||||||
final EdgeInsetsGeometry? padding;
|
final EdgeInsetsGeometry padding;
|
||||||
|
|
||||||
/// Defines how compact the button's layout will be.
|
/// Defines how compact the button's layout will be.
|
||||||
///
|
///
|
||||||
|
@ -340,7 +342,7 @@ class MaterialButton extends StatelessWidget {
|
||||||
///
|
///
|
||||||
/// * [ThemeData.visualDensity], which specifies the [visualDensity] for all
|
/// * [ThemeData.visualDensity], which specifies the [visualDensity] for all
|
||||||
/// widgets within a [Theme].
|
/// widgets within a [Theme].
|
||||||
final VisualDensity? visualDensity;
|
final VisualDensity visualDensity;
|
||||||
|
|
||||||
/// The shape of the button's [Material].
|
/// The shape of the button's [Material].
|
||||||
///
|
///
|
||||||
|
@ -350,7 +352,7 @@ class MaterialButton extends StatelessWidget {
|
||||||
///
|
///
|
||||||
/// Defaults to the value from the current [ButtonTheme],
|
/// Defaults to the value from the current [ButtonTheme],
|
||||||
/// [ButtonThemeData.shape].
|
/// [ButtonThemeData.shape].
|
||||||
final ShapeBorder? shape;
|
final ShapeBorder shape;
|
||||||
|
|
||||||
/// {@macro flutter.widgets.Clip}
|
/// {@macro flutter.widgets.Clip}
|
||||||
///
|
///
|
||||||
|
@ -358,7 +360,7 @@ class MaterialButton extends StatelessWidget {
|
||||||
final Clip clipBehavior;
|
final Clip clipBehavior;
|
||||||
|
|
||||||
/// {@macro flutter.widgets.Focus.focusNode}
|
/// {@macro flutter.widgets.Focus.focusNode}
|
||||||
final FocusNode? focusNode;
|
final FocusNode focusNode;
|
||||||
|
|
||||||
/// {@macro flutter.widgets.Focus.autofocus}
|
/// {@macro flutter.widgets.Focus.autofocus}
|
||||||
final bool autofocus;
|
final bool autofocus;
|
||||||
|
@ -366,7 +368,7 @@ class MaterialButton extends StatelessWidget {
|
||||||
/// Defines the duration of animated changes for [shape] and [elevation].
|
/// Defines the duration of animated changes for [shape] and [elevation].
|
||||||
///
|
///
|
||||||
/// The default value is [kThemeChangeDuration].
|
/// The default value is [kThemeChangeDuration].
|
||||||
final Duration? animationDuration;
|
final Duration animationDuration;
|
||||||
|
|
||||||
/// Configures the minimum size of the tap target.
|
/// Configures the minimum size of the tap target.
|
||||||
///
|
///
|
||||||
|
@ -375,17 +377,17 @@ class MaterialButton extends StatelessWidget {
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [MaterialTapTargetSize], for a description of how this affects tap targets.
|
/// * [MaterialTapTargetSize], for a description of how this affects tap targets.
|
||||||
final MaterialTapTargetSize? materialTapTargetSize;
|
final MaterialTapTargetSize materialTapTargetSize;
|
||||||
|
|
||||||
/// The smallest horizontal extent that the button will occupy.
|
/// The smallest horizontal extent that the button will occupy.
|
||||||
///
|
///
|
||||||
/// Defaults to the value from the current [ButtonTheme].
|
/// Defaults to the value from the current [ButtonTheme].
|
||||||
final double? minWidth;
|
final double minWidth;
|
||||||
|
|
||||||
/// The vertical extent of the button.
|
/// The vertical extent of the button.
|
||||||
///
|
///
|
||||||
/// Defaults to the value from the current [ButtonTheme].
|
/// Defaults to the value from the current [ButtonTheme].
|
||||||
final double? height;
|
final double height;
|
||||||
|
|
||||||
/// Whether detected gestures should provide acoustic and/or haptic feedback.
|
/// Whether detected gestures should provide acoustic and/or haptic feedback.
|
||||||
///
|
///
|
||||||
|
@ -399,7 +401,7 @@ class MaterialButton extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final ThemeData theme = Theme.of(context)!;
|
final ThemeData theme = Theme.of(context);
|
||||||
final ButtonThemeData buttonTheme = ButtonTheme.of(context);
|
final ButtonThemeData buttonTheme = ButtonTheme.of(context);
|
||||||
|
|
||||||
return RawMaterialButton(
|
return RawMaterialButton(
|
||||||
|
@ -409,9 +411,9 @@ class MaterialButton extends StatelessWidget {
|
||||||
onHighlightChanged: onHighlightChanged,
|
onHighlightChanged: onHighlightChanged,
|
||||||
mouseCursor: mouseCursor,
|
mouseCursor: mouseCursor,
|
||||||
fillColor: buttonTheme.getFillColor(this),
|
fillColor: buttonTheme.getFillColor(this),
|
||||||
textStyle: theme.textTheme.button!.copyWith(color: buttonTheme.getTextColor(this)),
|
textStyle: theme.textTheme.button.copyWith(color: buttonTheme.getTextColor(this)),
|
||||||
focusColor: focusColor ?? buttonTheme.getFocusColor(this),
|
focusColor: focusColor ?? buttonTheme.getFocusColor(this) ?? theme.focusColor,
|
||||||
hoverColor: hoverColor ?? buttonTheme.getHoverColor(this),
|
hoverColor: hoverColor ?? buttonTheme.getHoverColor(this) ?? theme.hoverColor,
|
||||||
highlightColor: highlightColor ?? theme.highlightColor,
|
highlightColor: highlightColor ?? theme.highlightColor,
|
||||||
splashColor: splashColor ?? theme.splashColor,
|
splashColor: splashColor ?? theme.splashColor,
|
||||||
elevation: buttonTheme.getElevation(this),
|
elevation: buttonTheme.getElevation(this),
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -30,7 +30,7 @@ void main() {
|
||||||
expect(themeData.showUnselectedLabels, null);
|
expect(themeData.showUnselectedLabels, null);
|
||||||
expect(themeData.type, null);
|
expect(themeData.type, null);
|
||||||
|
|
||||||
const BottomNavigationBarTheme theme = BottomNavigationBarTheme(data: BottomNavigationBarThemeData(), child: SizedBox());
|
const BottomNavigationBarTheme theme = BottomNavigationBarTheme(data: BottomNavigationBarThemeData());
|
||||||
expect(theme.data.backgroundColor, null);
|
expect(theme.data.backgroundColor, null);
|
||||||
expect(theme.data.elevation, null);
|
expect(theme.data.elevation, null);
|
||||||
expect(theme.data.selectedIconTheme, null);
|
expect(theme.data.selectedIconTheme, null);
|
||||||
|
|
Loading…
Reference in a new issue