IconThemeData.size (#4633)
This commit is contained in:
parent
5809a0cb71
commit
cff31a3f6d
@ -26,29 +26,34 @@ import 'theme.dart';
|
|||||||
///
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [IconButton], for interactive icons
|
/// * [IconButton], for interactive icons.
|
||||||
/// * [Icons], for the list of available icons for use with this class
|
/// * [Icons], for the list of available icons for use with this class.
|
||||||
|
/// * [IconTheme], which provides ambient configuration for icons.
|
||||||
class Icon extends StatelessWidget {
|
class Icon extends StatelessWidget {
|
||||||
/// Creates an icon.
|
/// Creates an icon.
|
||||||
///
|
///
|
||||||
/// The [size] argument most not be null.
|
/// The [size] and [color] default to the value given by the current [IconTheme].
|
||||||
Icon({
|
const Icon({
|
||||||
Key key,
|
Key key,
|
||||||
this.icon,
|
this.icon,
|
||||||
this.size: 24.0,
|
this.size,
|
||||||
this.color
|
this.color
|
||||||
}) : super(key: key) {
|
}) : super(key: key);
|
||||||
assert(size != null);
|
|
||||||
}
|
/// The icon to display. The available icons are described in [Icons].
|
||||||
|
///
|
||||||
|
/// If null, no icon is shown.
|
||||||
|
final IconData icon;
|
||||||
|
|
||||||
/// The size of the icon in logical pixels.
|
/// The size of the icon in logical pixels.
|
||||||
///
|
///
|
||||||
/// Icons occupy a square with width and height equal to size.
|
/// Icons occupy a square with width and height equal to size.
|
||||||
|
///
|
||||||
|
/// Defaults to the current [IconTheme] size, if any. If there is no
|
||||||
|
/// [IconTheme], or it does not specify an explicit size, then it defaults to
|
||||||
|
/// 24.0.
|
||||||
final double size;
|
final double size;
|
||||||
|
|
||||||
/// The icon to display. The available icons are described in [Icons].
|
|
||||||
final IconData icon;
|
|
||||||
|
|
||||||
/// The color to use when drawing the icon.
|
/// The color to use when drawing the icon.
|
||||||
///
|
///
|
||||||
/// Defaults to the current [IconTheme] color, if any. If there is
|
/// Defaults to the current [IconTheme] color, if any. If there is
|
||||||
@ -56,6 +61,9 @@ class Icon extends StatelessWidget {
|
|||||||
/// and black if the theme is light. See [Theme] to set the current
|
/// and black if the theme is light. See [Theme] to set the current
|
||||||
/// theme and [ThemeData.brightness] for setting the current theme's
|
/// theme and [ThemeData.brightness] for setting the current theme's
|
||||||
/// brightness.
|
/// brightness.
|
||||||
|
///
|
||||||
|
/// The given color will be adjusted by the opacity of the current
|
||||||
|
/// [IconTheme], if any.
|
||||||
final Color color;
|
final Color color;
|
||||||
|
|
||||||
Color _getDefaultColorForBrightness(Brightness brightness) {
|
Color _getDefaultColorForBrightness(Brightness brightness) {
|
||||||
@ -75,8 +83,10 @@ class Icon extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final double iconSize = size ?? IconTheme.of(context)?.size ?? 24.0;
|
||||||
|
|
||||||
if (icon == null)
|
if (icon == null)
|
||||||
return new SizedBox(width: size, height: size);
|
return new SizedBox(width: iconSize, height: iconSize);
|
||||||
|
|
||||||
final double iconOpacity = IconTheme.of(context)?.opacity ?? 1.0;
|
final double iconOpacity = IconTheme.of(context)?.opacity ?? 1.0;
|
||||||
Color iconColor = color ?? _getDefaultColor(context);
|
Color iconColor = color ?? _getDefaultColor(context);
|
||||||
@ -85,15 +95,15 @@ class Icon extends StatelessWidget {
|
|||||||
|
|
||||||
return new ExcludeSemantics(
|
return new ExcludeSemantics(
|
||||||
child: new SizedBox(
|
child: new SizedBox(
|
||||||
width: size,
|
width: iconSize,
|
||||||
height: size,
|
height: iconSize,
|
||||||
child: new Center(
|
child: new Center(
|
||||||
child: new Text(
|
child: new Text(
|
||||||
new String.fromCharCode(icon.codePoint),
|
new String.fromCharCode(icon.codePoint),
|
||||||
style: new TextStyle(
|
style: new TextStyle(
|
||||||
inherit: false,
|
inherit: false,
|
||||||
color: iconColor,
|
color: iconColor,
|
||||||
fontSize: size,
|
fontSize: iconSize,
|
||||||
fontFamily: 'MaterialIcons'
|
fontFamily: 'MaterialIcons'
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -105,9 +115,14 @@ class Icon extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
void debugFillDescription(List<String> description) {
|
void debugFillDescription(List<String> description) {
|
||||||
super.debugFillDescription(description);
|
super.debugFillDescription(description);
|
||||||
description.add('$icon');
|
if (icon != null) {
|
||||||
description.add('size: $size');
|
description.add('$icon');
|
||||||
if (this.color != null)
|
} else {
|
||||||
|
description.add('<empty>');
|
||||||
|
}
|
||||||
|
if (size != null)
|
||||||
|
description.add('size: $size');
|
||||||
|
if (color != null)
|
||||||
description.add('color: $color');
|
description.add('color: $color');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,9 +7,10 @@ import 'package:meta/meta.dart';
|
|||||||
|
|
||||||
import 'icon_theme_data.dart';
|
import 'icon_theme_data.dart';
|
||||||
|
|
||||||
/// Controls the color and opacity of icons in a widget subtree.
|
/// Controls the default color, opacity, and size of icons in a widget subtree.
|
||||||
class IconTheme extends InheritedWidget {
|
class IconTheme extends InheritedWidget {
|
||||||
/// Creates an icon theme that controls the color and opacity of descendant widgets.
|
/// Creates an icon theme that controls the color, opacity, and size of
|
||||||
|
/// descendant widgets.
|
||||||
///
|
///
|
||||||
/// Both [data] and [child] arguments must not be null.
|
/// Both [data] and [child] arguments must not be null.
|
||||||
IconTheme({
|
IconTheme({
|
||||||
@ -21,7 +22,7 @@ class IconTheme extends InheritedWidget {
|
|||||||
assert(child != null);
|
assert(child != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The color and opacity to use for icons in this subtree.
|
/// The color, opacity, and size to use for icons in this subtree.
|
||||||
final IconThemeData data;
|
final IconThemeData data;
|
||||||
|
|
||||||
/// The data from the closest instance of this class that encloses the given context.
|
/// The data from the closest instance of this class that encloses the given context.
|
||||||
|
@ -5,16 +5,16 @@
|
|||||||
import 'dart:ui' as ui show lerpDouble;
|
import 'dart:ui' as ui show lerpDouble;
|
||||||
import 'dart:ui' show Color, hashValues;
|
import 'dart:ui' show Color, hashValues;
|
||||||
|
|
||||||
/// Defines the color and opacity of icons.
|
/// Defines the color, opacity, and size of icons.
|
||||||
///
|
///
|
||||||
/// Used by [IconTheme] to control the color and opacity of icons in a widget
|
/// Used by [IconTheme] to control the color, opacity, and size of icons in a
|
||||||
/// subtree.
|
/// widget subtree.
|
||||||
class IconThemeData {
|
class IconThemeData {
|
||||||
/// Creates an icon theme data.
|
/// Creates an icon theme data.
|
||||||
///
|
///
|
||||||
/// The opacity applies to both explicit and default icon colors. The value
|
/// The opacity applies to both explicit and default icon colors. The value
|
||||||
/// is clamped between 0.0 and 1.0.
|
/// is clamped between 0.0 and 1.0.
|
||||||
const IconThemeData({ this.color, double opacity: 1.0 }) : _opacity = opacity;
|
const IconThemeData({ this.color, double opacity: 1.0, this.size }) : _opacity = opacity;
|
||||||
|
|
||||||
/// The default color for icons.
|
/// The default color for icons.
|
||||||
final Color color;
|
final Color color;
|
||||||
@ -23,25 +23,42 @@ class IconThemeData {
|
|||||||
double get opacity => (_opacity ?? 1.0).clamp(0.0, 1.0);
|
double get opacity => (_opacity ?? 1.0).clamp(0.0, 1.0);
|
||||||
final double _opacity;
|
final double _opacity;
|
||||||
|
|
||||||
|
/// The default size for icons.
|
||||||
|
final double size;
|
||||||
|
|
||||||
/// Linearly interpolate between two icon theme data objects.
|
/// Linearly interpolate between two icon theme data objects.
|
||||||
static IconThemeData lerp(IconThemeData begin, IconThemeData end, double t) {
|
static IconThemeData lerp(IconThemeData begin, IconThemeData end, double t) {
|
||||||
return new IconThemeData(
|
return new IconThemeData(
|
||||||
color: Color.lerp(begin.color, end.color, t),
|
color: Color.lerp(begin.color, end.color, t),
|
||||||
opacity: ui.lerpDouble(begin.opacity, end.opacity, t)
|
opacity: ui.lerpDouble(begin.opacity, end.opacity, t),
|
||||||
|
size: ui.lerpDouble(begin.size, end.size, t)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(dynamic other) {
|
bool operator ==(dynamic other) {
|
||||||
if (other is! IconThemeData)
|
if (other.runtimeType != runtimeType)
|
||||||
return false;
|
return false;
|
||||||
final IconThemeData typedOther = other;
|
final IconThemeData typedOther = other;
|
||||||
return color == typedOther.color && opacity == typedOther.opacity;
|
return color == typedOther.color
|
||||||
|
&& opacity == typedOther.opacity
|
||||||
|
&& size == typedOther.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => hashValues(color, opacity);
|
int get hashCode => hashValues(color, opacity, size);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() => '$color';
|
String toString() {
|
||||||
|
List<String> result = <String>[];
|
||||||
|
if (color != null)
|
||||||
|
result.add('color: $color');
|
||||||
|
if (opacity != 1.0)
|
||||||
|
result.add('opacity: $opacity');
|
||||||
|
if (size != null)
|
||||||
|
result.add('size: $size');
|
||||||
|
if (result.length == 0)
|
||||||
|
return '<no theme>';
|
||||||
|
return result.join(', ');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
78
packages/flutter/test/material/icon_test.dart
Normal file
78
packages/flutter/test/material/icon_test.dart
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
// Copyright 2015 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/widgets.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets('Icon sizing - no theme, default size', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
new Center(
|
||||||
|
child: new Icon()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
RenderBox renderObject = tester.renderObject(find.byType(Icon));
|
||||||
|
expect(renderObject.size, equals(const Size.square(24.0)));
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('Icon sizing - no theme, explicit size', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
new Center(
|
||||||
|
child: new Icon(
|
||||||
|
size: 96.0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
RenderBox renderObject = tester.renderObject(find.byType(Icon));
|
||||||
|
expect(renderObject.size, equals(const Size.square(96.0)));
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('Icon sizing - sized theme', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
new Center(
|
||||||
|
child: new IconTheme(
|
||||||
|
data: new IconThemeData(size: 36.0),
|
||||||
|
child: new Icon()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
RenderBox renderObject = tester.renderObject(find.byType(Icon));
|
||||||
|
expect(renderObject.size, equals(const Size.square(36.0)));
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('Icon sizing - sized theme, explicit size', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
new Center(
|
||||||
|
child: new IconTheme(
|
||||||
|
data: new IconThemeData(size: 36.0),
|
||||||
|
child: new Icon(
|
||||||
|
size: 48.0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
RenderBox renderObject = tester.renderObject(find.byType(Icon));
|
||||||
|
expect(renderObject.size, equals(const Size.square(48.0)));
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('Icon sizing - sizeless theme, default size', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
new Center(
|
||||||
|
child: new IconTheme(
|
||||||
|
data: new IconThemeData(),
|
||||||
|
child: new Icon()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
RenderBox renderObject = tester.renderObject(find.byType(Icon));
|
||||||
|
expect(renderObject.size, equals(const Size.square(24.0)));
|
||||||
|
});
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user