1 /*
2 * Copyright 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package androidx.compose.material
18
19 import androidx.compose.foundation.layout.Box
20 import androidx.compose.foundation.layout.size
21 import androidx.compose.runtime.Composable
22 import androidx.compose.runtime.NonRestartableComposable
23 import androidx.compose.runtime.remember
24 import androidx.compose.ui.Modifier
25 import androidx.compose.ui.draw.paint
26 import androidx.compose.ui.geometry.Size
27 import androidx.compose.ui.graphics.Color
28 import androidx.compose.ui.graphics.ColorFilter
29 import androidx.compose.ui.graphics.ImageBitmap
30 import androidx.compose.ui.graphics.painter.BitmapPainter
31 import androidx.compose.ui.graphics.painter.Painter
32 import androidx.compose.ui.graphics.toolingGraphicsLayer
33 import androidx.compose.ui.graphics.vector.ImageVector
34 import androidx.compose.ui.graphics.vector.rememberVectorPainter
35 import androidx.compose.ui.layout.ContentScale
36 import androidx.compose.ui.semantics.Role
37 import androidx.compose.ui.semantics.contentDescription
38 import androidx.compose.ui.semantics.role
39 import androidx.compose.ui.semantics.semantics
40 import androidx.compose.ui.unit.dp
41
42 /**
43 * A Material Design icon component that draws [imageVector] using [tint], with a default value of
44 * [LocalContentColor]. If [imageVector] has no intrinsic size, this component will use the
45 * recommended default size. Icon is an opinionated component designed to be used with single-color
46 * icons so that they can be tinted correctly for the component they are placed in. For multicolored
47 * icons and icons that should not be tinted, use [Color.Unspecified] for [tint]. For generic images
48 * that should not be tinted, and do not follow the recommended icon size, use the generic
49 * [androidx.compose.foundation.Image] instead. For a clickable icon, see [IconButton].
50 *
51 * @param imageVector [ImageVector] to draw inside this Icon
52 * @param contentDescription text used by accessibility services to describe what this icon
53 * represents. This should always be provided unless this icon is used for decorative purposes,
54 * and does not represent a meaningful action that a user can take. This text should be localized,
55 * such as by using [androidx.compose.ui.res.stringResource] or similar
56 * @param modifier optional [Modifier] for this Icon
57 * @param tint tint to be applied to [imageVector]. If [Color.Unspecified] is provided, then no tint
58 * is applied
59 */
60 @Composable
61 @NonRestartableComposable
Iconnull62 fun Icon(
63 imageVector: ImageVector,
64 contentDescription: String?,
65 modifier: Modifier = Modifier,
66 tint: Color = LocalContentColor.current.copy(alpha = LocalContentAlpha.current)
67 ) {
68 Icon(
69 painter = rememberVectorPainter(imageVector),
70 contentDescription = contentDescription,
71 modifier = modifier,
72 tint = tint
73 )
74 }
75
76 /**
77 * A Material Design icon component that draws [bitmap] using [tint], with a default value of
78 * [LocalContentColor]. If [bitmap] has no intrinsic size, this component will use the recommended
79 * default size. Icon is an opinionated component designed to be used with single-color icons so
80 * that they can be tinted correctly for the component they are placed in. For multicolored icons
81 * and icons that should not be tinted, use [Color.Unspecified] for [tint]. For generic images that
82 * should not be tinted, and do not follow the recommended icon size, use the generic
83 * [androidx.compose.foundation.Image] instead. For a clickable icon, see [IconButton].
84 *
85 * @param bitmap [ImageBitmap] to draw inside this Icon
86 * @param contentDescription text used by accessibility services to describe what this icon
87 * represents. This should always be provided unless this icon is used for decorative purposes,
88 * and does not represent a meaningful action that a user can take. This text should be localized,
89 * such as by using [androidx.compose.ui.res.stringResource] or similar
90 * @param modifier optional [Modifier] for this Icon
91 * @param tint tint to be applied to [bitmap]. If [Color.Unspecified] is provided, then no tint is
92 * applied
93 */
94 @Composable
95 @NonRestartableComposable
Iconnull96 fun Icon(
97 bitmap: ImageBitmap,
98 contentDescription: String?,
99 modifier: Modifier = Modifier,
100 tint: Color = LocalContentColor.current.copy(alpha = LocalContentAlpha.current)
101 ) {
102 val painter = remember(bitmap) { BitmapPainter(bitmap) }
103 Icon(
104 painter = painter,
105 contentDescription = contentDescription,
106 modifier = modifier,
107 tint = tint
108 )
109 }
110
111 /**
112 * A Material Design icon component that draws [painter] using [tint], with a default value of
113 * [LocalContentColor]. If [painter] has no intrinsic size, this component will use the recommended
114 * default size. Icon is an opinionated component designed to be used with single-color icons so
115 * that they can be tinted correctly for the component they are placed in. For multicolored icons
116 * and icons that should not be tinted, use [Color.Unspecified] for [tint]. For generic images that
117 * should not be tinted, and do not follow the recommended icon size, use the generic
118 * [androidx.compose.foundation.Image] instead. For a clickable icon, see [IconButton].
119 *
120 * @param painter [Painter] to draw inside this Icon
121 * @param contentDescription text used by accessibility services to describe what this icon
122 * represents. This should always be provided unless this icon is used for decorative purposes,
123 * and does not represent a meaningful action that a user can take. This text should be localized,
124 * such as by using [androidx.compose.ui.res.stringResource] or similar
125 * @param modifier optional [Modifier] for this Icon
126 * @param tint tint to be applied to [painter]. If [Color.Unspecified] is provided, then no tint is
127 * applied
128 */
129 @Composable
Iconnull130 fun Icon(
131 painter: Painter,
132 contentDescription: String?,
133 modifier: Modifier = Modifier,
134 tint: Color = LocalContentColor.current.copy(alpha = LocalContentAlpha.current)
135 ) {
136 val colorFilter =
137 remember(tint) { if (tint == Color.Unspecified) null else ColorFilter.tint(tint) }
138 val semantics =
139 if (contentDescription != null) {
140 Modifier.semantics {
141 this.contentDescription = contentDescription
142 this.role = Role.Image
143 }
144 } else {
145 Modifier
146 }
147 Box(
148 modifier
149 .toolingGraphicsLayer()
150 .defaultSizeFor(painter)
151 .paint(painter, colorFilter = colorFilter, contentScale = ContentScale.Fit)
152 .then(semantics)
153 )
154 }
155
defaultSizeFornull156 private fun Modifier.defaultSizeFor(painter: Painter) =
157 this.then(
158 if (painter.intrinsicSize == Size.Unspecified || painter.intrinsicSize.isInfinite()) {
159 DefaultIconSizeModifier
160 } else {
161 Modifier
162 }
163 )
164
isInfinitenull165 private fun Size.isInfinite() = width.isInfinite() && height.isInfinite()
166
167 // Default icon size, for icons with no intrinsic size information
168 private val DefaultIconSizeModifier = Modifier.size(24.dp)
169