[Material] Create theme for Dividers to enable customization of thickness (#38621)
This commit is contained in:
parent
95b510618e
commit
13844aa62a
@ -50,6 +50,7 @@ export 'src/material/debug.dart';
|
||||
export 'src/material/dialog.dart';
|
||||
export 'src/material/dialog_theme.dart';
|
||||
export 'src/material/divider.dart';
|
||||
export 'src/material/divider_theme.dart';
|
||||
export 'src/material/drawer.dart';
|
||||
export 'src/material/drawer_header.dart';
|
||||
export 'src/material/dropdown.dart';
|
||||
|
@ -5,18 +5,18 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter/painting.dart';
|
||||
|
||||
import 'divider_theme.dart';
|
||||
import 'theme.dart';
|
||||
|
||||
// Examples can assume:
|
||||
// BuildContext context;
|
||||
|
||||
/// A one device pixel thick horizontal line, with padding on either
|
||||
/// side.
|
||||
/// A thin horizontal line, with padding on either side.
|
||||
///
|
||||
/// In the material design language, this represents a divider. Dividers can be
|
||||
/// used in lists, [Drawer]s, and elsewhere to separate content.
|
||||
///
|
||||
/// To create a one-pixel divider between [ListTile] items, consider using
|
||||
/// To create a divider between [ListTile] items, consider using
|
||||
/// [ListTile.divideTiles], which is optimized for this case.
|
||||
///
|
||||
/// The box's total height is controlled by [height]. The appropriate
|
||||
@ -30,36 +30,56 @@ import 'theme.dart';
|
||||
class Divider extends StatelessWidget {
|
||||
/// Creates a material design divider.
|
||||
///
|
||||
/// The height must be positive.
|
||||
/// The [height], [thickness], [indent], and [endIndent] must be null or
|
||||
/// non-negative.
|
||||
const Divider({
|
||||
Key key,
|
||||
this.height = 16.0,
|
||||
this.indent = 0.0,
|
||||
this.endIndent = 0.0,
|
||||
this.height,
|
||||
this.thickness,
|
||||
this.indent,
|
||||
this.endIndent,
|
||||
this.color,
|
||||
}) : assert(height >= 0.0),
|
||||
}) : assert(height == null || height >= 0.0),
|
||||
assert(thickness == null || thickness >= 0.0),
|
||||
assert(indent == null || indent >= 0.0),
|
||||
assert(endIndent == null || endIndent >= 0.0),
|
||||
super(key: key);
|
||||
|
||||
|
||||
/// The divider's height extent.
|
||||
///
|
||||
/// The divider itself is always drawn as one device pixel thick horizontal
|
||||
/// line that is centered within the height specified by this value.
|
||||
/// The divider itself is always drawn as a horizontal line that is centered
|
||||
/// within the height specified by this value.
|
||||
///
|
||||
/// A divider with a [height] of 0.0 is always drawn as a line with a height
|
||||
/// of exactly one device pixel, without any padding around it.
|
||||
/// If this is null, then the [DividerThemeData.space] is used. If that is
|
||||
/// also null, then this defaults to 16.0.
|
||||
final double height;
|
||||
|
||||
/// The amount of empty space to the left of the divider.
|
||||
/// The thickness of the line drawn within the divider.
|
||||
///
|
||||
/// A divider with a [thickness] of 0.0 is always drawn as a line with a
|
||||
/// height of exactly one device pixel.
|
||||
///
|
||||
/// If this is null, then the [DividerThemeData.dividerThickness] is used. If
|
||||
/// that is also null, then this defaults to 0.0.
|
||||
final double thickness;
|
||||
|
||||
/// The amount of empty space to the leading edge of the divider.
|
||||
///
|
||||
/// If this is null, then the [DividerThemeData.indent] is used. If that is
|
||||
/// also null, then this defaults to 0.0.
|
||||
final double indent;
|
||||
|
||||
/// The amount of empty space to the right of the divider.
|
||||
/// The amount of empty space to the trailing edge of the divider.
|
||||
///
|
||||
/// If this is null, then the [DividerThemeData.endIndent] is used. If that is
|
||||
/// also null, then this defaults to 0.0.
|
||||
final double endIndent;
|
||||
|
||||
/// The color to use when painting the line.
|
||||
///
|
||||
/// Defaults to the current theme's divider color, given by
|
||||
/// [ThemeData.dividerColor].
|
||||
/// If this is null, then the [DividerThemeData.color] is used. If that is
|
||||
/// also null, then [ThemeData.dividerColor] is used.
|
||||
///
|
||||
/// {@tool sample}
|
||||
///
|
||||
@ -76,7 +96,7 @@ class Divider extends StatelessWidget {
|
||||
/// [ThemeData.dividerColor] specified in the ambient [Theme].
|
||||
///
|
||||
/// The `width` argument can be used to override the default width of the
|
||||
/// divider border, which is usually 0.0 (a hairline border).
|
||||
/// divider border, which defaults to 0.0 (a hairline border).
|
||||
///
|
||||
/// {@tool sample}
|
||||
///
|
||||
@ -96,25 +116,30 @@ class Divider extends StatelessWidget {
|
||||
/// )
|
||||
/// ```
|
||||
/// {@end-tool}
|
||||
static BorderSide createBorderSide(BuildContext context, { Color color, double width = 0.0 }) {
|
||||
assert(width != null);
|
||||
static BorderSide createBorderSide(BuildContext context, { Color color, double width }) {
|
||||
return BorderSide(
|
||||
color: color ?? Theme.of(context).dividerColor,
|
||||
width: width,
|
||||
color: color ?? DividerTheme.of(context).color ?? Theme.of(context).dividerColor,
|
||||
width: width ?? DividerTheme.of(context).thickness ?? 0.0,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final DividerThemeData dividerTheme = DividerTheme.of(context);
|
||||
final double height = this.height ?? dividerTheme.space ?? 16.0;
|
||||
final double thickness = this.thickness ?? dividerTheme.thickness ?? 0.0;
|
||||
final double indent = this.indent ?? dividerTheme.indent ?? 0.0;
|
||||
final double endIndent = this.endIndent ?? dividerTheme.endIndent ?? 0.0;
|
||||
|
||||
return SizedBox(
|
||||
height: height,
|
||||
child: Center(
|
||||
child: Container(
|
||||
height: 0.0,
|
||||
height: thickness,
|
||||
margin: EdgeInsetsDirectional.only(start: indent, end: endIndent),
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
bottom: createBorderSide(context, color: color),
|
||||
bottom: createBorderSide(context, color: color, width: thickness),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -123,8 +148,7 @@ class Divider extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
/// A one device pixel thick vertical line, with padding on either
|
||||
/// side.
|
||||
/// A thin vertical line, with padding on either side.
|
||||
///
|
||||
/// In the material design language, this represents a divider. Vertical
|
||||
/// dividers can be used in horizontally scrolling lists, such as a
|
||||
@ -138,37 +162,57 @@ class Divider extends StatelessWidget {
|
||||
/// * [ListView.separated], which can be used to generate vertical dividers.
|
||||
/// * <https://material.io/design/components/dividers.html>
|
||||
class VerticalDivider extends StatelessWidget {
|
||||
/// Creates a material design divider.
|
||||
/// Creates a material design vertical divider.
|
||||
///
|
||||
/// The width must be positive.
|
||||
/// The [width], [thickness], [indent], and [endIndent] must be null or
|
||||
/// non-negative.
|
||||
const VerticalDivider({
|
||||
Key key,
|
||||
this.width = 16.0,
|
||||
this.indent = 0.0,
|
||||
this.endIndent = 0.0,
|
||||
this.width,
|
||||
this.thickness,
|
||||
this.indent,
|
||||
this.endIndent,
|
||||
this.color,
|
||||
}) : assert(width >= 0.0),
|
||||
}) : assert(width == null || width >= 0.0),
|
||||
assert(thickness == null || thickness >= 0.0),
|
||||
assert(indent == null || indent >= 0.0),
|
||||
assert(endIndent == null || endIndent >= 0.0),
|
||||
super(key: key);
|
||||
|
||||
/// The divider's width.
|
||||
///
|
||||
/// The divider itself is always drawn as one device pixel thick
|
||||
/// line that is centered within the width specified by this value.
|
||||
/// The divider itself is always drawn as a vertical line that is centered
|
||||
/// within the width specified by this value.
|
||||
///
|
||||
/// A divider with a [width] of 0.0 is always drawn as a line with a width
|
||||
/// of exactly one device pixel, without any padding around it.
|
||||
/// If this is null, then the [DividerThemeData.space] is used. If that is
|
||||
/// also null, then this defaults to 16.0.
|
||||
final double width;
|
||||
|
||||
/// The thickness of the line drawn within the divider.
|
||||
///
|
||||
/// A divider with a [thickness] of 0.0 is always drawn as a line with a
|
||||
/// width of exactly one device pixel.
|
||||
///
|
||||
/// If this is null, then the [DividerThemeData.thickness] is used which
|
||||
/// defaults to 0.0.
|
||||
final double thickness;
|
||||
|
||||
/// The amount of empty space on top of the divider.
|
||||
///
|
||||
/// If this is null, then the [DividerThemeData.indent] is used. If that is
|
||||
/// also null, then this defaults to 0.0.
|
||||
final double indent;
|
||||
|
||||
/// The amount of empty space under the divider.
|
||||
///
|
||||
/// If this is null, then the [DividerThemeData.endIndent] is used. If that is
|
||||
/// also null, then this defaults to 0.0.
|
||||
final double endIndent;
|
||||
|
||||
/// The color to use when painting the line.
|
||||
///
|
||||
/// Defaults to the current theme's divider color, given by
|
||||
/// [ThemeData.dividerColor].
|
||||
/// If this is null, then the [DividerThemeData.color] is used. If that is
|
||||
/// also null, then [ThemeData.dividerColor] is used.
|
||||
///
|
||||
/// {@tool sample}
|
||||
///
|
||||
@ -182,15 +226,21 @@ class VerticalDivider extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final DividerThemeData dividerTheme = DividerTheme.of(context);
|
||||
final double width = this.width ?? dividerTheme.space ?? 16.0;
|
||||
final double thickness = this.thickness ?? dividerTheme.thickness ?? 0.0;
|
||||
final double indent = this.indent ?? dividerTheme.indent ?? 0.0;
|
||||
final double endIndent = this.endIndent ?? dividerTheme.endIndent ?? 0.0;
|
||||
|
||||
return SizedBox(
|
||||
width: width,
|
||||
child: Center(
|
||||
child: Container(
|
||||
width: 0.0,
|
||||
width: thickness,
|
||||
margin: EdgeInsetsDirectional.only(top: indent, bottom: endIndent),
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
left: Divider.createBorderSide(context, color: color),
|
||||
left: Divider.createBorderSide(context, color: color, width: thickness),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
168
packages/flutter/lib/src/material/divider_theme.dart
Normal file
168
packages/flutter/lib/src/material/divider_theme.dart
Normal file
@ -0,0 +1,168 @@
|
||||
// Copyright 2019 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:ui' show lerpDouble;
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'theme.dart';
|
||||
|
||||
/// Defines the visual properties of [Divider], [VerticalDivider], dividers
|
||||
/// between [ListTile]s, and dividers between rows in [DataTable]s.
|
||||
///
|
||||
/// Descendant widgets obtain the current [DividerThemeData] object using
|
||||
/// `DividerTheme.of(context)`. Instances of [DividerThemeData]
|
||||
/// can be customized with [DividerThemeData.copyWith].
|
||||
///
|
||||
/// Typically a [DividerThemeData] is specified as part of the overall
|
||||
/// [Theme] with [ThemeData.dividerTheme].
|
||||
///
|
||||
/// All [DividerThemeData] properties are `null` by default. When null,
|
||||
/// the widgets will provide their own defaults.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [ThemeData], which describes the overall theme information for the
|
||||
/// application.
|
||||
class DividerThemeData extends Diagnosticable {
|
||||
|
||||
/// Creates a theme that can be used for [DividerTheme] or
|
||||
/// [ThemeData.dividerTheme].
|
||||
const DividerThemeData({
|
||||
this.color,
|
||||
this.space,
|
||||
this.thickness,
|
||||
this.indent,
|
||||
this.endIndent,
|
||||
});
|
||||
|
||||
/// The color of [Divider]s and [VerticalDivider]s, also
|
||||
/// used between [ListTile]s, between rows in [DataTable]s, and so forth.
|
||||
final Color color;
|
||||
|
||||
/// The [Divider]'s width or the [VerticalDivider]'s height.
|
||||
///
|
||||
/// This represents the amount of horizontal or vertical space the divider
|
||||
/// takes up.
|
||||
final double space;
|
||||
|
||||
/// The thickness of the line drawn within the divider.
|
||||
final double thickness;
|
||||
|
||||
/// The amount of empty space at the leading edge of [Divider] or top edge of
|
||||
/// [VerticalDivider].
|
||||
final double indent;
|
||||
|
||||
/// The amount of empty space at the trailing edge of [Divider] or bottom edge
|
||||
/// of [VerticalDivider].
|
||||
final double endIndent;
|
||||
|
||||
/// Creates a copy of this object with the given fields replaced with the
|
||||
/// new values.
|
||||
DividerThemeData copyWith({
|
||||
Color color,
|
||||
double space,
|
||||
double thickness,
|
||||
double indent,
|
||||
double endIndent,
|
||||
}) {
|
||||
return DividerThemeData(
|
||||
color: color ?? this.color,
|
||||
space: space ?? this.space,
|
||||
thickness: thickness ?? this.thickness,
|
||||
indent: indent ?? this.indent,
|
||||
endIndent: endIndent ?? this.endIndent,
|
||||
);
|
||||
}
|
||||
|
||||
/// Linearly interpolate between two Divider themes.
|
||||
///
|
||||
/// The argument `t` must not be null.
|
||||
///
|
||||
/// {@macro dart.ui.shadow.lerp}
|
||||
static DividerThemeData lerp(DividerThemeData a, DividerThemeData b, double t) {
|
||||
assert(t != null);
|
||||
return DividerThemeData(
|
||||
color: Color.lerp(a?.color, b?.color, t),
|
||||
space: lerpDouble(a?.space, b?.space, t),
|
||||
thickness: lerpDouble(a?.thickness, b?.thickness, t),
|
||||
indent: lerpDouble(a?.indent, b?.indent, t),
|
||||
endIndent: lerpDouble(a?.endIndent, b?.endIndent, t),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return hashValues(
|
||||
color,
|
||||
space,
|
||||
thickness,
|
||||
indent,
|
||||
endIndent,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(dynamic other) {
|
||||
if (identical(this, other))
|
||||
return true;
|
||||
if (other.runtimeType != runtimeType)
|
||||
return false;
|
||||
final DividerThemeData typedOther = other;
|
||||
return typedOther.color == color
|
||||
&& typedOther.space == space
|
||||
&& typedOther.thickness == thickness
|
||||
&& typedOther.indent == indent
|
||||
&& typedOther.endIndent == endIndent;
|
||||
}
|
||||
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
super.debugFillProperties(properties);
|
||||
properties.add(ColorProperty('color', color, defaultValue: null));
|
||||
properties.add(DoubleProperty('space', space, defaultValue: null));
|
||||
properties.add(DoubleProperty('thickness', thickness, defaultValue: null));
|
||||
properties.add(DoubleProperty('indent', indent, defaultValue: null));
|
||||
properties.add(DoubleProperty('endIndent', endIndent, defaultValue: null));
|
||||
}
|
||||
}
|
||||
|
||||
/// An inherited widget that defines the configuration for
|
||||
/// [Divider]s, [VerticalDividers]s, dividers between [ListTile]s, and dividers
|
||||
/// between rows in [DataTable]s in this widget's subtree.
|
||||
class DividerTheme extends InheritedWidget {
|
||||
/// Creates a divider theme that controls the configurations for
|
||||
/// [Divider]s, [VerticalDividers]s, dividers between [ListTile]s, and dividers
|
||||
/// between rows in [DataTable]s in its widget subtree.
|
||||
const DividerTheme({
|
||||
Key key,
|
||||
@required this.data,
|
||||
Widget child,
|
||||
}) : assert(data != null),
|
||||
super(key: key, child: child);
|
||||
|
||||
/// The properties for descendant [Divider]s, [VerticalDividers]s, dividers
|
||||
/// between [ListTile]s, and dividers between rows in [DataTable]s.
|
||||
final DividerThemeData data;
|
||||
|
||||
/// The closest instance of this class's [data] value that encloses the given
|
||||
/// context.
|
||||
///
|
||||
/// If there is no ancestor, it returns [ThemeData.dividerTheme]. Applications
|
||||
/// can assume that the returned value will not be null.
|
||||
///
|
||||
/// Typical usage is as follows:
|
||||
///
|
||||
/// ```dart
|
||||
/// DividerThemeData theme = DividerTheme.of(context);
|
||||
/// ```
|
||||
static DividerThemeData of(BuildContext context) {
|
||||
final DividerTheme dividerTheme = context.inheritFromWidgetOfExactType(DividerTheme);
|
||||
return dividerTheme?.data ?? Theme.of(context).dividerTheme;
|
||||
}
|
||||
|
||||
@override
|
||||
bool updateShouldNotify(DividerTheme oldWidget) => data != oldWidget.data;
|
||||
}
|
@ -19,6 +19,7 @@ import 'chip_theme.dart';
|
||||
import 'color_scheme.dart';
|
||||
import 'colors.dart';
|
||||
import 'dialog_theme.dart';
|
||||
import 'divider_theme.dart';
|
||||
import 'floating_action_button_theme.dart';
|
||||
import 'ink_splash.dart';
|
||||
import 'ink_well.dart' show InteractiveInkFeatureFactory;
|
||||
@ -178,6 +179,7 @@ class ThemeData extends Diagnosticable {
|
||||
BottomSheetThemeData bottomSheetTheme,
|
||||
PopupMenuThemeData popupMenuTheme,
|
||||
MaterialBannerThemeData bannerTheme,
|
||||
DividerThemeData dividerTheme,
|
||||
}) {
|
||||
brightness ??= Brightness.light;
|
||||
final bool isDark = brightness == Brightness.dark;
|
||||
@ -282,6 +284,7 @@ class ThemeData extends Diagnosticable {
|
||||
bottomSheetTheme ??= const BottomSheetThemeData();
|
||||
popupMenuTheme ??= const PopupMenuThemeData();
|
||||
bannerTheme ??= const MaterialBannerThemeData();
|
||||
dividerTheme ??= const DividerThemeData();
|
||||
|
||||
return ThemeData.raw(
|
||||
brightness: brightness,
|
||||
@ -344,6 +347,7 @@ class ThemeData extends Diagnosticable {
|
||||
bottomSheetTheme: bottomSheetTheme,
|
||||
popupMenuTheme: popupMenuTheme,
|
||||
bannerTheme: bannerTheme,
|
||||
dividerTheme: dividerTheme,
|
||||
);
|
||||
}
|
||||
|
||||
@ -418,6 +422,7 @@ class ThemeData extends Diagnosticable {
|
||||
@required this.bottomSheetTheme,
|
||||
@required this.popupMenuTheme,
|
||||
@required this.bannerTheme,
|
||||
@required this.dividerTheme,
|
||||
}) : assert(brightness != null),
|
||||
assert(primaryColor != null),
|
||||
assert(primaryColorBrightness != null),
|
||||
@ -474,7 +479,8 @@ class ThemeData extends Diagnosticable {
|
||||
assert(snackBarTheme != null),
|
||||
assert(bottomSheetTheme != null),
|
||||
assert(popupMenuTheme != null),
|
||||
assert(bannerTheme != null);
|
||||
assert(bannerTheme != null),
|
||||
assert(dividerTheme != null);
|
||||
|
||||
/// Create a [ThemeData] based on the colors in the given [colorScheme] and
|
||||
/// text styles of the optional [textTheme].
|
||||
@ -867,6 +873,10 @@ class ThemeData extends Diagnosticable {
|
||||
/// A theme for customizing the color and text style of a [MaterialBanner].
|
||||
final MaterialBannerThemeData bannerTheme;
|
||||
|
||||
/// A theme for customizing the color, thickness, and indents of [Divider]s,
|
||||
/// [VerticalDivider]s, etc.
|
||||
final DividerThemeData dividerTheme;
|
||||
|
||||
/// Creates a copy of this theme but with the given fields replaced with the new values.
|
||||
ThemeData copyWith({
|
||||
Brightness brightness,
|
||||
@ -929,6 +939,7 @@ class ThemeData extends Diagnosticable {
|
||||
BottomSheetThemeData bottomSheetTheme,
|
||||
PopupMenuThemeData popupMenuTheme,
|
||||
MaterialBannerThemeData bannerTheme,
|
||||
DividerThemeData dividerTheme,
|
||||
}) {
|
||||
cupertinoOverrideTheme = cupertinoOverrideTheme?.noDefault();
|
||||
return ThemeData.raw(
|
||||
@ -992,6 +1003,7 @@ class ThemeData extends Diagnosticable {
|
||||
bottomSheetTheme: bottomSheetTheme ?? this.bottomSheetTheme,
|
||||
popupMenuTheme: popupMenuTheme ?? this.popupMenuTheme,
|
||||
bannerTheme: bannerTheme ?? this.bannerTheme,
|
||||
dividerTheme: dividerTheme ?? this.dividerTheme,
|
||||
);
|
||||
}
|
||||
|
||||
@ -1133,6 +1145,7 @@ class ThemeData extends Diagnosticable {
|
||||
bottomSheetTheme: BottomSheetThemeData.lerp(a.bottomSheetTheme, b.bottomSheetTheme, t),
|
||||
popupMenuTheme: PopupMenuThemeData.lerp(a.popupMenuTheme, b.popupMenuTheme, t),
|
||||
bannerTheme: MaterialBannerThemeData.lerp(a.bannerTheme, b.bannerTheme, t),
|
||||
dividerTheme: DividerThemeData.lerp(a.dividerTheme, b.dividerTheme, t),
|
||||
);
|
||||
}
|
||||
|
||||
@ -1201,7 +1214,8 @@ class ThemeData extends Diagnosticable {
|
||||
(otherData.snackBarTheme == snackBarTheme) &&
|
||||
(otherData.bottomSheetTheme == bottomSheetTheme) &&
|
||||
(otherData.popupMenuTheme == popupMenuTheme) &&
|
||||
(otherData.bannerTheme == bannerTheme);
|
||||
(otherData.bannerTheme == bannerTheme) &&
|
||||
(otherData.dividerTheme == dividerTheme);
|
||||
}
|
||||
|
||||
@override
|
||||
@ -1270,6 +1284,7 @@ class ThemeData extends Diagnosticable {
|
||||
bottomSheetTheme,
|
||||
popupMenuTheme,
|
||||
bannerTheme,
|
||||
dividerTheme,
|
||||
];
|
||||
return hashList(values);
|
||||
}
|
||||
@ -1335,6 +1350,7 @@ class ThemeData extends Diagnosticable {
|
||||
properties.add(DiagnosticsProperty<BottomSheetThemeData>('bottomSheetTheme', bottomSheetTheme, defaultValue: defaultData.bottomSheetTheme));
|
||||
properties.add(DiagnosticsProperty<PopupMenuThemeData>('popupMenuTheme', popupMenuTheme, defaultValue: defaultData.popupMenuTheme));
|
||||
properties.add(DiagnosticsProperty<MaterialBannerThemeData>('bannerTheme', bannerTheme, defaultValue: defaultData.bannerTheme));
|
||||
properties.add(DiagnosticsProperty<DividerThemeData>('dividerTheme', dividerTheme, defaultValue: defaultData.dividerTheme));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,25 @@ void main() {
|
||||
);
|
||||
final RenderBox box = tester.firstRenderObject(find.byType(Divider));
|
||||
expect(box.size.height, 16.0);
|
||||
expect(find.byType(Divider), paints..path(strokeWidth: 0.0));
|
||||
final Container container = tester.widget(find.byType(Container));
|
||||
final BoxDecoration decoration = container.decoration;
|
||||
expect(decoration.border.bottom.width, 0.0);
|
||||
});
|
||||
|
||||
testWidgets('Divider custom thickness', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: Center(
|
||||
child: Divider(
|
||||
thickness: 5.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
final Container container = tester.widget(find.byType(Container));
|
||||
final BoxDecoration decoration = container.decoration;
|
||||
expect(decoration.border.bottom.width, 5.0);
|
||||
});
|
||||
|
||||
testWidgets('Horizontal divider custom indentation', (WidgetTester tester) async {
|
||||
@ -86,7 +104,27 @@ void main() {
|
||||
);
|
||||
final RenderBox box = tester.firstRenderObject(find.byType(VerticalDivider));
|
||||
expect(box.size.width, 16.0);
|
||||
expect(find.byType(VerticalDivider), paints..path(strokeWidth: 0.0));
|
||||
final Container container = tester.widget(find.byType(Container));
|
||||
final BoxDecoration decoration = container.decoration;
|
||||
final Border border = decoration.border;
|
||||
expect(border.left.width, 0.0);
|
||||
});
|
||||
|
||||
testWidgets('Divider custom thickness', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: Center(
|
||||
child: VerticalDivider(
|
||||
thickness: 5.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
final Container container = tester.widget(find.byType(Container));
|
||||
final BoxDecoration decoration = container.decoration;
|
||||
final Border border = decoration.border;
|
||||
expect(border.left.width, 5.0);
|
||||
});
|
||||
|
||||
testWidgets('Vertical Divider Test 2', (WidgetTester tester) async {
|
||||
|
238
packages/flutter/test/material/divider_theme_test.dart
Normal file
238
packages/flutter/test/material/divider_theme_test.dart
Normal file
@ -0,0 +1,238 @@
|
||||
// Copyright 2019 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
test('DividerThemeData copyWith, ==, hashCode basics', () {
|
||||
expect(const DividerThemeData(), const DividerThemeData().copyWith());
|
||||
expect(const DividerThemeData().hashCode, const DividerThemeData().copyWith().hashCode);
|
||||
});
|
||||
|
||||
test('DividerThemeData null fields by default', () {
|
||||
const DividerThemeData dividerTheme = DividerThemeData();
|
||||
expect(dividerTheme.color, null);
|
||||
expect(dividerTheme.space, null);
|
||||
expect(dividerTheme.thickness, null);
|
||||
expect(dividerTheme.indent, null);
|
||||
expect(dividerTheme.endIndent, null);
|
||||
});
|
||||
|
||||
testWidgets('Default DividerThemeData debugFillProperties', (WidgetTester tester) async {
|
||||
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
|
||||
const DividerThemeData().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('DividerThemeData implements debugFillProperties', (WidgetTester tester) async {
|
||||
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
|
||||
const DividerThemeData(
|
||||
color: Color(0xFFFFFFFF),
|
||||
space: 5.0,
|
||||
thickness: 4.0,
|
||||
indent: 3.0,
|
||||
endIndent: 2.0,
|
||||
).debugFillProperties(builder);
|
||||
|
||||
final List<String> description = builder.properties
|
||||
.where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
|
||||
.map((DiagnosticsNode node) => node.toString())
|
||||
.toList();
|
||||
|
||||
expect(description, <String>[
|
||||
'color: Color(0xffffffff)',
|
||||
'space: 5.0',
|
||||
'thickness: 4.0',
|
||||
'indent: 3.0',
|
||||
'endIndent: 2.0',
|
||||
]);
|
||||
});
|
||||
|
||||
group('Horizontal Divider', () {
|
||||
testWidgets('Passing no DividerThemeData returns defaults', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(const MaterialApp(
|
||||
home: Scaffold(
|
||||
body: Divider(),
|
||||
),
|
||||
));
|
||||
|
||||
final RenderBox box = tester.firstRenderObject(find.byType(Divider));
|
||||
expect(box.size.height, 16.0);
|
||||
|
||||
final Container container = tester.widget(find.byType(Container));
|
||||
final BoxDecoration decoration = container.decoration;
|
||||
expect(decoration.border.bottom.width, 0.0);
|
||||
|
||||
final ThemeData theme = ThemeData();
|
||||
expect(decoration.border.bottom.color, theme.dividerColor);
|
||||
|
||||
final Rect dividerRect = tester.getRect(find.byType(Divider));
|
||||
final Rect lineRect = tester.getRect(find.byType(DecoratedBox));
|
||||
expect(lineRect.left, dividerRect.left);
|
||||
expect(lineRect.right, dividerRect.right);
|
||||
});
|
||||
|
||||
testWidgets('Uses values from DividerThemeData', (WidgetTester tester) async {
|
||||
final DividerThemeData dividerTheme = _dividerTheme();
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
theme: ThemeData(dividerTheme: dividerTheme),
|
||||
home: const Scaffold(
|
||||
body: Divider(),
|
||||
),
|
||||
));
|
||||
|
||||
final RenderBox box = tester.firstRenderObject(find.byType(Divider));
|
||||
expect(box.size.height, dividerTheme.space);
|
||||
|
||||
final Container container = tester.widget(find.byType(Container));
|
||||
final BoxDecoration decoration = container.decoration;
|
||||
expect(decoration.border.bottom.width, dividerTheme.thickness);
|
||||
expect(decoration.border.bottom.color, dividerTheme.color);
|
||||
|
||||
final Rect dividerRect = tester.getRect(find.byType(Divider));
|
||||
final Rect lineRect = tester.getRect(find.byType(DecoratedBox));
|
||||
expect(lineRect.left, dividerRect.left + dividerTheme.indent);
|
||||
expect(lineRect.right, dividerRect.right - dividerTheme.endIndent);
|
||||
});
|
||||
|
||||
testWidgets('Widget properties take priority over theme', (WidgetTester tester) async {
|
||||
const Color color = Colors.purple;
|
||||
const double height = 10.0;
|
||||
const double thickness = 5.0;
|
||||
const double indent = 8.0;
|
||||
const double endIndent = 9.0;
|
||||
|
||||
final DividerThemeData dividerTheme = _dividerTheme();
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
theme: ThemeData(dividerTheme: dividerTheme),
|
||||
home: const Scaffold(
|
||||
body: Divider(
|
||||
color: color,
|
||||
height: height,
|
||||
thickness: thickness,
|
||||
indent: indent,
|
||||
endIndent: endIndent,
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
final RenderBox box = tester.firstRenderObject(find.byType(Divider));
|
||||
expect(box.size.height, height);
|
||||
|
||||
final Container container = tester.widget(find.byType(Container));
|
||||
final BoxDecoration decoration = container.decoration;
|
||||
expect(decoration.border.bottom.width, thickness);
|
||||
expect(decoration.border.bottom.color, color);
|
||||
|
||||
final Rect dividerRect = tester.getRect(find.byType(Divider));
|
||||
final Rect lineRect = tester.getRect(find.byType(DecoratedBox));
|
||||
expect(lineRect.left, dividerRect.left + indent);
|
||||
expect(lineRect.right, dividerRect.right - endIndent);
|
||||
});
|
||||
});
|
||||
|
||||
group('Vertical Divider', () {
|
||||
testWidgets('Passing no DividerThemeData returns defaults', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(const MaterialApp(
|
||||
home: Scaffold(
|
||||
body: VerticalDivider(),
|
||||
),
|
||||
));
|
||||
|
||||
final RenderBox box = tester.firstRenderObject(find.byType(VerticalDivider));
|
||||
expect(box.size.width, 16.0);
|
||||
|
||||
final Container container = tester.widget(find.byType(Container));
|
||||
final BoxDecoration decoration = container.decoration;
|
||||
final Border border = decoration.border;
|
||||
expect(border.left.width, 0.0);
|
||||
|
||||
final ThemeData theme = ThemeData();
|
||||
expect(border.left.color, theme.dividerColor);
|
||||
|
||||
final Rect dividerRect = tester.getRect(find.byType(VerticalDivider));
|
||||
final Rect lineRect = tester.getRect(find.byType(DecoratedBox));
|
||||
expect(lineRect.top, dividerRect.top);
|
||||
expect(lineRect.bottom, dividerRect.bottom);
|
||||
});
|
||||
|
||||
testWidgets('Uses values from DividerThemeData', (WidgetTester tester) async {
|
||||
final DividerThemeData dividerTheme = _dividerTheme();
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
theme: ThemeData(dividerTheme: dividerTheme),
|
||||
home: const Scaffold(
|
||||
body: VerticalDivider(),
|
||||
),
|
||||
));
|
||||
|
||||
final RenderBox box = tester.firstRenderObject(find.byType(VerticalDivider));
|
||||
expect(box.size.width, dividerTheme.space);
|
||||
|
||||
final Container container = tester.widget(find.byType(Container));
|
||||
final BoxDecoration decoration = container.decoration;
|
||||
final Border border = decoration.border;
|
||||
expect(border.left.width, dividerTheme.thickness);
|
||||
expect(border.left.color, dividerTheme.color);
|
||||
|
||||
final Rect dividerRect = tester.getRect(find.byType(VerticalDivider));
|
||||
final Rect lineRect = tester.getRect(find.byType(DecoratedBox));
|
||||
expect(lineRect.top, dividerRect.top + dividerTheme.indent);
|
||||
expect(lineRect.bottom, dividerRect.bottom - dividerTheme.endIndent);
|
||||
});
|
||||
|
||||
testWidgets('Widget properties take priority over theme', (WidgetTester tester) async {
|
||||
const Color color = Colors.purple;
|
||||
const double width = 10.0;
|
||||
const double thickness = 5.0;
|
||||
const double indent = 8.0;
|
||||
const double endIndent = 9.0;
|
||||
|
||||
final DividerThemeData dividerTheme = _dividerTheme();
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
theme: ThemeData(dividerTheme: dividerTheme),
|
||||
home: const Scaffold(
|
||||
body: VerticalDivider(
|
||||
color: color,
|
||||
width: width,
|
||||
thickness: thickness,
|
||||
indent: indent,
|
||||
endIndent: endIndent,
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
final RenderBox box = tester.firstRenderObject(find.byType(VerticalDivider));
|
||||
expect(box.size.width, width);
|
||||
|
||||
final Container container = tester.widget(find.byType(Container));
|
||||
final BoxDecoration decoration = container.decoration;
|
||||
final Border border = decoration.border;
|
||||
expect(border.left.width, thickness);
|
||||
expect(border.left.color, color);
|
||||
|
||||
final Rect dividerRect = tester.getRect(find.byType(VerticalDivider));
|
||||
final Rect lineRect = tester.getRect(find.byType(DecoratedBox));
|
||||
expect(lineRect.top, dividerRect.top + indent);
|
||||
expect(lineRect.bottom, dividerRect.bottom - endIndent);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
DividerThemeData _dividerTheme() {
|
||||
return const DividerThemeData(
|
||||
color: Colors.orange,
|
||||
space: 12.0,
|
||||
thickness: 2.0,
|
||||
indent: 7.0,
|
||||
endIndent: 5.0,
|
||||
);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user