---
name: "MovableView"
mode: "component"
versionRequirements:
  - { name: "@ray-js/ray", version: "0.5.10" }
title: "MovableView - Draggable and slidable view container"
---

## MovableView

> [VERSION] @ray-js/ray >= 0.5.10

### Description

Draggable movable view; must be used inside MovableArea.

### Props

| Property | Type | Required | Default | Since | Description |
| --- | --- | --- | --- | --- | --- |
| `direction` | `"all" \| "vertical" \| "horizontal" \| "none"` | No | `"none"` | - | Movement direction of movable-view |
| `inertia` | `boolean` | No | `false` | - | Whether movable-view has inertia |
| `outOfBounds` | `boolean` | No | `false` | - | Whether movable-view can move beyond the movable area |
| `x` | `number` | No | - | - | Define the offset on the x-axis. If x is out of range, it will auto-adjust into the movable range; changing x triggers an animation |
| `y` | `number` | No | - | - | Define the offset on the y-axis. If y is out of range, it will auto-adjust into the movable range; changing y triggers an animation |
| `damping` | `number` | No | `20` | - | Damping coefficient, controls the animation when x or y changes and the overscroll bounce; the larger the value, the faster it moves |
| `friction` | `number` | No | `2` | - | Friction coefficient, controls the animation of inertial scrolling; the larger the value, the greater the friction and the quicker it stops; must be greater than 0, otherwise the default is used |
| `disabled` | `boolean` | No | `false` | - | Whether disabled |
| `scale` | `boolean` | No | `false` | - | Whether pinch-to-zoom is supported; by default the gesture is effective only within the movable-view |
| `scaleMin` | `number` | No | `0.5` | - | Define the minimum zoom scale |
| `scaleMax` | `number` | No | `10` | - | Define the maximum zoom scale |
| `scaleValue` | `number` | No | `1` | - | Define the zoom scale, valid range 0.5 - 10 |
| `animation` | `boolean` | No | `true` | - | Whether to use animation |
| `onChange` | `(event: MovableViewChangeEvent) => void` | No | - | - | Triggers during dragging |
| `onScale` | `(event: MovableViewScaleEvent) => void` | No | - | `2.1.0` | Triggers during zoom; x and y fields are supported since 2.1.0 |
| `dataset` | `DOMStringMap` | No | - | - | Custom attributes: sent to the event handler when events are triggered on the component |
| `id` | `string` | No | - | - | Unique identifier for the component: must be unique across the entire page |
| `className` | `string` | No | - | - | Component style classes: classes defined in the corresponding WXSS |
| `style` | `any` | No | - | - | Component inline style: inline styles that can be set dynamically |
| `hidden` | `boolean` | No | - | - | Whether the component is visible: all components are visible by default |
| `children` | `any` | No | - | - | Child nodes children |
| `onTap` | `(/   s: TouchEvent) => void` | No | - | - | Triggered on tap |
| `onClick` | `(t int: TouchEvent) => void` | No | - | - | Triggered on tap |
| `onTouchStart` | `(*/  : TouchEvent) => void` | No | - | - | Touch start |
| `onTouchMove` | `(etail: TouchEvent) => void` | No | - | - | Touch move |
| `onTouchCancel` | `(ableV: TouchEvent) => void` | No | - | - | Touch canceled (e.g., incoming call or popup) |
| `onTouchEnd` | `(/basi: TouchEvent) => void` | No | - | - | Touch end |
| `onLongPress` | `(@exa: TouchEvent) => void` | No | - | - | After a touch, if released after more than 350 ms, and if an event callback is specified and this event fires, the tap event will not fire |
| `onLongTap` | `(/demo: TouchEvent) => void` | No | - | - | After a touch, if released after more than 350 ms (use the longpress event instead) |
| `onTransitionEnd` | `('anim: GenericEvent) => void` | No | - | - | Triggered after a WXSS transition or a ty.createAnimation animation ends |
| `onAnimationStart` | `(' \| ': GenericEvent) => void` | No | - | - | Triggered when a WXSS animation starts |
| `onAnimationiteration` | `(移动 */: GenericEvent) => void` | No | - | - | Triggered when one iteration of a WXSS animation ends |
| `onAnimationEnd` | `(动画 */: GenericEvent) => void` | No | - | - | Triggered when a WXSS animation completes |
| `onTouchForceChange` | `(* 阻尼系数，用于控制 x 或 y 改变时的动画和过界回弹的动画，值越大移动越快 */   : TouchEvent) => void` | No | - | - | On iPhones that support 3D Touch, fires on deep press |
| `catchClick` | `(* 摩擦系数，用于控制惯性滑动的动画，值越大摩擦力越大，滑动越快停止；必须大于 0，否则会被设置成默认值 */   : TouchEvent) => void` | No | - | - | Triggered on tap and stops event propagation |

##### DOMStringMap properties

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |


### Referenced Types

##### `interface` MovableViewChangeEvent

| Property | Type | Description |
| --- | --- | --- |
| `detail` | `MovableViewChangeDetail` | Event data |

##### `interface` MovableViewScaleEvent

| Property | Type | Description |
| --- | --- | --- |
| `detail` | `MovableViewScaleDetail` | Event data |

##### `interface` TouchEvent

| Property | Type | Description |
| --- | --- | --- |
| `touches` | `T[]` | Touch event: array of touch points currently on the screen |
| `changedTouches` | `T[]` | Touch event: array of changed touch points |

##### `interface` GenericEvent

| Property | Type | Description |
| --- | --- | --- |
| `detail` | `Object & Detail` | Additional information |

##### `interface` MovableViewChangeDetail

| Property | Type | Description |
| --- | --- | --- |
| `x` | `number` | Offset along the x-axis |
| `y` | `number` | Offset along the y-axis |
| `source` | `"touch" \| "touch-out-of-bounds" \| "out-of-bounds" \| "friction" \| ""` | Cause of movement |

##### `interface` BaseEvent

| Property | Type | Description |
| --- | --- | --- |
| `type` | `string` | Event type |
| `timeStamp` | `number` | Time in milliseconds since the page opened |
| `target` | `Target` | Source component of the event |
| `currentTarget` | `Target` | Collection of property values for the current component |
| `mark` | `any` | Event mark data |

##### `interface` MovableViewScaleDetail

| Property | Type | Description |
| --- | --- | --- |
| `x` | `number` | Offset along the x-axis |
| `y` | `number` | Offset along the y-axis |
| `scale` | `number` | Zoom scale |

##### `interface` Target

| Property | Type | Description |
| --- | --- | --- |
| `id` | `string` | id of the event source component |
| `dataset` | `Record<string, unknown>` | Collection of custom attributes from the `dataset` on the event source component |

##### `type` GenericEvent.detail

| Property | Type | Description |
| --- | --- | --- |
| `value` | `any` |  |


### Examples

#### Basic usage

```tsx
import React from 'react';
import { MovableArea, MovableView, View, Text } from '@ray-js/ray';

export default function BasicMovableView() {
  return (
    <MovableArea
      style={{
        width: '400rpx',
        height: '400rpx',
        backgroundColor: '#f5f5f5',
        overflow: 'hidden',
      }}
    >
      <MovableView direction="all">
        <View
          style={{
            width: '100rpx',
            height: '100rpx',
            backgroundColor: '#1890ff',
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
          }}
        >
          <Text style={{ color: '#fff' }}>Drag me</Text>
        </View>
      </MovableView>
    </MovableArea>
  );
}
```

#### Inertia and bounce

```tsx
import React from 'react';
import { MovableArea, MovableView, View, Text } from '@ray-js/ray';

export default function InertiaDemo() {
  return (
    <MovableArea
      style={{
        width: '400rpx',
        height: '400rpx',
        backgroundColor: '#f5f5f5',
        overflow: 'hidden',
      }}
    >
      <MovableView
        direction="all"
        inertia
        outOfBounds
        damping={30}
        friction={5}
        x={50}
        y={50}
        animation
        onChange={(e) => console.log('Position:', e.detail.x, e.detail.y, 'Reason:', e.detail.source)}
      >
        <View
          style={{
            width: '100rpx',
            height: '100rpx',
            backgroundColor: '#52c41a',
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
          }}
        >
          <Text style={{ color: '#fff' }}>Inertia</Text>
        </View>
      </MovableView>
    </MovableArea>
  );
}
```

#### Disabled and specified position

```tsx
import React, { useState } from 'react';
import { MovableArea, MovableView, View, Text, Button } from '@ray-js/ray';

export default function DisabledDemo() {
  const [pos, setPos] = useState({ x: 0, y: 0 });

  return (
    <View>
      <View style={{ display: 'flex', marginBottom: '20rpx', gap: '10rpx' }}>
        <Button size="mini" onClick={() => setPos({ x: 0, y: 0 })}>
          Top left
        </Button>
        <Button size="mini" onClick={() => setPos({ x: 150, y: 150 })}>
          Center
        </Button>
      </View>
      <MovableArea
        style={{
          width: '400rpx',
          height: '400rpx',
          backgroundColor: '#f5f5f5',
          overflow: 'hidden',
        }}
      >
        <MovableView direction="all" x={pos.x} y={pos.y} animation>
          <View
            style={{
              width: '100rpx',
              height: '100rpx',
              backgroundColor: '#1890ff',
              display: 'flex',
              alignItems: 'center',
              justifyContent: 'center',
            }}
          >
            <Text style={{ color: '#fff' }}>Move</Text>
          </View>
        </MovableView>
        <MovableView direction="all" disabled x={200} y={0}>
          <View
            style={{
              width: '100rpx',
              height: '100rpx',
              backgroundColor: '#d9d9d9',
              display: 'flex',
              alignItems: 'center',
              justifyContent: 'center',
            }}
          >
            <Text style={{ color: '#999' }}>Disabled</Text>
          </View>
        </MovableView>
      </MovableArea>
    </View>
  );
}
```

#### Pinch-to-zoom

```tsx
// The scaling effect needs to be previewed on a real device
import React from 'react';
import { MovableArea, MovableView, View, Text } from '@ray-js/ray';

export default function ScaleDemo() {
  return (
    <MovableArea
      scaleArea
      style={{
        width: '400rpx',
        height: '400rpx',
        backgroundColor: '#f5f5f5',
        overflow: 'hidden',
      }}
    >
      <MovableView
        direction="all"
        scale
        scaleMin={0.5}
        scaleMax={3}
        scaleValue={1}
        onScale={(e) => console.log('Scale:', e.detail.scale, 'Position:', e.detail.x, e.detail.y)}
      >
        <View
          style={{
            width: '150rpx',
            height: '150rpx',
            backgroundColor: '#722ed1',
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
          }}
        >
          <Text style={{ color: '#fff' }}>Scale</Text>
        </View>
      </MovableView>
    </MovableArea>
  );
}
```
