---
name: "MovableView"
mode: "component"
versionRequirements:
  - { name: "@ray-js/ray", version: "0.5.10" }
title: "MovableView - 可移动的视图容器，在页面中可以拖拽滑动"
---

## MovableView

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

### 描述

可拖拽的可移动视图，须置于 MovableArea 内使用。

### 属性

| 属性 | 类型 | 必填 | 默认值 | 最低版本 | 描述 |
| --- | --- | --- | --- | --- | --- |
| `direction` | `"all" \| "vertical" \| "horizontal" \| "none"` | 否 | `"none"` | - | movable-view 的移动方向 |
| `inertia` | `boolean` | 否 | `false` | - | movable-view 是否带有惯性 |
| `outOfBounds` | `boolean` | 否 | `false` | - | 超过可移动区域后，movable-view 是否还可以移动 |
| `x` | `number` | 否 | - | - | 定义 x 轴方向的偏移，如果 x 的值不在可移动范围内，会自动移动到可移动范围；改变 x 的值会触发动画 |
| `y` | `number` | 否 | - | - | 定义 y 轴方向的偏移，如果 y 的值不在可移动范围内，会自动移动到可移动范围；改变 y 的值会触发动画 |
| `damping` | `number` | 否 | `20` | - | 阻尼系数，用于控制 x 或 y 改变时的动画和过界回弹的动画，值越大移动越快 |
| `friction` | `number` | 否 | `2` | - | 摩擦系数，用于控制惯性滑动的动画，值越大摩擦力越大，滑动越快停止；必须大于 0，否则会被设置成默认值 |
| `disabled` | `boolean` | 否 | `false` | - | 是否禁用 |
| `scale` | `boolean` | 否 | `false` | - | 是否支持双指缩放，默认缩放手势生效区域是在 movable-view 内 |
| `scaleMin` | `number` | 否 | `0.5` | - | 定义缩放倍数最小值 |
| `scaleMax` | `number` | 否 | `10` | - | 定义缩放倍数最大值 |
| `scaleValue` | `number` | 否 | `1` | - | 定义缩放倍数，取值范围为 0.5 - 10 |
| `animation` | `boolean` | 否 | `true` | - | 是否使用动画 |
| `onChange` | `(event: MovableViewChangeEvent) => void` | 否 | - | - | 拖动过程中触发 |
| `onScale` | `(event: MovableViewScaleEvent) => void` | 否 | - | `2.1.0` | 缩放过程中触发，x 和 y 字段在 2.1.0 之后支持 |
| `dataset` | `DOMStringMap` | 否 | - | - | 自定义属性: 组件上触发的事件时，会发送给事件处理函数 |
| `id` | `string` | 否 | - | - | 组件的唯一标示: 保持整个页面唯一 |
| `className` | `string` | 否 | - | - | 组件的样式类: 在对应的 WXSS 中定义的样式类 |
| `style` | `any` | 否 | - | - | 组件的内联样式: 可以动态设置的内联样式 |
| `hidden` | `boolean` | 否 | - | - | 组件是否显示: 所有组件默认显示 |
| `children` | `any` | 否 | - | - | 子节点 children |
| `onTap` | `(/   s: TouchEvent) => void` | 否 | - | - | 点击时触发 |
| `onClick` | `(t int: TouchEvent) => void` | 否 | - | - | 点击时触发 |
| `onTouchStart` | `(*/  : TouchEvent) => void` | 否 | - | - | 手指触摸动作开始 |
| `onTouchMove` | `(etail: TouchEvent) => void` | 否 | - | - | 手指触摸后移动 |
| `onTouchCancel` | `(ableV: TouchEvent) => void` | 否 | - | - | 手指触摸动作被打断，如来电提醒，弹窗 |
| `onTouchEnd` | `(/basi: TouchEvent) => void` | 否 | - | - | 手指触摸动作结束 |
| `onLongPress` | `(@exa: TouchEvent) => void` | 否 | - | - | 手指触摸后，超过350ms再离开，如果指定了事件回调函数并触发了这个事件，tap事件将不被触发 |
| `onLongTap` | `(/demo: TouchEvent) => void` | 否 | - | - | 手指触摸后，超过350ms再离开（推荐使用longpress事件代替） |
| `onTransitionEnd` | `('anim: GenericEvent) => void` | 否 | - | - | 会在 WXSS transition 或 ty.createAnimation 动画结束后触发 |
| `onAnimationStart` | `(' \| ': GenericEvent) => void` | 否 | - | - | 会在一个 WXSS animation 动画开始时触发 |
| `onAnimationiteration` | `(移动 */: GenericEvent) => void` | 否 | - | - | 会在一个 WXSS animation 一次迭代结束时触发 |
| `onAnimationEnd` | `(动画 */: GenericEvent) => void` | 否 | - | - | 会在一个 WXSS animation 动画完成时触发 |
| `onTouchForceChange` | `(* 阻尼系数，用于控制 x 或 y 改变时的动画和过界回弹的动画，值越大移动越快 */   : TouchEvent) => void` | 否 | - | - | 在支持 3D Touch 的 iPhone 设备，重按时会触发 |
| `catchClick` | `(* 摩擦系数，用于控制惯性滑动的动画，值越大摩擦力越大，滑动越快停止；必须大于 0，否则会被设置成默认值 */   : TouchEvent) => void` | 否 | - | - | 点击时触发同时阻止事件冒泡 |

##### DOMStringMap 的属性

| 属性 | 类型 | 必填 | 默认值 | 描述 |
| --- | --- | --- | --- | --- |


### 引用对象

##### `interface` MovableViewChangeEvent

| 属性 | 类型 | 描述 |
| --- | --- | --- |
| `detail` | `MovableViewChangeDetail` | 事件数据 |

##### `interface` MovableViewScaleEvent

| 属性 | 类型 | 描述 |
| --- | --- | --- |
| `detail` | `MovableViewScaleDetail` | 事件数据 |

##### `interface` TouchEvent

| 属性 | 类型 | 描述 |
| --- | --- | --- |
| `touches` | `T[]` | 触摸事件，当前停留在屏幕中的触摸点信息的数组 |
| `changedTouches` | `T[]` | 触摸事件，当前变化的触摸点信息的数组 |

##### `interface` GenericEvent

| 属性 | 类型 | 描述 |
| --- | --- | --- |
| `detail` | `Object & Detail` | 额外的信息 |

##### `interface` MovableViewChangeDetail

| 属性 | 类型 | 描述 |
| --- | --- | --- |
| `x` | `number` | x 轴方向的偏移 |
| `y` | `number` | y 轴方向的偏移 |
| `source` | `"touch" \| "touch-out-of-bounds" \| "out-of-bounds" \| "friction" \| ""` | 产生移动的原因 |

##### `interface` BaseEvent

| 属性 | 类型 | 描述 |
| --- | --- | --- |
| `type` | `string` | 事件类型 |
| `timeStamp` | `number` | 页面打开到触发事件所经过的毫秒数 |
| `target` | `Target` | 触发事件的源组件 |
| `currentTarget` | `Target` | 当前组件的一些属性值集合 |
| `mark` | `any` | 事件标记数据 |

##### `interface` MovableViewScaleDetail

| 属性 | 类型 | 描述 |
| --- | --- | --- |
| `x` | `number` | x 轴方向的偏移 |
| `y` | `number` | y 轴方向的偏移 |
| `scale` | `number` | 缩放倍数 |

##### `interface` Target

| 属性 | 类型 | 描述 |
| --- | --- | --- |
| `id` | `string` | 事件源组件的id |
| `dataset` | `Record<string, unknown>` | 事件源组件上的 `dataset` 自定义属性组成的集合 |

##### `type` GenericEvent.detail

| 属性 | 类型 | 描述 |
| --- | --- | --- |
| `value` | `any` |  |


### 示例代码

#### 基础用法

```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' }}>拖我</Text>
        </View>
      </MovableView>
    </MovableArea>
  );
}
```

#### 惯性与回弹

```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('位置:', e.detail.x, e.detail.y, '原因:', e.detail.source)}
      >
        <View
          style={{
            width: '100rpx',
            height: '100rpx',
            backgroundColor: '#52c41a',
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
          }}
        >
          <Text style={{ color: '#fff' }}>惯性</Text>
        </View>
      </MovableView>
    </MovableArea>
  );
}
```

#### 禁用与指定位置

```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 })}>
          左上角
        </Button>
        <Button size="mini" onClick={() => setPos({ x: 150, y: 150 })}>
          居中
        </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' }}>移动</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' }}>禁用</Text>
          </View>
        </MovableView>
      </MovableArea>
    </View>
  );
}
```

#### 双指缩放

```tsx
// 缩放效果需在真机上预览
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('缩放:', e.detail.scale, '位置:', e.detail.x, e.detail.y)}
      >
        <View
          style={{
            width: '150rpx',
            height: '150rpx',
            backgroundColor: '#722ed1',
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
          }}
        >
          <Text style={{ color: '#fff' }}>缩放</Text>
        </View>
      </MovableView>
    </MovableArea>
  );
}
```
