https://kotlinlang.org logo
#compose
Title
# compose
c

Chris Fillmore

05/19/2022, 6:33 PM
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

Kirill Grouchnikov

05/19/2022, 6:41 PM
There's a code example right there showing how
centroid
is used
c

Chris Fillmore

05/19/2022, 6:42 PM
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

Alex Vanyo

05/19/2022, 8:34 PM
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

Chris Fillmore

05/19/2022, 8:37 PM
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

Alex Vanyo

05/19/2022, 8:41 PM
I’m curious how you’re using
exampleCentroid
(I only see that set, not read anywhere). Is that related?
c

Chris Fillmore

05/19/2022, 8:41 PM
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

Chris Fillmore

05/19/2022, 8:44 PM
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

Kirill Grouchnikov

05/19/2022, 8:45 PM
Looks like centroid only looks at down events
c

Chris Fillmore

05/19/2022, 8:45 PM
In the original example in the docs,
centroid
is updating throughout gesturing
I tested this
a

Alex Vanyo

05/19/2022, 8:48 PM
So I think the tricky part might be describing what the
centroid
is fixed in relation to
c

Chris Fillmore

05/19/2022, 8:52 PM
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

Alex Vanyo

05/19/2022, 9:25 PM
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

Chris Fillmore

05/19/2022, 9:28 PM
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

Alex Vanyo

05/19/2022, 9:31 PM
that seems so obvious
I don’t know about you, but the interactions here still hurt my brain 😆
c

Chris Fillmore

05/19/2022, 9:32 PM
Oh yeah, it’s been hurting my brain for a couple days now 🤯
😄 1
a

Alex Vanyo

05/19/2022, 10:16 PM
Well glad you were able to get the behavior you wanted!
9 Views