Unverified Commit 60f039cb authored by Taha Tesser's avatar Taha Tesser Committed by GitHub

Add `ExpansionTileTheme` (#98405)

parent 2a2f9731
......@@ -73,6 +73,7 @@ export 'src/material/elevation_overlay.dart';
export 'src/material/expand_icon.dart';
export 'src/material/expansion_panel.dart';
export 'src/material/expansion_tile.dart';
export 'src/material/expansion_tile_theme.dart';
export 'src/material/feedback.dart';
export 'src/material/flat_button.dart';
export 'src/material/flexible_space_bar.dart';
......
......@@ -6,6 +6,7 @@ import 'package:flutter/widgets.dart';
import 'color_scheme.dart';
import 'colors.dart';
import 'expansion_tile_theme.dart';
import 'icons.dart';
import 'list_tile.dart';
import 'theme.dart';
......@@ -107,9 +108,25 @@ class ExpansionTile extends StatefulWidget {
final List<Widget> children;
/// The color to display behind the sublist when expanded.
///
/// If this property is null then [ExpansionTileThemeData.backgroundColor] is used. If that
/// is also null then Colors.transparent is used.
///
/// See also:
///
/// * [ExpansionTileTheme.of], which returns the nearest [ExpansionTileTheme]'s
/// [ExpansionTileThemeData].
final Color? backgroundColor;
/// When not null, defines the background color of tile when the sublist is collapsed.
///
/// If this property is null then [ExpansionTileThemeData.collapsedBackgroundColor] is used.
/// If that is also null then Colors.transparent is used.
///
/// See also:
///
/// * [ExpansionTileTheme.of], which returns the nearest [ExpansionTileTheme]'s
/// [ExpansionTileThemeData].
final Color? collapsedBackgroundColor;
/// A widget to display after the title.
......@@ -134,7 +151,13 @@ class ExpansionTile extends StatefulWidget {
/// the [leading], [title], [subtitle] and [trailing] widgets. It does not inset
/// the expanded [children] widgets.
///
/// When the value is null, the tile's padding is `EdgeInsets.symmetric(horizontal: 16.0)`.
/// If this property is null then [ExpansionTileThemeData.tilePadding] is used. If that
/// is also null then the tile's padding is `EdgeInsets.symmetric(horizontal: 16.0)`.
///
/// See also:
///
/// * [ExpansionTileTheme.of], which returns the nearest [ExpansionTileTheme]'s
/// [ExpansionTileThemeData].
final EdgeInsetsGeometry? tilePadding;
/// Specifies the alignment of [children], which are arranged in a column when
......@@ -150,7 +173,13 @@ class ExpansionTile extends StatefulWidget {
///
/// The width of the column is the width of the widest child widget in [children].
///
/// When the value is null, the value of `expandedAlignment` is [Alignment.center].
/// If this property is null then [ExpansionTileThemeData.expandedAlignment]is used. If that
/// is also null then the value of `expandedAlignment` is [Alignment.center].
///
/// See also:
///
/// * [ExpansionTileTheme.of], which returns the nearest [ExpansionTileTheme]'s
/// [ExpansionTileThemeData].
final Alignment? expandedAlignment;
/// Specifies the alignment of each child within [children] when the tile is expanded.
......@@ -171,12 +200,26 @@ class ExpansionTile extends StatefulWidget {
/// Specifies padding for [children].
///
/// When the value is null, the value of `childrenPadding` is [EdgeInsets.zero].
/// If this property is null then [ExpansionTileThemeData.childrenPadding] is used. If that
/// is also null then the value of `childrenPadding` is [EdgeInsets.zero].
///
/// See also:
///
/// * [ExpansionTileTheme.of], which returns the nearest [ExpansionTileTheme]'s
/// [ExpansionTileThemeData].
final EdgeInsetsGeometry? childrenPadding;
/// The icon color of tile's expansion arrow icon when the sublist is expanded.
///
/// Used to override to the [ListTileThemeData.iconColor].
///
/// If this property is null then [ExpansionTileThemeData.iconColor] is used. If that
/// is also null then the value of [ListTileThemeData.iconColor] is used.
///
/// See also:
///
/// * [ExpansionTileTheme.of], which returns the nearest [ExpansionTileTheme]'s
/// [ExpansionTileThemeData].
final Color? iconColor;
/// The icon color of tile's expansion arrow icon when the sublist is collapsed.
......@@ -188,11 +231,27 @@ class ExpansionTile extends StatefulWidget {
/// The color of the tile's titles when the sublist is expanded.
///
/// Used to override to the [ListTileThemeData.textColor].
///
/// If this property is null then [ExpansionTileThemeData.textColor] is used. If that
/// is also null then the value of [ListTileThemeData.textColor] is used.
///
/// See also:
///
/// * [ExpansionTileTheme.of], which returns the nearest [ExpansionTileTheme]'s
/// [ExpansionTileThemeData].
final Color? textColor;
/// The color of the tile's titles when the sublist is collapsed.
///
/// Used to override to the [ListTileThemeData.textColor].
///
/// If this property is null then [ExpansionTileThemeData.collapsedTextColor] is used. If that
/// is also null then the value of [ListTileThemeData.textColor] is used.
///
/// See also:
///
/// * [ExpansionTileTheme.of], which returns the nearest [ExpansionTileTheme]'s
/// [ExpansionTileThemeData].
final Color? collapsedTextColor;
/// Typically used to force the expansion arrow icon to the tile's leading or trailing edge.
......@@ -297,11 +356,12 @@ class _ExpansionTileState extends State<ExpansionTile> with SingleTickerProvider
}
Widget _buildChildren(BuildContext context, Widget? child) {
final ExpansionTileThemeData expansionTileTheme = ExpansionTileTheme.of(context);
final Color borderSideColor = _borderColor.value ?? Colors.transparent;
return Container(
decoration: BoxDecoration(
color: _backgroundColor.value ?? Colors.transparent,
color: _backgroundColor.value ?? expansionTileTheme.backgroundColor ?? Colors.transparent,
border: Border(
top: BorderSide(color: borderSideColor),
bottom: BorderSide(color: borderSideColor),
......@@ -311,11 +371,11 @@ class _ExpansionTileState extends State<ExpansionTile> with SingleTickerProvider
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTileTheme.merge(
iconColor: _iconColor.value,
iconColor: _iconColor.value ?? expansionTileTheme.iconColor,
textColor: _headerColor.value,
child: ListTile(
onTap: _handleTap,
contentPadding: widget.tilePadding,
contentPadding: widget.tilePadding ?? expansionTileTheme.tilePadding,
leading: widget.leading ?? _buildLeadingIcon(context),
title: widget.title,
subtitle: widget.subtitle,
......@@ -324,7 +384,9 @@ class _ExpansionTileState extends State<ExpansionTile> with SingleTickerProvider
),
ClipRect(
child: Align(
alignment: widget.expandedAlignment ?? Alignment.center,
alignment: widget.expandedAlignment
?? expansionTileTheme.expandedAlignment
?? Alignment.center,
heightFactor: _heightFactor.value,
child: child,
),
......@@ -337,22 +399,28 @@ class _ExpansionTileState extends State<ExpansionTile> with SingleTickerProvider
@override
void didChangeDependencies() {
final ThemeData theme = Theme.of(context);
final ExpansionTileThemeData expansionTileTheme = ExpansionTileTheme.of(context);
final ColorScheme colorScheme = theme.colorScheme;
_borderColorTween.end = theme.dividerColor;
_headerColorTween
..begin = widget.collapsedTextColor ?? theme.textTheme.subtitle1!.color
..end = widget.textColor ?? colorScheme.primary;
..begin = widget.collapsedTextColor
?? expansionTileTheme.collapsedTextColor
?? theme.textTheme.subtitle1!.color
..end = widget.textColor ?? expansionTileTheme.textColor ?? colorScheme.primary;
_iconColorTween
..begin = widget.collapsedIconColor ?? theme.unselectedWidgetColor
..end = widget.iconColor ?? colorScheme.primary;
..begin = widget.collapsedIconColor
?? expansionTileTheme.collapsedIconColor
?? theme.unselectedWidgetColor
..end = widget.iconColor ?? expansionTileTheme.iconColor ?? colorScheme.primary;
_backgroundColorTween
..begin = widget.collapsedBackgroundColor
..end = widget.backgroundColor;
..begin = widget.collapsedBackgroundColor ?? expansionTileTheme.collapsedBackgroundColor
..end = widget.backgroundColor ?? expansionTileTheme.backgroundColor;
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
final ExpansionTileThemeData expansionTileTheme = ExpansionTileTheme.of(context);
final bool closed = !_isExpanded && _controller.isDismissed;
final bool shouldRemoveChildren = closed && !widget.maintainState;
......@@ -361,7 +429,7 @@ class _ExpansionTileState extends State<ExpansionTile> with SingleTickerProvider
child: TickerMode(
enabled: !closed,
child: Padding(
padding: widget.childrenPadding ?? EdgeInsets.zero,
padding: widget.childrenPadding ?? expansionTileTheme.childrenPadding ?? EdgeInsets.zero,
child: Column(
crossAxisAlignment: widget.expandedCrossAxisAlignment ?? CrossAxisAlignment.center,
children: widget.children,
......
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:ui';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'theme.dart';
/// Used with [ExpansionTileTheme] to define default property values for
/// descendant [ExpansionTile] widgets.
///
/// Descendant widgets obtain the current [ExpansionTileThemeData] object
/// using `ExpansionTileTheme.of(context)`. Instances of
/// [ExpansionTileThemeData] can be customized with
/// [ExpansionTileThemeData.copyWith].
///
/// A [ExpansionTileThemeData] is often specified as part of the
/// overall [Theme] with [ThemeData.expansionTileTheme].
///
/// All [ExpansionTileThemeData] properties are `null` by default.
/// When a theme property is null, the [ExpansionTile] will provide its own
/// default based on the overall [Theme]'s textTheme and
/// colorScheme. See the individual [ExpansionTile] properties for details.
///
/// See also:
///
/// * [ThemeData], which describes the overall theme information for the
/// application.
/// * [ExpansionTileTheme] which overrides the default [ExpansionTileTheme]
/// of its [ExpansionTile] descendants.
/// * [ThemeData.textTheme], text with a color that contrasts with the card
/// and canvas colors.
/// * [ThemeData.colorScheme], the thirteen colors that most Material widget
/// default colors are based on.
@immutable
class ExpansionTileThemeData with Diagnosticable {
/// Creates a [ExpansionTileThemeData].
const ExpansionTileThemeData ({
this.backgroundColor,
this.collapsedBackgroundColor,
this.tilePadding,
this.expandedAlignment,
this.childrenPadding,
this.iconColor,
this.collapsedIconColor,
this.textColor,
this.collapsedTextColor,
});
/// Overrides the default value of [ExpansionTile.backgroundColor].
final Color? backgroundColor;
/// Overrides the default value of [ExpansionTile.collapsedBackgroundColor].
final Color? collapsedBackgroundColor;
/// Overrides the default value of [ExpansionTile.tilePadding].
final EdgeInsetsGeometry? tilePadding;
/// Overrides the default value of [ExpansionTile.expandedAlignment].
final AlignmentGeometry? expandedAlignment;
/// Overrides the default value of [ExpansionTile.childrenPadding].
final EdgeInsetsGeometry? childrenPadding;
/// Overrides the default value of [ExpansionTile.iconColor].
final Color? iconColor;
/// Overrides the default value of [ExpansionTile.collapsedIconColor].
final Color? collapsedIconColor;
/// Overrides the default value of [ExpansionTile.textColor].
final Color? textColor;
/// Overrides the default value of [ExpansionTile.collapsedTextColor].
final Color? collapsedTextColor;
/// Creates a copy of this object with the given fields replaced with the
/// new values.
ExpansionTileThemeData copyWith({
Color? backgroundColor,
Color? collapsedBackgroundColor,
EdgeInsetsGeometry? tilePadding,
AlignmentGeometry? expandedAlignment,
EdgeInsetsGeometry? childrenPadding,
Color? iconColor,
Color? collapsedIconColor,
Color? textColor,
Color? collapsedTextColor,
}) {
return ExpansionTileThemeData(
backgroundColor: backgroundColor ?? this.backgroundColor,
collapsedBackgroundColor: collapsedBackgroundColor ?? this.collapsedBackgroundColor,
tilePadding: tilePadding ?? this.tilePadding,
expandedAlignment: expandedAlignment ?? this.expandedAlignment,
childrenPadding: childrenPadding ?? this.childrenPadding,
iconColor: iconColor ?? this.iconColor,
collapsedIconColor: collapsedIconColor ?? this.collapsedIconColor,
textColor: textColor ?? this.textColor,
collapsedTextColor: collapsedTextColor ?? this.collapsedTextColor,
);
}
/// Linearly interpolate between ExpansionTileThemeData objects.
static ExpansionTileThemeData? lerp(ExpansionTileThemeData? a, ExpansionTileThemeData? b, double t) {
assert (t != null);
if (a == null && b == null)
return null;
return ExpansionTileThemeData(
backgroundColor: Color.lerp(a?.backgroundColor, b?.backgroundColor, t),
collapsedBackgroundColor: Color.lerp(a?.collapsedBackgroundColor, b?.collapsedBackgroundColor, t),
tilePadding: EdgeInsetsGeometry.lerp(a?.tilePadding, b?.tilePadding, t),
expandedAlignment: AlignmentGeometry.lerp(a?.expandedAlignment, b?.expandedAlignment, t),
childrenPadding: EdgeInsetsGeometry.lerp(a?.childrenPadding, b?.childrenPadding, t),
iconColor: Color.lerp(a?.iconColor, b?.iconColor, t),
collapsedIconColor: Color.lerp(a?.collapsedIconColor, b?.collapsedIconColor, t),
textColor: Color.lerp(a?.textColor, b?.textColor, t),
collapsedTextColor: Color.lerp(a?.collapsedTextColor, b?.collapsedTextColor, t),
);
}
@override
int get hashCode {
return hashValues(
backgroundColor,
collapsedBackgroundColor,
tilePadding,
expandedAlignment,
childrenPadding,
iconColor,
collapsedIconColor,
textColor,
collapsedTextColor,
);
}
@override
bool operator ==(Object other) {
if (identical(this, other))
return true;
if (other.runtimeType != runtimeType)
return false;
return other is ExpansionTileThemeData
&& other.backgroundColor == backgroundColor
&& other.collapsedBackgroundColor == collapsedBackgroundColor
&& other.tilePadding == tilePadding
&& other.expandedAlignment == expandedAlignment
&& other.childrenPadding == childrenPadding
&& other.iconColor == iconColor
&& other.collapsedIconColor == collapsedIconColor
&& other.textColor == textColor
&& other.collapsedTextColor == collapsedTextColor;
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(ColorProperty('backgroundColor', backgroundColor, defaultValue: null));
properties.add(ColorProperty('collapsedBackgroundColor', collapsedBackgroundColor, defaultValue: null));
properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('tilePadding', tilePadding, defaultValue: null));
properties.add(DiagnosticsProperty<AlignmentGeometry>('expandedAlignment', expandedAlignment, defaultValue: null));
properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('childrenPadding', childrenPadding, defaultValue: null));
properties.add(ColorProperty('iconColor', iconColor, defaultValue: null));
properties.add(ColorProperty('collapsedIconColor', collapsedIconColor, defaultValue: null));
properties.add(ColorProperty('textColor', textColor, defaultValue: null));
properties.add(ColorProperty('collapsedTextColor', collapsedTextColor, defaultValue: null));
}
}
/// Overrides the default [ExpansionTileTheme] of its [ExpansionTile] descendants.
///
/// See also:
///
/// * [ExpansionTileThemeData], which is used to configure this theme.
/// * [ThemeData.expansionTileTheme], which can be used to override the default
/// [ExpansionTileTheme] for [ExpansionTile]s below the overall [Theme].
class ExpansionTileTheme extends InheritedTheme {
/// Applies the given theme [data] to [child].
///
/// The [data] and [child] arguments must not be null.
const ExpansionTileTheme({
Key? key,
required this.data,
required Widget child,
}) : assert(child != null),
assert(data != null),
super(key: key, child: child);
/// Specifies color, alignment, and text style values for
/// descendant [ExpansionTile] widgets.
final ExpansionTileThemeData data;
/// The closest instance of this class that encloses the given context.
///
/// If there is no enclosing [ExpansionTileTheme] widget, then
/// [ThemeData.expansionTileTheme] is used.
///
/// Typical usage is as follows:
///
/// ```dart
/// ExpansionTileThemeData theme = ExpansionTileTheme.of(context);
/// ```
static ExpansionTileThemeData of(BuildContext context) {
final ExpansionTileTheme? inheritedTheme = context.dependOnInheritedWidgetOfExactType<ExpansionTileTheme>();
return inheritedTheme?.data ?? Theme.of(context).expansionTileTheme;
}
@override
Widget wrap(BuildContext context, Widget child) {
return ExpansionTileTheme(data: data, child: child);
}
@override
bool updateShouldNotify(ExpansionTileTheme oldWidget) => data != oldWidget.data;
}
......@@ -24,6 +24,7 @@ import 'dialog_theme.dart';
import 'divider_theme.dart';
import 'drawer_theme.dart';
import 'elevated_button_theme.dart';
import 'expansion_tile_theme.dart';
import 'floating_action_button_theme.dart';
import 'ink_splash.dart';
import 'ink_well.dart' show InteractiveInkFeatureFactory;
......@@ -321,6 +322,7 @@ class ThemeData with Diagnosticable {
TimePickerThemeData? timePickerTheme,
ToggleButtonsThemeData? toggleButtonsTheme,
TooltipThemeData? tooltipTheme,
ExpansionTileThemeData? expansionTileTheme,
// DEPRECATED (newest deprecations at the bottom)
@Deprecated(
'No longer used by the framework, please remove any reference to it. '
......@@ -541,6 +543,7 @@ class ThemeData with Diagnosticable {
timePickerTheme ??= const TimePickerThemeData();
toggleButtonsTheme ??= const ToggleButtonsThemeData();
tooltipTheme ??= const TooltipThemeData();
expansionTileTheme ??= const ExpansionTileThemeData();
// DEPRECATED (newest deprecations at the bottom)
useTextSelectionTheme ??= true;
......@@ -630,6 +633,7 @@ class ThemeData with Diagnosticable {
timePickerTheme: timePickerTheme,
toggleButtonsTheme: toggleButtonsTheme,
tooltipTheme: tooltipTheme,
expansionTileTheme: expansionTileTheme,
// DEPRECATED (newest deprecations at the bottom)
useTextSelectionTheme: useTextSelectionTheme,
textSelectionColor: textSelectionColor,
......@@ -735,6 +739,7 @@ class ThemeData with Diagnosticable {
required this.timePickerTheme,
required this.toggleButtonsTheme,
required this.tooltipTheme,
required this.expansionTileTheme,
// DEPRECATED (newest deprecations at the bottom)
@Deprecated(
'No longer used by the framework, please remove any reference to it. '
......@@ -873,6 +878,7 @@ class ThemeData with Diagnosticable {
assert(timePickerTheme != null),
assert(toggleButtonsTheme != null),
assert(tooltipTheme != null),
assert(expansionTileTheme != null),
// DEPRECATED (newest deprecations at the bottom)
assert(useTextSelectionTheme != null),
assert(textSelectionColor != null),
......@@ -1409,6 +1415,9 @@ class ThemeData with Diagnosticable {
/// This is the value returned from [TooltipTheme.of].
final TooltipThemeData tooltipTheme;
/// A theme for customizing the visual properties of [ExpansionTile]s.
final ExpansionTileThemeData expansionTileTheme;
// DEPRECATED (newest deprecations at the bottom)
/// A temporary flag that was used to opt-in to the new [TextSelectionTheme]
......@@ -1634,6 +1643,7 @@ class ThemeData with Diagnosticable {
TimePickerThemeData? timePickerTheme,
ToggleButtonsThemeData? toggleButtonsTheme,
TooltipThemeData? tooltipTheme,
ExpansionTileThemeData? expansionTileTheme,
// DEPRECATED (newest deprecations at the bottom)
@Deprecated(
'No longer used by the framework, please remove any reference to it. '
......@@ -1777,6 +1787,7 @@ class ThemeData with Diagnosticable {
timePickerTheme: timePickerTheme ?? this.timePickerTheme,
toggleButtonsTheme: toggleButtonsTheme ?? this.toggleButtonsTheme,
tooltipTheme: tooltipTheme ?? this.tooltipTheme,
expansionTileTheme: expansionTileTheme ?? this.expansionTileTheme,
// DEPRECATED (newest deprecations at the bottom)
useTextSelectionTheme: useTextSelectionTheme ?? this.useTextSelectionTheme,
textSelectionColor: textSelectionColor ?? this.textSelectionColor,
......@@ -1946,6 +1957,7 @@ class ThemeData with Diagnosticable {
timePickerTheme: TimePickerThemeData.lerp(a.timePickerTheme, b.timePickerTheme, t),
toggleButtonsTheme: ToggleButtonsThemeData.lerp(a.toggleButtonsTheme, b.toggleButtonsTheme, t)!,
tooltipTheme: TooltipThemeData.lerp(a.tooltipTheme, b.tooltipTheme, t)!,
expansionTileTheme: ExpansionTileThemeData.lerp(a.expansionTileTheme, b.expansionTileTheme, t)!,
// DEPRECATED (newest deprecations at the bottom)
useTextSelectionTheme: t < 0.5 ? a.useTextSelectionTheme : b.useTextSelectionTheme,
textSelectionColor: Color.lerp(a.textSelectionColor, b.textSelectionColor, t)!,
......@@ -2045,6 +2057,7 @@ class ThemeData with Diagnosticable {
other.timePickerTheme == timePickerTheme &&
other.toggleButtonsTheme == toggleButtonsTheme &&
other.tooltipTheme == tooltipTheme &&
other.expansionTileTheme == expansionTileTheme &&
// DEPRECATED (newest deprecations at the bottom)
other.useTextSelectionTheme == useTextSelectionTheme &&
other.textSelectionColor == textSelectionColor &&
......@@ -2141,6 +2154,7 @@ class ThemeData with Diagnosticable {
timePickerTheme,
toggleButtonsTheme,
tooltipTheme,
expansionTileTheme,
// DEPRECATED (newest deprecations at the bottom)
useTextSelectionTheme,
textSelectionColor,
......@@ -2237,6 +2251,7 @@ class ThemeData with Diagnosticable {
properties.add(DiagnosticsProperty<TimePickerThemeData>('timePickerTheme', timePickerTheme, defaultValue: defaultData.timePickerTheme, level: DiagnosticLevel.debug));
properties.add(DiagnosticsProperty<ToggleButtonsThemeData>('toggleButtonsTheme', toggleButtonsTheme, level: DiagnosticLevel.debug));
properties.add(DiagnosticsProperty<TooltipThemeData>('tooltipTheme', tooltipTheme, level: DiagnosticLevel.debug));
properties.add(DiagnosticsProperty<ExpansionTileThemeData>('expansionTileTheme', expansionTileTheme, level: DiagnosticLevel.debug));
// DEPRECATED (newest deprecations at the bottom)
properties.add(DiagnosticsProperty<bool>('useTextSelectionTheme', useTextSelectionTheme, level: DiagnosticLevel.debug));
properties.add(ColorProperty('textSelectionColor', textSelectionColor, defaultValue: defaultData.textSelectionColor, level: DiagnosticLevel.debug));
......
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart';
class TestIcon extends StatefulWidget {
const TestIcon({Key? key}) : super(key: key);
@override
TestIconState createState() => TestIconState();
}
class TestIconState extends State<TestIcon> {
late IconThemeData iconTheme;
@override
Widget build(BuildContext context) {
iconTheme = IconTheme.of(context);
return const Icon(Icons.expand_more);
}
}
class TestText extends StatefulWidget {
const TestText(this.text, {Key? key}) : super(key: key);
final String text;
@override
TestTextState createState() => TestTextState();
}
class TestTextState extends State<TestText> {
late TextStyle textStyle;
@override
Widget build(BuildContext context) {
textStyle = DefaultTextStyle.of(context).style;
return Text(widget.text);
}
}
void main() {
test('ExpansionTileThemeData copyWith, ==, hashCode basics', () {
expect(const ExpansionTileThemeData(), const ExpansionTileThemeData().copyWith());
expect(const ExpansionTileThemeData().hashCode, const ExpansionTileThemeData().copyWith().hashCode);
});
test('ExpansionTileThemeData defaults', () {
const ExpansionTileThemeData theme = ExpansionTileThemeData();
expect(theme.backgroundColor, null);
expect(theme.collapsedBackgroundColor, null);
expect(theme.tilePadding, null);
expect(theme.expandedAlignment, null);
expect(theme.childrenPadding, null);
expect(theme.iconColor, null);
expect(theme.collapsedIconColor, null);
expect(theme.textColor, null);
expect(theme.collapsedTextColor, null);
});
testWidgets('Default ExpansionTileThemeData debugFillProperties', (WidgetTester tester) async {
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
const TooltipThemeData().debugFillProperties(builder);
final List<String> description = builder.properties
.where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
.map((DiagnosticsNode node) => node.toString())
.toList();
expect(description, <String>[]);
});
testWidgets('ExpansionTileThemeData implements debugFillProperties', (WidgetTester tester) async {
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
const ExpansionTileThemeData(
backgroundColor: Color(0xff000000),
collapsedBackgroundColor: Color(0xff6f83fc),
tilePadding: EdgeInsets.all(20.0),
expandedAlignment: Alignment.bottomCenter,
childrenPadding: EdgeInsets.all(10.0),
iconColor: Color(0xffa7c61c),
collapsedIconColor: Color(0xffdd0b1f),
textColor: Color(0xffffffff),
collapsedTextColor: Color(0xff522bab),
).debugFillProperties(builder);
final List<String> description = builder.properties
.where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
.map((DiagnosticsNode node) => node.toString())
.toList();
expect(description, <String>[
'backgroundColor: Color(0xff000000)',
'collapsedBackgroundColor: Color(0xff6f83fc)',
'tilePadding: EdgeInsets.all(20.0)',
'expandedAlignment: Alignment.bottomCenter',
'childrenPadding: EdgeInsets.all(10.0)',
'iconColor: Color(0xffa7c61c)',
'collapsedIconColor: Color(0xffdd0b1f)',
'textColor: Color(0xffffffff)',
'collapsedTextColor: Color(0xff522bab)',
]);
});
testWidgets('ExpansionTileTheme - collapsed', (WidgetTester tester) async {
final Key tileKey = UniqueKey();
final Key titleKey = UniqueKey();
final Key iconKey = UniqueKey();
const Color backgroundColor = Colors.orange;
const Color collapsedBackgroundColor = Colors.red;
const Color iconColor = Colors.green;
const Color collapsedIconColor = Colors.blue;
const Color textColor = Colors.black;
const Color collapsedTextColor = Colors.white;
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(
expansionTileTheme: const ExpansionTileThemeData(
backgroundColor: backgroundColor,
collapsedBackgroundColor: collapsedBackgroundColor,
tilePadding: EdgeInsets.fromLTRB(8, 12, 4, 10),
expandedAlignment: Alignment.centerRight,
childrenPadding: EdgeInsets.all(20.0),
iconColor: iconColor,
collapsedIconColor: collapsedIconColor,
textColor: textColor,
collapsedTextColor: collapsedTextColor,
),
),
home: Material(
child: Center(
child: ExpansionTile(
key: tileKey,
title: TestText('Collapsed Tile', key: titleKey),
trailing: TestIcon(key: iconKey),
children: const <Widget>[Text('Tile 1')],
),
),
),
),
);
final BoxDecoration boxDecoration = tester.firstWidget<Container>(find.descendant(
of: find.byKey(tileKey),
matching: find.byType(Container),
)).decoration! as BoxDecoration;
// Check the tile's collapsed background color when collapsedBackgroundColor is applied.
expect(boxDecoration.color, collapsedBackgroundColor);
final Rect titleRect = tester.getRect(find.text('Collapsed Tile'));
final Rect trailingRect = tester.getRect(find.byIcon(Icons.expand_more));
final Rect listTileRect = tester.getRect(find.byType(ListTile));
final Rect tallerWidget = titleRect.height > trailingRect.height ? titleRect : trailingRect;
// Check the positions of title and trailing Widgets, after padding is applied.
expect(listTileRect.left, titleRect.left - 8);
expect(listTileRect.right, trailingRect.right + 4);
// Calculate the remaining height of ListTile from the default height.
final double remainingHeight = 56 - tallerWidget.height;
expect(listTileRect.top, tallerWidget.top - remainingHeight / 2 - 12);
expect(listTileRect.bottom, tallerWidget.bottom + remainingHeight / 2 + 10);
Color getIconColor() => tester.state<TestIconState>(find.byType(TestIcon)).iconTheme.color!;
Color getTextColor() => tester.state<TestTextState>(find.byType(TestText)).textStyle.color!;
// Check the collapsed icon color when iconColor is applied.
expect(getIconColor(), collapsedIconColor);
// Check the collapsed text color when textColor is applied.
expect(getTextColor(), collapsedTextColor);
});
testWidgets('ExpansionTileTheme - expanded', (WidgetTester tester) async {
final Key tileKey = UniqueKey();
final Key titleKey = UniqueKey();
final Key iconKey = UniqueKey();
const Color backgroundColor = Colors.orange;
const Color collapsedBackgroundColor = Colors.red;
const Color iconColor = Colors.green;
const Color collapsedIconColor = Colors.blue;
const Color textColor = Colors.black;
const Color collapsedTextColor = Colors.white;
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(
expansionTileTheme: const ExpansionTileThemeData(
backgroundColor: backgroundColor,
collapsedBackgroundColor: collapsedBackgroundColor,
tilePadding: EdgeInsets.fromLTRB(8, 12, 4, 10),
expandedAlignment: Alignment.centerRight,
childrenPadding: EdgeInsets.all(20.0),
iconColor: iconColor,
collapsedIconColor: collapsedIconColor,
textColor: textColor,
collapsedTextColor: collapsedTextColor,
),
),
home: Material(
child: Center(
child: ExpansionTile(
key: tileKey,
initiallyExpanded: true,
title: TestText('Expanded Tile', key: titleKey),
trailing: TestIcon(key: iconKey),
children: const <Widget>[Text('Tile 1')],
),
),
),
),
);
final BoxDecoration boxDecoration = tester.firstWidget<Container>(find.descendant(
of: find.byKey(tileKey),
matching: find.byType(Container),
)).decoration! as BoxDecoration;
// Check the tile's background color when backgroundColor is applied.
expect(boxDecoration.color, backgroundColor);
final Rect titleRect = tester.getRect(find.text('Expanded Tile'));
final Rect trailingRect = tester.getRect(find.byIcon(Icons.expand_more));
final Rect listTileRect = tester.getRect(find.byType(ListTile));
final Rect tallerWidget = titleRect.height > trailingRect.height ? titleRect : trailingRect;
// Check the positions of title and trailing Widgets, after padding is applied.
expect(listTileRect.left, titleRect.left - 8);
expect(listTileRect.right, trailingRect.right + 4);
// Calculate the remaining height of ListTile from the default height.
final double remainingHeight = 56 - tallerWidget.height;
expect(listTileRect.top, tallerWidget.top - remainingHeight / 2 - 12);
expect(listTileRect.bottom, tallerWidget.bottom + remainingHeight / 2 + 10);
Color getIconColor() => tester.state<TestIconState>(find.byType(TestIcon)).iconTheme.color!;
Color getTextColor() => tester.state<TestTextState>(find.byType(TestText)).textStyle.color!;
// Check the expanded icon color when iconColor is applied.
expect(getIconColor(), iconColor);
// Check the expanded text color when textColor is applied.
expect(getTextColor(), textColor);
// Check the child position when expandedAlignment is applied.
final Rect childRect = tester.getRect(find.text('Tile 1'));
expect(childRect.right, 800 - 20);
expect(childRect.left, 800 - childRect.width - 20);
// Check the child padding when childrenPadding is applied.
final Rect paddingRect = tester.getRect(find.byType(Padding).last);
expect(childRect.top, paddingRect.top + 20);
expect(childRect.left, paddingRect.left + 20);
expect(childRect.right, paddingRect.right - 20);
expect(childRect.bottom, paddingRect.bottom - 20);
});
}
......@@ -430,6 +430,7 @@ void main() {
sliderTheme: sliderTheme,
tabBarTheme: const TabBarTheme(labelColor: Colors.black),
tooltipTheme: const TooltipThemeData(height: 100),
expansionTileTheme: const ExpansionTileThemeData(backgroundColor: Colors.black),
cardTheme: const CardTheme(color: Colors.black),
chipTheme: chipTheme,
platform: TargetPlatform.iOS,
......@@ -529,6 +530,7 @@ void main() {
sliderTheme: otherSliderTheme,
tabBarTheme: const TabBarTheme(labelColor: Colors.white),
tooltipTheme: const TooltipThemeData(height: 100),
expansionTileTheme: const ExpansionTileThemeData(backgroundColor: Colors.black),
cardTheme: const CardTheme(color: Colors.white),
chipTheme: otherChipTheme,
platform: TargetPlatform.android,
......@@ -841,6 +843,7 @@ void main() {
'timePickerTheme',
'toggleButtonsTheme',
'tooltipTheme',
'expansionTileTheme',
// DEPRECATED (newest deprecations at the bottom)
'useTextSelectionTheme',
'textSelectionColor',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment