Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/*
* Copyright 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.example.compose.snippets.components

import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsPressedAsState
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import com.example.compose.snippets.R
import kotlinx.coroutines.delay

// [START android_compose_components_togglebuttonexample]
@Preview
@Composable
fun ToggleIconButtonExample() {
// isToggled initial value should be read from a view model or persistent storage.
var isToggled by rememberSaveable { mutableStateOf(false) }

IconButton(
onClick = { isToggled = !isToggled }
) {
Icon(
painter = if (isToggled) painterResource(R.drawable.favorite_filled) else painterResource(R.drawable.favorite),
contentDescription = if (isToggled) "Selected icon button" else "Unselected icon button."
)
}
}
// [END android_compose_components_togglebuttonexample]

// [START android_compose_components_iconbutton]
@Composable
fun MomentaryIconButton(
unselectedImage: Int,
selectedImage: Int,
contentDescription: String,
modifier: Modifier = Modifier,
stepDelay: Long = 100L, // Minimum value is 1L milliseconds.
onClick: () -> Unit
) {
val interactionSource = remember { MutableInteractionSource() }
val isPressed by interactionSource.collectIsPressedAsState()
val pressedListener by rememberUpdatedState(onClick)

LaunchedEffect(isPressed) {
while (isPressed) {
delay(stepDelay.coerceIn(1L, Long.MAX_VALUE))
pressedListener()
}
}

IconButton(
modifier = modifier,
onClick = onClick,
interactionSource = interactionSource
) {
Icon(
painter = if (isPressed) painterResource(id = selectedImage) else painterResource(id = unselectedImage),
contentDescription = contentDescription,
)
}
}
// [END android_compose_components_iconbutton]

// [START android_compose_components_momentaryiconbuttons]
@Preview()
@Composable
fun MomentaryIconButtonExample() {
var pressedCount by remember { mutableIntStateOf(0) }

Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
MomentaryIconButton(
unselectedImage = R.drawable.fast_rewind,
selectedImage = R.drawable.fast_rewind_filled,
stepDelay = 100L,
onClick = { pressedCount -= 1 },
contentDescription = "Decrease count button"
)
Spacer(modifier = Modifier)
Text("advanced by $pressedCount frames")
Spacer(modifier = Modifier)
MomentaryIconButton(
unselectedImage = R.drawable.fast_forward,
selectedImage = R.drawable.fast_forward_filled,
contentDescription = "Increase count button",
stepDelay = 100L,
onClick = { pressedCount += 1 }
)
}
}
// [END android_compose_components_momentaryiconbuttons]
9 changes: 9 additions & 0 deletions compose/snippets/src/main/res/drawable/fast_forward.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:pathData="M100,720v-480l360,240 -360,240ZM500,720v-480l360,240 -360,240ZM180,480ZM580,480ZM180,570 L316,480 180,390v180ZM580,570 L716,480 580,390v180Z"
android:fillColor="#e3e3e3"/>
</vector>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:pathData="M100,720v-480l360,240 -360,240ZM500,720v-480l360,240 -360,240Z"
android:fillColor="#e3e3e3"/>
</vector>
9 changes: 9 additions & 0 deletions compose/snippets/src/main/res/drawable/fast_rewind.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:pathData="M860,720 L500,480l360,-240v480ZM460,720L100,480l360,-240v480ZM380,480ZM780,480ZM380,570v-180l-136,90 136,90ZM780,570v-180l-136,90 136,90Z"
android:fillColor="#e3e3e3"/>
</vector>
9 changes: 9 additions & 0 deletions compose/snippets/src/main/res/drawable/fast_rewind_filled.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:pathData="M860,720 L500,480l360,-240v480ZM460,720L100,480l360,-240v480Z"
android:fillColor="#e3e3e3"/>
</vector>
9 changes: 9 additions & 0 deletions compose/snippets/src/main/res/drawable/favorite.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:pathData="m480,840 l-58,-52q-101,-91 -167,-157T150,512.5Q111,460 95.5,416T80,326q0,-94 63,-157t157,-63q52,0 99,22t81,62q34,-40 81,-62t99,-22q94,0 157,63t63,157q0,46 -15.5,90T810,512.5Q771,565 705,631T538,788l-58,52ZM480,732q96,-86 158,-147.5t98,-107q36,-45.5 50,-81t14,-70.5q0,-60 -40,-100t-100,-40q-47,0 -87,26.5T518,280h-76q-15,-41 -55,-67.5T300,186q-60,0 -100,40t-40,100q0,35 14,70.5t50,81q36,45.5 98,107T480,732ZM480,459Z"
android:fillColor="#e3e3e3"/>
</vector>
9 changes: 9 additions & 0 deletions compose/snippets/src/main/res/drawable/favorite_filled.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:pathData="m480,840 l-58,-52q-101,-91 -167,-157T150,512.5Q111,460 95.5,416T80,326q0,-94 63,-157t157,-63q52,0 99,22t81,62q34,-40 81,-62t99,-22q94,0 157,63t63,157q0,46 -15.5,90T810,512.5Q771,565 705,631T538,788l-58,52Z"
android:fillColor="#e3e3e3"/>
</vector>