There're many oft-used material icons in androidx.compose.material.icons.Icons but some are missing. Just as an example there is no print icon.
...
import androidx.compose.material.Icon
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Menu // ok
import androidx.compose.material.icons.filled.Print // error, unresolved reference
#Composable
fun IconsExample() {
Icon(Icons.Filled.Menu, "menu") // ok
Icon(Icons.Filled.Print, "print") // error, unresolved reference
}
What is the simplest way to use those missing icons in an app?
There's a separate dependency material-icons-extended which contains the full list of material icons, just add it into your app's build.gradle
dependencies {
...
implementation "androidx.compose.material:material-icons-extended:$compose_version"
}
Now you can use any material icon, for example:
...
import androidx.compose.material.Icon
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Menu // ok
import androidx.compose.material.icons.filled.Print // ok
#Composable
fun IconsExample() {
Icon(Icons.Filled.Menu, "menu") // ok
Icon(Icons.Filled.Print, "print") // ok
}
A note about the artifact size: Since the artifact contains all material icons for multiple themes, it's a pretty big dependency, 18MB aar as of 1.0.0-alpha10. There's a note on maven repository that recommends not to use it directly:
This module contains all Material icons. It is a very large dependency and should not be included directly.
Сonsidering that most Android projects enable code shrinking for release builds, such a large dependency won't affect the release build size but it can affect your debug build and device upload time, though I'm not sure that the influence would be significant. Actually many of compose samples use this dependency.
If only a few additional icons are required and you decided not to use material-icons-extended artifact, the icons can be easily added into your project resources using Android Studio. You can use such resource-icons like this:
...
import com.mycompany.myproject.R
import androidx.compose.ui.res.painterResource
#Composable
fun ResourceIconExample() {
Icon(
painter = painterResource(R.drawable.ic_baseline_print_24),
contentDescription = "print"
)
}
I will add to previous comment that you can use not only painterResource but ImageVector. That way you can use the same type parameter in composable functions.
ImageBitmap vs ImageVector
val imageVector = ImageVector.vectorResource(id = R.drawable.baseline_shopping_cart_24)
Related
Currently, I am migrating one of my apps to Material Design 3 which is entirely written in Kotlin using Jetpack Compose.
While using Material Design 2, I was able to change the emphasis of the text using the code below.
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
Text(
text = "Hello, world",
style = MaterialTheme.typography.h6,
fontWeight = FontWeight.SemiBold,
)
}
However, the same code doesn't work for Material Design 3 and the text has the default emphasis. Also, I can't find the relevant function anywhere for Material Design 3. I would like to know if there is any official way to achieve the same effect.
MaterialTheme.typography.h6 is from Material 2, which means you're using Text composable from Material 2 too.
Material 3 analog of h6 is MaterialTheme.typography.headlineSmall.
Make sure you have correct imports of both Text and MaterialTheme - these should be imported from androidx.compose.material3 package. Also make sure you provide a correctly imported theme, e.g. here.
Wrong imports is the most common mistake when migrating to M3, so be patient with it.
Also note that LocalContentAlpha doesn't exists in M3, providing M2 version will have no effect on M3 views. You can compare how Text composable determines its color in M2 and in M3.
I'm not sure wether it's gonna be added later (it's alpha after all), or it's handled in some other way in M3, here's a workaround(which is not perfect for sure):
CompositionLocalProvider(LocalContentColor provides LocalContentColor.current.copy(alpha = 0.4f)) {
p.s. LocalContentColor needs to be imported from M3 too
The "Emphasis and content alpha" section in the Migrate from Material 2 to Material 3 in Compose details the API changes.
Material2:
import androidx.compose.material.ContentAlpha
import androidx.compose.material.LocalContentAlpha
// High emphasis
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.high) {
Icon(…)
}
// Medium emphasis
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
Icon(…)
}
// Disabled emphasis
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.disabled) {
Icon(…)
}
Material3:
import androidx.compose.material3.LocalContentColor
// High emphasis
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onSurface) {
Icon(…)
}
// Medium emphasis
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onSurfaceVariant) {
Icon(…)
}
// Disabled emphasis
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onSurface.copy(alpha = 0.38f)) {
Icon(…)
}
I know how to implement BottomSheet in Material 2 Jetpack Compose using BottomSheetScaffold.
But there is no BottomSheetScaffold in Material 3. Also, there is nothing in official samples about BottomSheet.
So I was able to make it work!
It seems that, as of today, BottomSheetScaffold is not available yet on Material3, this is discussed in this issue I found digging around: https://issuetracker.google.com/issues/229839039
I quote the important part from the reply of a google dev:
we aren't in a super easy spot with Swipeable. It currently has a number of critical bugs that need to be addressed first (we are working on this), which is why we are limiting the surface we are exposing for Swipeable in M3 for the time. Our plan for the coming months is to focus on this specific area and improve developer experience.
Material 3 for Jetpack Compose is still in alpha - this means we
consider components production-ready, but the API shape is flexible
while in alpha. This gives us space to iterate while getting
real-world feedback from developers, which ultimately helps improve
your experience. Copy-pasting source code for components that are not
(fully) implemented or exposed in an alpha version can be a good thing
to do in the meantime! Owning the source code while the API shape is
still flexible gives you a number of benefits like ease of updating
dependencies, even if the APIs change, and allows you to evolve your
components in your own pace.
So I just followed the advice and I copy pasted BottomSheetScaffold into my project. Of course it did not work straight away because of a few missing classes and some minor API changes. At the end I was able to make it work by pulling and hacking the following classes and adding them to my project:
BottomSheetScaffold.kt
Drawer.kt
Strings.kt
Swipeable.kt
I have created a gist with the source code if you want to try:
https://gist.github.com/Marlinski/0b043968c2f574d70ee6060aeda54882
You will have to change the import to make it work on your project as well as add the "-Xjvm-default=all" option by adding the following into your gradle file in the android{} section:
android{
...
kotlinOptions {
freeCompilerArgs += ["-Xjvm-default=all"]
// "-Xjvm-default=all" option added because of this error:
// ... Inheritance from an interface with '#JvmDefault' members is only allowed with -Xjvm-default option
// triggered by porting BottomSheetScaffold for Material3 on Swipeable.kt:844
}
}
It works very well for me, will keep this solution until it is officially supported in material3.
Hope it helps!
I got pretty similar results using a fullscreen dialog with AnimatedVisibility, here is the code if interested:
// Visibility state for the dialog which will trigger it only once when called
val transitionState = remember {
MutableTransitionState(false).apply {
targetState = true
}
}
Dialog(
onDismissRequest = {} // You can set a visibility state variable to false in here which will close the dialog when clicked outside its bounds, no reason to when full screen though,
properties = DialogProperties(
// This property makes the dialog full width of the screen
usePlatformDefaultWidth = false
)
) {
// Visibility animation, more information in android docs if needed
AnimatedVisibility(
visibleState = transitionState,
enter = slideInVertically(
initialOffsetY = { it },
animationSpec = ...
),
exit = slideOutVertically(
targetOffsetY = { it },
animationSpec = ...
)
)
) {
Box(
modifier = Modifier.fillMaxSize().background(color = ...)
) {
// Your layout
// This can be any user interraction that closes the dialog
Button(
transitionState.apply { targetState = false }
) ...
}
}
All of this is in a composable function that gets called when a UI action to open said dialog is performed, it's not ideal but it works.
Hope I was able to help!
There is already a great answer by Marlinski, but i would like to add that there is also a ModalBottomSheetLayout which also does not have any implementation for Material 3.
I created a gist for people who need it in use right now:
https://gist.github.com/Pasha831/bdedcfee01acdc96cf3ae643da64f88a
We finally have ModalBottomSheet in Material3.
var openBottomSheet by rememberSaveable { mutableStateOf(false) }
val bottomSheetState = rememberSheetState(skipHalfExpanded = true)
// Sheet content
if (openBottomSheet) {
ModalBottomSheet(
onDismissRequest = { openBottomSheet = false },
sheetState = bottomSheetState,
) {
Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) {
Button(
// Note: If you provide logic outside of onDismissRequest to remove the sheet,
// you must additionally handle intended state cleanup, if any.
onClick = {
scope.launch { bottomSheetState.hide() }.invokeOnCompletion {
if (!bottomSheetState.isVisible) {
openBottomSheet = false
}
}
}
) {
Text("Hide Bottom Sheet")
}
}
}
}
For more link here: https://developer.android.com/reference/kotlin/androidx/compose/material3/package-summary#ModalBottomSheet(kotlin.Function0,androidx.compose.ui.Modifier,androidx.compose.material3.SheetState,androidx.compose.ui.graphics.Shape,androidx.compose.ui.graphics.Color,androidx.compose.ui.graphics.Color,androidx.compose.ui.unit.Dp,androidx.compose.ui.graphics.Color,kotlin.Function0,kotlin.Function1)
I am trying to use imageResource in an Android Jetpack Compose app but I cannot find the depndency to add to my grade file.
imageResource is in the docs here:
androidx.compose.ui.res
Image(
bitmap = imageResource(id = R.drawable.background),
modifier = Modifier.fillMaxSize(),
contentScale = ContentScale.Crop
)
When I add androidx.compose.ui.res to my grade file it fails to resolve.
How do I find the dependency to add to my grade file for immageresouzrce?
No dependency, the link you posted clearly states the method is accessible though ImageBitmap.Companion.imageResource(...), so that is what it is.
Type the exact phrase and you'll be good.
Explicitly using the Companion property is not necessary, you could directly use ImageBitmap.imageResource(...) here as well.
I am following this YouTube Tutorial where they are using Modifier.preferredSize() on a box and Modifier.preferredHeight() on a Spacer Composable - all other chained Modifiers are fine.
However Android Studio is not recognizing these 2 options.
Here is the code that I am working with:
Column() {
var isBlue by remember { mutableStateOf(false) }
val color = if(isBlue) Color.Blue else Color.Green
Button(onClick = { isBlue = !isBlue }) {}
Spacer(modifier = Modifier.preferredHeight(128.dp))
Box(modifier = Modifier.preferredHeight(128.dp).background(color = color)){}
}
The Editor is high-lighting preferredHeight as unresolved.
This is the image from the IDE for perspective.
I am using compose_version = '1.0.1' and I'm on AS Arctic Fox
preferredSize was renamed to size and preferredHeight to height
If I face some old video/article with invalid api, I'm searching through compose-samples(official samples from the maintainers) commits to find place where this method was deprecated/renamed, it's the easiest way to know if it just was renamed or I need to change more logic. In this case change was on this commit
Modifier.preferredWidth/preferredHeight/preferredSize were renamed to width/height/size starting from 1.0.0-beta01
I resolved it by following the mouse over suggestion, pressing the alt+Enter to import automatically the required referenced packages
I am following the lessons for andoid and kotlin and had stacked with this error.
For AGP 4.1.x / 4.2.0-alpha16, they don't have public BaseExtension#registerTransform(...) method, the new ApplicationExtension.kt doesn't export it as well.
Though it still works with 4.0.0 and below, but in 4.1.x and above the BaseExtension has been changed to package access only.
May I know if any replacement for this API? If this is intentional, can someone explain why to do that?
Much thanks.
I sorted out by a workaround below, but I'm not gonna pick it up as the final answer... will keep it open to see if any other elegant approaches could have.
package com.android.build.gradle
import com.android.build.api.transform.Transform
import org.gradle.api.Project
/**
* Note the package name above, because `BaseExtension` has package access modifier,
* so we can just forward the method invocation by using a jump class of the same package with `BaseExtension`.
*/
class BaseExtensionExport {
fun registerTransform(project: Project, transform: Transform, vararg dependencies: Any) {
val baseExt = project.extensions.findByType(BaseExtension::class.java)
if (baseExt == null) {
project.logger.error("Could not find BaseExtension in current project \"${project.name}\"")
throw IllegalArgumentException()
}
baseExt.registerTransform(transform, dependencies)
}
}
Update: I find project.extensions.findByType(AppExtension::class.java)!!.registerTransform(...) still works.