How to use Animated vector drawable in Compose - android

I created my vector drawable animation and I want to use in in Compose. I found in official documentation that I need to call animatedVectorResource. But whole AnimatedImageVector has been removed from compose till next versions. How to launch animated drawable in current compose version?

You need to update compose to 1.1.0-alpha01 and add the module androidx.compose.animation:animation-graphics as indicated in the last changelog
implementation("androidx.compose.animation:animation-graphics:1.1.0-alpha01")
val image = animatedVectorResource(id = R.drawable.animated_vector)
val atEnd by remember { mutableStateOf(false) }
Icon(
painter = image.painterFor(atEnd = atEnd),
contentDescription = null
)

AnimatedImageVector was temporarily removed in 1.0.0-rc01 and it is not present in the final stable 1.0.0.
Starting from 1.1.0-alpha01 AnimatedImageVector and the related APIs are now in the new
androidx.compose.animation:animation-graphics module.
You can use something like:
val image = animatedVectorResource(drawableId)
var atEnd by remember { mutableStateOf(false) }
Image(
painter = image.painterFor(atEnd),
contentDescription = "Your content description",
modifier = Modifier.size(64.dp).clickable {
atEnd = !atEnd
}
)

Related

TabRow/Tab Recomposition Issue in Compose Accompanist Pager

I was trying to create a sample Tab View in Jetpack compose, so the structure will be like
Inside a Parent TabRow we are iterating the tab title and create Tab composable.
More precise code will be like this.
#OptIn(ExperimentalPagerApi::class)
#Composable
private fun MainApp() {
Scaffold(
topBar = {
TopAppBar(
title = { Text(stringResource(R.string.app_name)) },
backgroundColor = MaterialTheme.colors.surface
)
},
modifier = Modifier.fillMaxSize()
) { padding ->
Column(Modifier.fillMaxSize().padding(padding)) {
val pagerState = rememberPagerState()
val coroutineScope = rememberCoroutineScope()
val tabContents = listOf(
"Home" to Icons.Filled.Home,
"Search" to Icons.Filled.Search,
"Settings" to Icons.Filled.Settings
)
HorizontalPager(
count = tabContents.size,
state = pagerState,
contentPadding = PaddingValues(horizontal = 32.dp),
modifier = Modifier
.weight(1f)
.fillMaxWidth()
) { page ->
PagerSampleItem(
page = page
)
}
TabRow(
selectedTabIndex = pagerState.currentPage,
backgroundColor = MaterialTheme.colors.surface,
contentColor = MaterialTheme.colors.onSurface,
indicator = { tabPositions ->
TabRowDefaults.Indicator(
Modifier
.pagerTabIndicatorOffset(pagerState, tabPositions)
.height(4.dp)
.background(
color = Color.Green,
shape = RectangleShape
)
)
}
) {
tabContents.forEachIndexed { index, pair: Pair<String, ImageVector> ->
Tab(
selected = pagerState.currentPage == index,
selectedContentColor = Color.Green,
unselectedContentColor = Color.Gray,
onClick = {
coroutineScope.launch {
pagerState.animateScrollToPage(index)
}
},
text = { Text(text = pair.first) },
icon = { Icon(imageVector = pair.second, contentDescription = null) }
)
}
}
}
}
}
#Composable
internal fun PagerSampleItem(
page: Int
) {
// Displays the page index
Text(
text = page.toString(),
modifier = Modifier
.padding(16.dp)
.background(MaterialTheme.colors.surface, RoundedCornerShape(4.dp))
.sizeIn(minWidth = 40.dp, minHeight = 40.dp)
.padding(8.dp)
.wrapContentSize(Alignment.Center)
)
}
And coming to my question is whenever we click on the tab item, the inner content get recompose so weirdly. Im not able to understand why it is happens.
Am attaching an image of the recomposition counts below, please take a look that too, it would be good if you guys can help me more for understand this, also for future developers.
There are two question we have to resolve in this stage
Whether it will create any performance issue, when the view getting more complex
How to resolve this recompostion issue
Thanks alot.
… whenever we click on the tab item, the
inner content get recompose so weirdly. Im not able to understand why
it is happens...
It's hard to determine what this "weirdness" is, there could be something inside the composable your'e mentioning here.
You also didn't specify what the API is, so I copied and pasted your code and integrated accompanist view pager, then I was able to run it though not on an Android Studio with a re-composition count feature.
And since your'e only concerned about the Text and the Icon parameter of the API, I think that's something out of your control. I suspect the reason why your'e getting those number of re-composition count is because your'e animating the page switching.
coroutineScope.launch {
pagerState.animateScrollToPage(index)
}
Though 'm not able to try this on another Android Studio version with the re-composition feature, I think (though I'm not sure) scrolling to another page without animation will yield less re-composition count.
coroutineScope.launch {
pagerState.scrollToPage(index)
}
If it still bothers you, the best course of action is to ask them directly, though personally I wouldn't concerned much about this as they are part of an accepted API and its just Text and Icon being re-composed many times by an animation which is also fine IMO.
Now if you have some concerns about your PagerSampleItem stability(which you have a full control), based on the provided code and screenshot, I think your'e fine.
There's actually a feature suggested from this article to check the stability of a composable, I run it and I got this report.
restartable skippable scheme("[androidx.compose.ui.UiComposable]") fun PagerSampleItem(
stable page: Int
)
Everything about this report is within the article I linked.
Also, your Text and Icon are using String and ImageVector which is stable and immutable (marked by #Immutable) respectively.
So TLDR, IMO your code is fine, your PagerSampleItem is not re-composing in the screenshot.

CenterAlignedTopAppBar scrollBehavior: No value passed for parameter 'state'

I saw that a new parameter has recently been added to the Material3 Top App Bar Composables on Jetpack Compose:
fun CenterAlignedTopAppBar(
...
scrollBehavior: TopAppBarScrollBehavior? = null
) {}
What I understood from the documentation is that this should enable us to implement the behaviour that the app bar hides at scrolling the content. However, I did not manage to implement this, as the only example I found on StackOverflow seems to no longer work on the latest version of Jetpack Compose and is giving the error No value passed for parameter 'state'.
Can anybody provide an example? What I want to achieve is a Scaffold, where as topBar a CenterAlignedTopAppBar is provided, that scrolls out on top of the screen if the scrollable content of the Scaffold is scrolled.
Thanks a lot for your help.
I finally managed to get it to work:
val topAppBarScrollState: TopAppBarScrollState = rememberTopAppBarScrollState()
val scrollBehavior = remember { TopAppBarDefaults.enterAlwaysScrollBehavior(topAppBarScrollState) }
CenterAlignedTopAppBar(
modifier = modifier,
title = { Text(text = stringResource(id = titleResource)) },
actions = {
IconButton(
onClick = { }
) {
Icon(
imageVector = Icons.Filled.Settings,
contentDescription = null,
)
}
},
scrollBehavior = scrollBehavior
)
This only seems to be necessary since Compose version 1.2.0-rc02 though, as on older versions the solution in the post linked in my answer still works.

How to implement animated vector drawable with Jetpack Compose

compose.animation:animation-graphics API will certainly be removed and so I want to know what is the best way to use animated vector drawable with JetPack Compose?
Here is the ancient code of using the API:
val image = animatedVectorResource(drawableId)
var atEnd by remember { mutableStateOf(false) }
Image(
painter = image.painterFor(atEnd),
contentDescription = "Your content description",
modifier = Modifier.size(64.dp).clickable {
atEnd = !atEnd
}
)
From android docs:
Note: This API is transient and will be likely removed for encouraging async resource loading.

How to use `ImageRequest.Builder.target` in the new coil version in jetpack compose?

My Gradle
// Coil
implementation "io.coil-kt:coil-compose:1.4.0"
Problem Description
Previously I used the coil together with Google's accompanist, but when I migrate to the new version of the coil as the documentation suggests I'm having problems with the target method:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.pokedex, PID: 13502
java.lang.IllegalArgumentException: request.target must be null.
at coil.compose.ImagePainterKt.rememberImagePainter(ImagePainter.kt:94)
...
Coil Implementation
When browsing the internal code of ImagePainter (coil class) you can see that the target method really needs to be null for some reason:
#Composable
fun rememberImagePainter(
request: ImageRequest,
imageLoader: ImageLoader,
onExecute: ExecuteCallback = ExecuteCallback.Default,
): ImagePainter {
requireSupportedData(request.data)
require(request.target == null) { "request.target must be null." }
...
My Code
Here's my component in jetpack compose (the image component is inside a column):
Image(
modifier = Modifier
.size(120.dp)
.align(Alignment.CenterHorizontally),
painter = rememberImagePainter(
data = entry.imageUrl,
builder = {
crossfade(true)
target {
viewModel.calcDominantColor(it) { color ->
dominantColor = color
}
}
transformations(CircleCropTransformation())
},
),
contentDescription = entry.pokemonName
)
I need the target method to do internal operations on my viewModel based on the drawable it passes as a parameter. Can someone help me?
In Coil 2.0.0 both AsyncImage and rememberAsyncImagePainter have onSuccess callback parameter, using which you can get the drawable as follows:
AsyncImage(
model = imageURL,
contentDescription = null,
onSuccess = { success ->
val drawable = success.result.drawable
}
)
Coil 1.4.0 version:
This is intended behaviour since rememberImagePainter sets the target internally.
You can track the painter state, wait for the Success and get the drawable from it. Also use it with LaunchedEffect to prevent re-calculations:
val painter = rememberImagePainter(
data = imageUrl,
builder = {
...
},
)
(painter.state as? ImagePainter.State.Success)
?.let { successState ->
LaunchedEffect(Unit) {
val drawable = successState.result.drawable
viewModel.calcDominantColor(drawable) { color ->
dominantColor = color
}
}
}
Image(
painter = painter,
contentDescription = "...",
modifier = Modifier
...
)
I know you follow this https://www.youtube.com/watch?v=jrIfGAk8PyQ&list=PLQkwcJG4YTCTimTCpEL5FZgaWdIZQuB7m&index=5
by Philipp Lackner
try this code
AsyncImage(
model = ImageRequest.Builder(LocalContext.current)
.data(entry.imageUrl)
.crossfade(true)
.build(),
contentDescription = entry.pokemonName,
onSuccess = {
viewModel.calcDominantColor(it.result.drawable) { color ->
dominantColor = color
}
},
modifier = Modifier
.size(120.dp)
.align(CenterHorizontally)
)
and use this library implementation("io.coil-kt:coil-compose:2.2.2")
and to more information https://coil-kt.github.io/coil/compose/

AnimatedImageVector missing in Jetpack Compose RC01

AnimatedImageVector is no more present in Jetpack Compose 1.0.0-rc01
Also function animatedVectorResource is missing.
How to replace them?
As you can read in the release notes:
AnimatedImageVector was temporarily removed in order to change the module structure
UPDATE:
Starting from 1.1.0-alpha01, "AnimatedImageVector and the related APIs are now in the new
androidx.compose.animation:animation-graphics module. More detail in this commit.
val image = animatedVectorResource(drawableId)
var atEnd by remember { mutableStateOf(false) }
Image(
painter = image.painterFor(atEnd),
contentDescription = "Your content description",
modifier = Modifier.size(64.dp).clickable {
atEnd = !atEnd
}
)

Categories

Resources