Unverified Commit 13844aa6 authored by rami-a's avatar rami-a Committed by GitHub

[Material] Create theme for Dividers to enable customization of thickness (#38621)

parent 95b51061
......@@ -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),
),
),
),
......
// 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 {
......
// 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,
);
}
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