# PointerEvent

Artifact: [androidx.compose.ui:ui](https://developer.android.com/jetpack/androidx/releases/compose-ui) [View Source](https://cs.android.com/search?q=file:androidx/compose/ui/input/pointer/PointerEvent.+class:androidx.compose.ui.input.pointer.PointerEvent) Added in [1.0.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.0.0) Common/AllAndroid/JVM
- Cmn

  ```
  class PointerEvent
  ```

*** ** * ** ***

Describes a pointer input change event that has occurred at a particular point in time.

## Summary

| ### Public constructors |
|---|---|
| `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerEvent#PointerEvent(kotlin.collections.List)(changes: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/-list/index.html<https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerInputChange>)` | Cmn android |

| ### Public functions |
|---|---|---|
| `https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/-list/index.html<https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerInputChange>` | `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerEvent#component1()()` | android |
| `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerEvent` | `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerEvent#copy(kotlin.collections.List,android.view.MotionEvent)(changes: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/-list/index.html<https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerInputChange>, motionEvent: https://developer.android.com/reference/android/view/MotionEvent.html?)` | android |

| ### Public properties |
|---|---|---|
| `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerButtons` | `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerEvent#buttons()` The state of buttons (e.g. mouse or stylus buttons) during this event. | Cmn android |
| `https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/-list/index.html<https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerInputChange>` | `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerEvent#changes()` The changes. | Cmn android |
| `https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-int/index.html` | `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerEvent#classification()` Returns [`MotionEvent`'s classification](https://developer.android.com/reference/android/view/MotionEvent#getClassification()). | android |
| `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerKeyboardModifiers` | `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerEvent#keyboardModifiers()` The state of modifier keys during this event. | Cmn android |
| `https://developer.android.com/reference/android/view/MotionEvent.html?` | `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerEvent#motionEvent()` The underlying Android `https://developer.android.com/reference/android/view/MotionEvent.html` that triggered this `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerEvent`. | android |
| `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerEventType` | `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerEvent#type()` The primary reason the `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerEvent` was sent. | Cmn android |

| ### Extension functions |
|---|---|---|
| `https://developer.android.com/reference/kotlin/androidx/compose/ui/geometry/Offset` | `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerEvent.https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerEvent#(androidx.compose.ui.input.pointer.PointerEvent).calculateCentroid(kotlin.Boolean)(useCurrent: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-boolean/index.html)` Returns the centroid of all pointers that are down and were previously down. | Cmn |
| `https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-float/index.html` | `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerEvent.https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerEvent#(androidx.compose.ui.input.pointer.PointerEvent).calculateCentroidSize(kotlin.Boolean)(useCurrent: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-boolean/index.html)` Returns the average distance from the centroid for all pointers that are currently and were previously down. | Cmn |
| `https://developer.android.com/reference/kotlin/androidx/compose/ui/geometry/Offset` | `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerEvent.https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerEvent#(androidx.compose.ui.input.pointer.PointerEvent).calculatePan()()` Returns the change in the centroid location between the previous and the current pointers that are down. | Cmn |
| `https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-float/index.html` | `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerEvent.https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerEvent#(androidx.compose.ui.input.pointer.PointerEvent).calculateRotation()()` Returns the rotation, in degrees, of the pointers between the `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerInputChange#previousPosition()` and `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerInputChange#position()` states. | Cmn |
| `https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-float/index.html` | `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerEvent.https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerEvent#(androidx.compose.ui.input.pointer.PointerEvent).calculateZoom()()` Uses the change of the centroid size between the `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerInputChange#previousPosition()` and `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerInputChange#position()` to determine how much zoom was intended. | Cmn |

## Public constructors

### PointerEvent

Cmn android Added in [1.0.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.0.0)

```
PointerEvent(changes: List<PointerInputChange>)
```

| Parameters |
|---|---|
| `changes: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/-list/index.html<https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerInputChange>` | The changes. |

## Public functions

### component1

android Added in [1.0.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.0.0)

```
fun component1(): List<PointerInputChange>
```

### copy

android Added in [1.0.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.0.0)

```
fun copy(changes: List<PointerInputChange>, motionEvent: MotionEvent?): PointerEvent
```

## Public properties

### buttons

Cmn android Added in [1.1.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.1.0)

```
val buttons: PointerButtons
```

The state of buttons (e.g. mouse or stylus buttons) during this event.

### changes

Cmn android Added in [1.0.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.0.0)

```
val changes: List<PointerInputChange>
```

The changes.

### classification

android Added in [1.8.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.8.0)

```
val classification: Int
```

Returns [`MotionEvent`'s classification](https://developer.android.com/reference/android/view/MotionEvent#getClassification()).

### keyboardModifiers

Cmn android Added in [1.1.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.1.0)

```
val keyboardModifiers: PointerKeyboardModifiers
```

The state of modifier keys during this event.

### motionEvent

android Added in [1.9.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.9.0)

```
val motionEvent: MotionEvent?
```

The underlying Android `https://developer.android.com/reference/android/view/MotionEvent.html` that triggered this `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerEvent`.

This property provides access to the raw `https://developer.android.com/reference/android/view/MotionEvent.html` for retrieving platform-specific information not yet exposed by the Compose `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerEvent` API (e.g., stylus tilt angle).

**Important Considerations:**

1. **Read-Only:** The returned `https://developer.android.com/reference/android/view/MotionEvent.html` is strictly read-only. Modifying it will lead to unpredictable behavior.

2. **Transient:** Do not store a reference to this `https://developer.android.com/reference/android/view/MotionEvent.html`. The Android framework may recycle it, rendering its state undefined and causing errors if accessed later. Access the data only within the scope where the `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerEvent` is received.

3. **Metadata Only:** This `https://developer.android.com/reference/android/view/MotionEvent.html` should *not* be used for primary input handling logic (e.g., determining pointer position or button presses). Rely on the properties of `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerEvent` and `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerInputChange` for this purpose. The `https://developer.android.com/reference/android/view/MotionEvent.html` is intended solely for accessing supplemental metadata.

4. **Nullability:** This property will be `null` in two cases:

   - The `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerEvent` was fabricated within Compose (i.e., not directly from a system input event).

   - The `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerEvent` has already been dispatched within the Compose input system. (See the sample code for details).

```kotlin
import androidx.compose.foundation.gestures.awaitEachGesture
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.pointer.pointerInput

@Composable
fun MyComposable() {
    Box(
        Modifier.fillMaxSize().pointerInput(Unit) {
            awaitEachGesture {
                val pointerEvent = awaitPointerEvent()

                // Use MotionEvent only for additional metadata.
                performAction(pointerEvent.motionEvent?.getAxisValue(MotionEvent.AXIS_TILT))

                awaitPointerEvent()
                // Do NOT try to access the MotionEvent of the first pointEvent after awaits
                // another PointerEvent. The PointerEvent's MotionEvent is set to null when it
                // finishes dispatch.
                // In the following line, pointerEvent.motionEvent returns null.
                performAction(pointerEvent.motionEvent?.getAxisValue(MotionEvent.AXIS_TILT))
            }
        }
    )
}
```

### type

Cmn android Added in [1.1.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.1.0)

```
val type: PointerEventType
```

The primary reason the `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerEvent` was sent.

## Extension functions

### PointerEvent.calculateCentroid

Cmn Artifact: [androidx.compose.foundation:foundation](https://developer.android.com/jetpack/androidx/releases/compose-foundation) [View Source](https://cs.android.com/search?q=file:androidx/compose/foundation/gestures/TransformGestureDetector.kt+function:calculateCentroid)

```
fun PointerEvent.calculateCentroid(useCurrent: Boolean = true): Offset
```

Returns the centroid of all pointers that are down and were previously down. If no pointers are down, `https://developer.android.com/reference/kotlin/androidx/compose/ui/geometry/Offset#Unspecified()` is returned. If `https://developer.android.com/reference/kotlin/androidx/compose/foundation/gestures/package-summary#(androidx.compose.ui.input.pointer.PointerEvent).calculateCentroid(kotlin.Boolean)` is `true`, the centroid of the `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerInputChange#position()` is returned and if `false`, the centroid of the `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerInputChange#previousPosition()` is returned. Only pointers that are down in both the previous and current state are used to calculate the centroid.

Example Usage:

```kotlin
import androidx.compose.foundation.gestures.awaitEachGesture
import androidx.compose.foundation.gestures.awaitFirstDown
import androidx.compose.foundation.gestures.calculateCentroid
import androidx.compose.foundation.gestures.calculateCentroidSize
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.pointerInput

var centroidSize by remember { mutableStateOf(0f) }
var position by remember { mutableStateOf(Offset.Zero) }
Box(
    Modifier.drawBehind {
            // Draw a circle where the gesture is
            drawCircle(Color.Blue, centroidSize, center = position)
        }
        .pointerInput(Unit) {
            awaitEachGesture {
                awaitFirstDown().also { position = it.position }
                do {
                    val event = awaitPointerEvent()
                    val size = event.calculateCentroidSize()
                    if (size != 0f) {
                        centroidSize = event.calculateCentroidSize()
                    }
                    val centroid = event.calculateCentroid()
                    if (centroid != Offset.Unspecified) {
                        position = centroid
                    }
                } while (event.changes.any { it.pressed })
            }
        }
        .fillMaxSize()
)
```

### PointerEvent.calculateCentroidSize

Cmn Artifact: [androidx.compose.foundation:foundation](https://developer.android.com/jetpack/androidx/releases/compose-foundation) [View Source](https://cs.android.com/search?q=file:androidx/compose/foundation/gestures/TransformGestureDetector.kt+function:calculateCentroidSize)

```
fun PointerEvent.calculateCentroidSize(useCurrent: Boolean = true): Float
```

Returns the average distance from the centroid for all pointers that are currently and were previously down. If no pointers are down, `0` is returned. If `https://developer.android.com/reference/kotlin/androidx/compose/foundation/gestures/package-summary#(androidx.compose.ui.input.pointer.PointerEvent).calculateCentroidSize(kotlin.Boolean)` is `true`, the size of the `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerInputChange#position()` is returned and if `false`, the size of `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerInputChange#previousPosition()` is returned. Only pointers that are down in both the previous and current state are used to calculate the centroid size.

Example Usage:

```kotlin
import androidx.compose.foundation.gestures.awaitEachGesture
import androidx.compose.foundation.gestures.awaitFirstDown
import androidx.compose.foundation.gestures.calculateCentroid
import androidx.compose.foundation.gestures.calculateCentroidSize
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.pointerInput

var centroidSize by remember { mutableStateOf(0f) }
var position by remember { mutableStateOf(Offset.Zero) }
Box(
    Modifier.drawBehind {
            // Draw a circle where the gesture is
            drawCircle(Color.Blue, centroidSize, center = position)
        }
        .pointerInput(Unit) {
            awaitEachGesture {
                awaitFirstDown().also { position = it.position }
                do {
                    val event = awaitPointerEvent()
                    val size = event.calculateCentroidSize()
                    if (size != 0f) {
                        centroidSize = event.calculateCentroidSize()
                    }
                    val centroid = event.calculateCentroid()
                    if (centroid != Offset.Unspecified) {
                        position = centroid
                    }
                } while (event.changes.any { it.pressed })
            }
        }
        .fillMaxSize()
)
```

### PointerEvent.calculatePan

Cmn Artifact: [androidx.compose.foundation:foundation](https://developer.android.com/jetpack/androidx/releases/compose-foundation) [View Source](https://cs.android.com/search?q=file:androidx/compose/foundation/gestures/TransformGestureDetector.kt+function:calculatePan)

```
fun PointerEvent.calculatePan(): Offset
```

Returns the change in the centroid location between the previous and the current pointers that are down. Pointers that are newly down or raised are not considered in the centroid movement.

Example Usage:

```kotlin
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.awaitEachGesture
import androidx.compose.foundation.gestures.awaitFirstDown
import androidx.compose.foundation.gestures.calculatePan
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.offset
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.unit.IntOffset

val offsetX = remember { mutableStateOf(0f) }
val offsetY = remember { mutableStateOf(0f) }
Box(
    Modifier.offset { IntOffset(offsetX.value.roundToInt(), offsetY.value.roundToInt()) }
        .graphicsLayer()
        .background(Color.Blue)
        .pointerInput(Unit) {
            awaitEachGesture {
                awaitFirstDown()
                do {
                    val event = awaitPointerEvent()
                    val offset = event.calculatePan()
                    offsetX.value += offset.x
                    offsetY.value += offset.y
                } while (event.changes.any { it.pressed })
            }
        }
        .fillMaxSize()
)
```

### PointerEvent.calculateRotation

Cmn Artifact: [androidx.compose.foundation:foundation](https://developer.android.com/jetpack/androidx/releases/compose-foundation) [View Source](https://cs.android.com/search?q=file:androidx/compose/foundation/gestures/TransformGestureDetector.kt+function:calculateRotation)

```
fun PointerEvent.calculateRotation(): Float
```

Returns the rotation, in degrees, of the pointers between the `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerInputChange#previousPosition()` and `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerInputChange#position()` states. Only the pointers that are down in both previous and current states are considered.

Example Usage:

```kotlin
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.awaitEachGesture
import androidx.compose.foundation.gestures.awaitFirstDown
import androidx.compose.foundation.gestures.calculateRotation
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.pointerInput

var angle by remember { mutableStateOf(0f) }
Box(
    Modifier.graphicsLayer(rotationZ = angle)
        .background(Color.Blue)
        .pointerInput(Unit) {
            awaitEachGesture {
                awaitFirstDown()
                do {
                    val event = awaitPointerEvent()
                    val rotation = event.calculateRotation()
                    angle += rotation
                } while (event.changes.any { it.pressed })
            }
        }
        .fillMaxSize()
)
```

### PointerEvent.calculateZoom

Cmn Artifact: [androidx.compose.foundation:foundation](https://developer.android.com/jetpack/androidx/releases/compose-foundation) [View Source](https://cs.android.com/search?q=file:androidx/compose/foundation/gestures/TransformGestureDetector.kt+function:calculateZoom)

```
fun PointerEvent.calculateZoom(): Float
```

Uses the change of the centroid size between the `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerInputChange#previousPosition()` and `https://developer.android.com/reference/kotlin/androidx/compose/ui/input/pointer/PointerInputChange#position()` to determine how much zoom was intended.

Example Usage:

```kotlin
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.awaitEachGesture
import androidx.compose.foundation.gestures.awaitFirstDown
import androidx.compose.foundation.gestures.calculateZoom
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.pointerInput

var zoom by remember { mutableStateOf(1f) }
Box(
    Modifier.graphicsLayer(scaleX = zoom, scaleY = zoom)
        .background(Color.Blue)
        .pointerInput(Unit) {
            awaitEachGesture {
                awaitFirstDown()
                do {
                    val event = awaitPointerEvent()
                    zoom *= event.calculateZoom()
                } while (event.changes.any { it.pressed })
            }
        }
        .fillMaxSize()
)
```