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.clickable
20 import androidx.compose.foundation.interaction.Interaction
21 import androidx.compose.foundation.interaction.MutableInteractionSource
22 import androidx.compose.foundation.layout.Box
23 import androidx.compose.foundation.selection.toggleable
24 import androidx.compose.runtime.Composable
25 import androidx.compose.runtime.CompositionLocalProvider
26 import androidx.compose.ui.Alignment
27 import androidx.compose.ui.Modifier
28 import androidx.compose.ui.semantics.Role
29 import androidx.compose.ui.unit.dp
30 
31 /**
32  * IconButton is a clickable icon, used to represent actions. An IconButton has an overall minimum
33  * touch target size of 48 x 48dp, to meet accessibility guidelines. [content] is centered inside
34  * the IconButton.
35  *
36  * This component is typically used inside an App Bar for the navigation icon / actions. See App Bar
37  * documentation for samples of this.
38  *
39  * [content] should typically be an [Icon], using an icon from
40  * [androidx.compose.material.icons.Icons]. If using a custom icon, note that the typical size for
41  * the internal icon is 24 x 24 dp.
42  *
43  * @sample androidx.compose.material.samples.IconButtonSample
44  * @param onClick the lambda to be invoked when this icon is pressed
45  * @param modifier optional [Modifier] for this IconButton
46  * @param enabled whether or not this IconButton will handle input events and appear enabled for
47  *   semantics purposes
48  * @param interactionSource an optional hoisted [MutableInteractionSource] for observing and
49  *   emitting [Interaction]s for this IconButton. You can use this to change the IconButton's
50  *   appearance or preview the IconButton in different states. Note that if `null` is provided,
51  *   interactions will still happen internally.
52  * @param content the content (icon) to be drawn inside the IconButton. This is typically an [Icon].
53  */
54 @Composable
IconButtonnull55 fun IconButton(
56     onClick: () -> Unit,
57     modifier: Modifier = Modifier,
58     enabled: Boolean = true,
59     interactionSource: MutableInteractionSource? = null,
60     content: @Composable () -> Unit
61 ) {
62     Box(
63         modifier =
64             modifier
65                 .minimumInteractiveComponentSize()
66                 .clickable(
67                     onClick = onClick,
68                     enabled = enabled,
69                     role = Role.Button,
70                     interactionSource = interactionSource,
71                     indication = ripple(bounded = false, radius = RippleRadius)
72                 ),
73         contentAlignment = Alignment.Center
74     ) {
75         val contentAlpha = if (enabled) LocalContentAlpha.current else ContentAlpha.disabled
76         CompositionLocalProvider(LocalContentAlpha provides contentAlpha, content = content)
77     }
78 }
79 
80 /**
81  * An [IconButton] with two states, for icons that can be toggled 'on' and 'off', such as a bookmark
82  * icon, or a navigation icon that opens a drawer.
83  *
84  * @sample androidx.compose.material.samples.IconToggleButtonSample
85  * @param checked whether this IconToggleButton is currently checked
86  * @param onCheckedChange callback to be invoked when this icon is selected
87  * @param modifier optional [Modifier] for this IconToggleButton
88  * @param enabled enabled whether or not this [IconToggleButton] will handle input events and appear
89  *   enabled for semantics purposes
90  * @param interactionSource an optional hoisted [MutableInteractionSource] for observing and
91  *   emitting [Interaction]s for this IconButton. You can use this to change the IconButton's
92  *   appearance or preview the IconButton in different states. Note that if `null` is provided,
93  *   interactions will still happen internally.
94  * @param content the content (icon) to be drawn inside the IconToggleButton. This is typically an
95  *   [Icon].
96  */
97 @Composable
IconToggleButtonnull98 fun IconToggleButton(
99     checked: Boolean,
100     onCheckedChange: (Boolean) -> Unit,
101     modifier: Modifier = Modifier,
102     enabled: Boolean = true,
103     interactionSource: MutableInteractionSource? = null,
104     content: @Composable () -> Unit
105 ) {
106     Box(
107         modifier =
108             modifier
109                 .minimumInteractiveComponentSize()
110                 .toggleable(
111                     value = checked,
112                     onValueChange = onCheckedChange,
113                     enabled = enabled,
114                     role = Role.Checkbox,
115                     interactionSource = interactionSource,
116                     indication = ripple(bounded = false, radius = RippleRadius)
117                 ),
118         contentAlignment = Alignment.Center
119     ) {
120         val contentAlpha = if (enabled) LocalContentAlpha.current else ContentAlpha.disabled
121         CompositionLocalProvider(LocalContentAlpha provides contentAlpha, content = content)
122     }
123 }
124 
125 // Default radius of an unbounded ripple in an IconButton
126 private val RippleRadius = 24.dp
127