Commit cff31a3f authored by Ian Hickson's avatar Ian Hickson Committed by GitHub

IconThemeData.size (#4633)

parent 5809a0cb
......@@ -26,29 +26,34 @@ import 'theme.dart';
///
/// See also:
///
/// * [IconButton], for interactive icons
/// * [Icons], for the list of available icons for use with this class
/// * [IconButton], for interactive icons.
/// * [Icons], for the list of available icons for use with this class.
/// * [IconTheme], which provides ambient configuration for icons.
class Icon extends StatelessWidget {
/// Creates an icon.
///
/// The [size] argument most not be null.
Icon({
/// The [size] and [color] default to the value given by the current [IconTheme].
const Icon({
Key key,
this.icon,
this.size: 24.0,
this.size,
this.color
}) : super(key: key) {
assert(size != null);
}
}) : super(key: key);
/// 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.
///
/// 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;
/// The icon to display. The available icons are described in [Icons].
final IconData icon;
/// The color to use when drawing the icon.
///
/// 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
/// theme and [ThemeData.brightness] for setting the current theme's
/// brightness.
///
/// The given color will be adjusted by the opacity of the current
/// [IconTheme], if any.
final Color color;
Color _getDefaultColorForBrightness(Brightness brightness) {
......@@ -75,8 +83,10 @@ class Icon extends StatelessWidget {
@override
Widget build(BuildContext context) {
final double iconSize = size ?? IconTheme.of(context)?.size ?? 24.0;
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;
Color iconColor = color ?? _getDefaultColor(context);
......@@ -85,15 +95,15 @@ class Icon extends StatelessWidget {
return new ExcludeSemantics(
child: new SizedBox(
width: size,
height: size,
width: iconSize,
height: iconSize,
child: new Center(
child: new Text(
new String.fromCharCode(icon.codePoint),
style: new TextStyle(
inherit: false,
color: iconColor,
fontSize: size,
fontSize: iconSize,
fontFamily: 'MaterialIcons'
)
)
......@@ -105,9 +115,14 @@ class Icon extends StatelessWidget {
@override
void debugFillDescription(List<String> description) {
super.debugFillDescription(description);
description.add('$icon');
description.add('size: $size');
if (this.color != null)
if (icon != null) {
description.add('$icon');
} else {
description.add('<empty>');
}
if (size != null)
description.add('size: $size');
if (color != null)
description.add('color: $color');
}
}
......@@ -7,9 +7,10 @@ import 'package:meta/meta.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 {
/// 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.
IconTheme({
......@@ -21,7 +22,7 @@ class IconTheme extends InheritedWidget {
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;
/// 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' 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
/// subtree.
/// Used by [IconTheme] to control the color, opacity, and size of icons in a
/// widget subtree.
class IconThemeData {
/// Creates an icon theme data.
///
/// The opacity applies to both explicit and default icon colors. The value
/// 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.
final Color color;
......@@ -23,25 +23,42 @@ class IconThemeData {
double get opacity => (_opacity ?? 1.0).clamp(0.0, 1.0);
final double _opacity;
/// The default size for icons.
final double size;
/// Linearly interpolate between two icon theme data objects.
static IconThemeData lerp(IconThemeData begin, IconThemeData end, double t) {
return new IconThemeData(
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
bool operator ==(dynamic other) {
if (other is! IconThemeData)
if (other.runtimeType != runtimeType)
return false;
final IconThemeData typedOther = other;
return color == typedOther.color && opacity == typedOther.opacity;
return color == typedOther.color
&& opacity == typedOther.opacity
&& size == typedOther.size;
}
@override
int get hashCode => hashValues(color, opacity);
int get hashCode => hashValues(color, opacity, size);
@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(', ');
}
}
// 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)));
});
}
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