Could someone help clarify this statement in the d...
# compose
c
Could someone help clarify this statement in the docs, re:
centroid
https://developer.android.com/reference/kotlin/androidx/compose/foundation/gestures/package-summary#(androidx.compose.ui.i[…]olean,kotlin.Function4)
onGesture
will also provide centroid of all the pointers that are down.
Are the centroid coordinates relative to the display? The window? Something else?
Thanks!
k
There's a code example right there showing how
centroid
is used
c
To be more specific, I’m trying to figure out how to incorporate
centroid
into
transformOrigin
(which that example doesn’t do)
And I’m wondering how to interpret the
centroid
coordinates
I have run that example code and observed the behaviour. It’s not quite what I’m looking for. Notably the
graphicsLayer
is placed after
pointerInput
, meaning the entire screen accepts input, not just the transformed area.
I’ll admit I don’t quite understand the example. It uses
transformOrigin
at (0,0), but rotation occurs about the
centroid
Ok it took me a bit of thinking but I reworked the example to do what I want
Copy code
var offset by remember { mutableStateOf(Offset.Zero) }
var zoom by remember { mutableStateOf(1f) }
var angle by remember { mutableStateOf(0f) }

Box(
  Modifier
    .graphicsLayer {
      val rotatedOffset = offset.rotateBy(angle)
      translationX = -rotatedOffset.x
      translationY = -rotatedOffset.y
      scaleX = zoom
      scaleY = zoom
      rotationZ = angle
      transformOrigin = TransformOrigin(0f, 0f)
    }
    .pointerInput(Unit) {
      detectTransformGestures(
        onGesture = { centroid, pan, gestureZoom, gestureRotate ->
          val oldScale = zoom
          val newScale = zoom * gestureZoom
          angle += gestureRotate
          zoom = newScale
          offset = (offset - centroid * oldScale).rotateBy(-gestureRotate) +
              (centroid * newScale - pan * oldScale)
        }
      )
    }
    .background(Color.Yellow)
    .fillMaxSize()
)
🎉 1
a
Nice, glad you were able to figure it out! Agreed that this type of thing is really hard to visualize with how the different coordinate spaces interact
c
One thing that I observe: although the behaviour is what I want, when using
pointerInput
after
graphicsLayer
, the
centroid
doesn’t update, its position remains fixed to the position it was in when touch slop first occurred. Any idea if that is expected behaviour? Or should I file a bug
a
I’m curious how you’re using
exampleCentroid
(I only see that set, not read anywhere). Is that related?
c
Oops, sorry that is leftover from some testing, it was used to show the centroid in UI
Forgot to remove it before posting the code
(I’ve removed it now)
c
But I added logging:
Copy code
onGesture = { centroid, pan, gestureZoom, gestureRotate ->
  Log.d("onGesture", "centroid=$centroid")
...
You can see the output:
Copy code
onGesture  D  centroid=Offset(612.1, 1684.4)
onGesture  D  centroid=Offset(612.0, 1684.4)
onGesture  D  centroid=Offset(612.0, 1684.4)
onGesture  D  centroid=Offset(612.0, 1684.4)
onGesture  D  centroid=Offset(612.0, 1684.4)
... (goes on like this until pointers are released)
k
Looks like centroid only looks at down events
c
In the original example in the docs,
centroid
is updating throughout gesturing
I tested this
a
So I think the tricky part might be describing what the
centroid
is fixed in relation to
c
So I should correct what I said: In fact I see
centroid
does update, but only very tiny increments
I didn’t even notice that, in the log I posted above.
It will update a tiny increment, then remain the same for a time.
I have filed an issue, in case this is in fact a bug: https://issuetracker.google.com/issues/233251825 Thanks for your time everyone 🙂
a
I think here’s what’s going on after trying out your version: When you’re applying the
graphicsLayer
transformation before consuming the the pointer events, the pointer events are being transformed as well when you’re consuming them in
detectTransformGestures
. So in your case, the centroid coordinates are in the yellow box’s coordinates space (as opposed to the screen wide coordinate space). Now, when you’re rotating and zooming in on the yellow box, the same part of the box remains underneath the centroid of the gesture, which makes sense: that makes it natural to interact with, because you can rotate the box anchored around a given point. So, because the same part of the box is remaining underneath the centroid, and the centroid is expressed in the box’s coordinate space, the centroid won’t be moving relative to the box (except for maybe some minor rounding errors)
c
Heh, you know now that you explain it, that seems so obvious
Thanks!! Yeah as I play with it on the phone here now, I see what you mean
a
that seems so obvious
I don’t know about you, but the interactions here still hurt my brain 😆
c
Oh yeah, it’s been hurting my brain for a couple days now 🤯
😄 1
a
Well glad you were able to get the behavior you wanted!