1// Copyright 2014 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5import 'package:flutter/rendering.dart';
6
7import 'basic.dart';
8import 'framework.dart';
9import 'icon.dart';
10import 'icon_theme.dart';
11import 'icon_theme_data.dart';
12import 'image.dart';
13
14/// An icon that comes from an [ImageProvider], e.g. an [AssetImage].
15///
16/// See also:
17///
18/// * [IconButton], for interactive icons.
19/// * [IconTheme], which provides ambient configuration for icons.
20/// * [Icon], for icons based on glyphs from fonts instead of images.
21/// * [Icons], the library of Material Icons.
22class ImageIcon extends StatelessWidget {
23 /// Creates an image icon.
24 ///
25 /// The [size] and [color] default to the value given by the current [IconTheme].
26 const ImageIcon(
27 this.image, {
28 super.key,
29 this.size,
30 this.color,
31 this.semanticLabel,
32 });
33
34 /// The image to display as the icon.
35 ///
36 /// The icon can be null, in which case the widget will render as an empty
37 /// space of the specified [size].
38 final ImageProvider? image;
39
40 /// The size of the icon in logical pixels.
41 ///
42 /// Icons occupy a square with width and height equal to size.
43 ///
44 /// Defaults to the current [IconTheme] size, if any. If there is no
45 /// [IconTheme], or it does not specify an explicit size, then it defaults to
46 /// 24.0.
47 final double? size;
48
49 /// The color to use when drawing the icon.
50 ///
51 /// Defaults to the current [IconTheme] color, if any. If there is
52 /// no [IconTheme], then it defaults to not recolorizing the image.
53 ///
54 /// The image will be additionally adjusted by the opacity of the current
55 /// [IconTheme], if any.
56 final Color? color;
57
58 /// Semantic label for the icon.
59 ///
60 /// Announced in accessibility modes (e.g TalkBack/VoiceOver).
61 /// This label does not show in the UI.
62 ///
63 /// * [SemanticsProperties.label], which is set to [semanticLabel] in the
64 /// underlying [Semantics] widget.
65 final String? semanticLabel;
66
67 @override
68 Widget build(BuildContext context) {
69 final IconThemeData iconTheme = IconTheme.of(context);
70 final double? iconSize = size ?? iconTheme.size;
71
72 if (image == null) {
73 return Semantics(
74 label: semanticLabel,
75 child: SizedBox(width: iconSize, height: iconSize),
76 );
77 }
78
79 final double? iconOpacity = iconTheme.opacity;
80 Color iconColor = color ?? iconTheme.color!;
81
82 if (iconOpacity != null && iconOpacity != 1.0) {
83 iconColor = iconColor.withOpacity(iconColor.opacity * iconOpacity);
84 }
85
86 return Semantics(
87 label: semanticLabel,
88 child: Image(
89 image: image!,
90 width: iconSize,
91 height: iconSize,
92 color: iconColor,
93 fit: BoxFit.scaleDown,
94 excludeFromSemantics: true,
95 ),
96 );
97 }
98
99 @override
100 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
101 super.debugFillProperties(properties);
102 properties.add(DiagnosticsProperty<ImageProvider>('image', image, ifNull: '<empty>', showName: false));
103 properties.add(DoubleProperty('size', size, defaultValue: null));
104 properties.add(ColorProperty('color', color, defaultValue: null));
105 }
106}
107