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