Android Compose Zoom out gesture not detected - android

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...

Related

Issue with jetpack compose animation performance

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

Jetpack Compose detectDragGestures seems to be working only when Canvas modifier is set to fillMaxSize or matchParentSize inside a Box

I am creating a project where I have to move around Canvas elements(circles and lines) on drag gestures. I am using a Box composable to put different Canvas(s) inside it. And then with the help of pointerInput modifier I want to detect drag Gesture and hopefully achieve the behaviour I want.
Box(
modifier = Modifier
.fillMaxSize()
.padding(paddingValue),
contentAlignment = Alignment.Center
){
Canvas(modifier = Modifier
.pointerInput(Unit) {
detectDragGestures { change, dragAmount ->
change.consumeAllChanges()
centerOffSet = centerOffSet.plus(dragAmount)
}
}
) {
drawCircle(
color = Color.White,
center = centerOffSet,
radius = radiusValue
)
}
}
The problem I'm facing is that when I set the Canvas modifier to .matchParentSize() or .fillMaxSize(), I'm able to drag the circle but this makes the whole surface of the Box a touch target, which is not desired, using the .wrapContentSize() modifier is not working. Is there something I'm missing here?
Canvas is a Spacer with Modifier.drawBehind so it needs dimensions to have bounds.
#Composable
fun Canvas(modifier: Modifier, onDraw: DrawScope.() -> Unit) =
Spacer(modifier.drawBehind(onDraw))
So you need to assign a Modifier that sets its dimensions. It's not correct that it s seems to be working only when Canvas modifier is set to fillMaxSize or matchParentSize inside a Box.
You can make it work any Modifier.size(), Modifier.fillX() or Modifier.matchParentSize().
It draws even without any dimensions while its Size is Size.Zero, or outside of your Canvas dimensions if you set one. You can see its bounds when you set a border or use Modifier.clipToBounds() which clips your drawing outside its bounds with no dimension assignment you will see that nothing is being drawn. Or you can check Canvas size from DrawScope to see what's its Size is.
The problem I'm facing is that when I set the Canvas modifier to
.matchParentSize() or .fillMaxSize(), I'm able to drag the circle but
this makes the whole surface of the Box a touch target
This is expected behavior.
In you question i didn't get how you exactly want to divide Box area to Canvases but you need to assign a Size according to your needs.

Jetpack Compose: is it possible to have multiple canvases in one page?

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.

Starting WebView fit to scale, with pinch zoom

I am trying to load a url into a webview, its actually a screen share stream into a phone app.
I have a couple of issues I need help with.
WebView starts always zoomed at the top left corner
There are zoom controls and fit to scale button, and after zooming you can move around by touch, however the two finger pinch zoom does not work.
Adding the setWebViewClient as below, enables pinch zoom but gives two more problems; there are additional -+ buttons, and zooming by pinch the original -+/fit to scale buttons become zoomed as well
screenShareWebView.settings.useWideViewPort = true
screenShareWebView.settings.loadWithOverviewMode = true
screenShareWebView.settings.setSupportZoom(true)
screenShareWebView.settings.builtInZoomControls = true
screenShareWebView.settings.displayZoomControls = true
screenShareWebView.scrollBarStyle = WebView.SCROLLBARS_INSIDE_OVERLAY
screenShareWebView.isScrollbarFadingEnabled = true
screenShareWebView.settings.javaScriptEnabled = true //needs to be true or else it doesnt work
screenShareWebView.loadUrl(it)
the pinch zoom is enabled (with the extra buttons) with
screenShareWebView.setWebViewClient(object : WebViewClient() {
override fun onPageFinished(view: WebView, url: String?) {
val javascript ="javascript:document.getElementsByName('viewport'[0].setAttribute('content', 'initial-scale=1.0,maximum-scale=10.0');"
view.loadUrl(javascript)
}
})
So i need to start fit to scale, enable pinch zoom if possible and dont add extra buttons

Invisible/transparent material for ShapeFactory renderable in Sceneform and ARCore

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)

Categories

Resources