I am using animateDpAsState animation, but there is an issue with performance. The animation is very laggy, lot of frames are dropped. When I build application with release mode, animation is running more smoothly, but it is not as good as it needs to be.
Strange thing is that when I play animation several times (for example 15 times), animation is then very smooth and everything is ok.
What could be a problem?
My code:
val contextMenuAnimation = animateDpAsState(
targetValue =
if (contextMenuOpened.value) -contextMenuWidth
else 0.dp,
animationSpec = tween()
)
.
.
.
Box(
modifier = Modifier
.offset(x = maxWidth + contextMenuAnimation.value)
.size(contextMenuWidth, height = maxHeight)
) {
SidePanel()
}
One improvement you can have over your current setup is using Modifier.offset{IntOffset} over Modifier.offset(). Jetpack Compose has three phases Composition, Layout and Draw if you use Modifiers with lambda you can skip or defer reads as you can see in official document. Using Modifiers with lambdas are advised with animations.
https://stackoverflow.com/a/73274631/5457853
You can also check out scoped or smart recomposition to limit recomposition amount to Composable scopes.
Jetpack Compose Smart Recomposition
And you still in need to improve performance that you think might happen due to recompositions you can check out these articles about stability/immutability
https://chris.banes.dev/posts/composable-metrics/
https://medium.com/androiddevelopers/jetpack-compose-stability-explained-79c10db270c8
Related
I want to implement Spring animation using MotionLayout.
Also, I want to give stiffness and damping as custom values.
By the way, I saw examples where you need to use the OnSwipe tag to use Spring animation in MotionLayout.
What I want is for animation to work without user's touch.
Is there any way?
It is a little unclear what you mean by spring animation.
If you want the progress to move in the form of a Spring.
So typically you do:
progress.animateTo(
1f,
animationSpec = tween(800)
)
MotionLayout(
...
progress = progress.value
)
This can be changed to
val progress by animateFloatAsState(
targetValue = 1f,
animationSpec = spring(
dampingRatio = Spring.DampingRatioHighBouncy,
stiffness = Spring.StiffnessMedium
)
)
MotionLayout(
...
progress = progress.value
)
You can achieve spring like effects inside of MotionLayout by creating custom interpolation curves.
I am using jetpack compose and I have a picture that i want to zoom and pan. The suggested solution in the answer of this (Android Jetpack Compose: how to zoom a image in a "box"?) thread works in general, however zooming out is not detected when both fingers are placed in a vertical or diagonal line. More concretely the lambda of detectTransformestures is not called in that case:
Image(
modifier = Modifier
.pointerInput(Unit) {
detectTransformGestures(panZoomLock = true) { _, pan, zoom, _ ->
//not called for vertical zoom-in
}
},
bitmap = bitmap,
contentDescription = null,
contentScale = ContentScale.Crop
)
Weirdly enough it is called when the entire gesture is started with a zoom-in, that works as expected also with a vertical zoom. However, when trying to start a gesture by zooming out nothing happens. Is this intentional? It feels very weird and unexpected...
What are widthDp and heightDp as a #Preview parameter?
【My environment】
Android Studio Arctic Fox | 2020.3.1 Patch3 build on October 1, 2021
Gradle: 7.0.2
AGP: 7.0.3
androidx.compose.ui:ui-tooling-preview:1.0.1
Here is my code.
#Preview(
showBackground = true,
widthDp = 200,
heightDp = 200,
)
#Composable
fun DefaultPreview() {
Box(modifier = Modifier.size(100.dp).background(Color.Red))
}
And preview shows below.
But I expected below.
It seems that the box size is larger than I expected.
Does anyone explain that?
This is somehow a bug with #Preview, the first composables take the hole space they have, can't explain why. Even without the two parameters widthDp = 200, heightDp = 300, The first Box takes all the space. So for now to get the result you want you have to put a box around which "protects" the main composables.
From Preview.kt codebase,
#param widthDp Max width in DP the annotated #[Composable] will be
rendered in. Use this to restrict the size of the rendering
viewport.
#param heightDp Max height in DP the annotated
#[Composable] will be rendered in. Use this to restrict the size of
the rendering viewport.
The parameters are to restrict the maximum rendering viewport.
It seems they scale the composable if the given dimensions are large/smaller than the actual dimensions of the composable.
Can I stack multiple canvases in a column? In the example below, each DeviceView has a canvas inside.
Column() {
DeviceView(PVSUM)
DeviceView(PVSUM)
}
Asking, because it doesn't seem to work. Only one canvas is shown.
Also tried to draw each with a different offset.
Column() {
DeviceView(x1,y1, PVSUM)
DeviceView(x2,y2, PVSUM)
}
But only the first DeviceView is shown.
I'm trying to create a completely transparent material for a cube renderable created with ShapeFactory. I use this cube renderable as a large rectangular surface to make an infinite floor, and need it to be completely transparent.
I tried using MaterialFactory's makeTransparentWithColor() with an alpha of 0.0 in order to achieve that. However, the cube does not become invisible, even though it is a little bit transparent. Below is the code I use:
MaterialFactory.makeTransparentWithColor(context, Color(0f, 0f, 255f, 0f)).thenAccept { material ->
val size = Vector3(100f,0.001f,100f)
val center = Vector3(0f,0f,0f)
val floorRenderable = ShapeFactory.makeCube(size,center,material)
floorRenderable.isShadowCaster = false
floorRenderable.isShadowReceiver = false
floorAnchorNode.renderable = floorRenderable
}
Any idea how to make an invisible material for the ShapeFactory cube? I saw this Github issue which might indicate I could somehow create a dummy-renderable containing a custom material with an unlit shading model, and then get that renderables material to apply in the makeCube()? Surely there must be a better way, similar to ARKit/SceneKit's SCNNode opacity. Please, if you know anything about this I appreciate any help I can get.
It can't be fully transparent simply because of lighting and material used here.
If you need to make something invisible, don't set any renderable. And if you simply want to intercept touch, use collision instead :
floorAnchorNode.collisionShape = Box(size, center)