react-native-drag-sort:拖拽排序组件,支持列表拖拽排序

拖拽排序组件,支持列表拖拽排序

分支5Tags3

文档模板:v0.4.2

react-native-drag-sort

本项目基于 react-native-drag-sort 开发。

该第三方库的仓库已迁移至 Gitcode,且支持直接从 npm 下载,新的包名为:@react-native-ohos/react-native-drag-sort,版本所属关系如下:

三方库名称 三方库版本(npm地址) 发布信息 支持RN版本 Autolink 编译API版本 社区基线版本 源码地址
@react-native-ohos/react-native-drag-sort ~2.5.0 Gitcode Releases 0.72.* / 0.77.* / 0.82.* 否 API12+ 2.4.4 master
@react-native-oh-tpl/react-native-drag-sort <=2.4.4-0.1.0@deprecated Github Releases(deprecated) 0.72 否 API12+ 2.4.4 sig

简介

拖拽排序组件,支持列表拖拽排序

下载安装

进入到工程目录并输入以下命令:

yarn

yarn add @react-native-ohos/react-native-drag-sort

npm

npm install @react-native-ohos/react-native-drag-sort

Tip

使用优先级: DragSortableView > AutoDragSortableView > AnySizeDragSortableView

  • 1、如果宽度和高度是固定的,不需要滑动,请使用DragSortableView。
  • 2、如果宽度和高度是固定的,需要滑动,请使用AutoDragSortableView。
  • 3、如果宽度和高度是任意的,需要滑动,请使用AnySizeDragSortableView。

下面的代码展示了这个库的基本使用场景:

DragSortableView组件使用
import React, { useState } from "react";
import { View, Text, StyleSheet, SafeAreaView } from "react-native";
import { DragSortableView } from "react-native-drag-sort";
//此案例id1、id2不支持拖拽
const Dragsort = () => {
  const [data, setData] = useState([
    {
      id: 1,
      title: "固定任务 1",
    },
    {
      id: 2,
      title: "固定任务 2",
    },
    {
      id: 3,
      title: "任务 3",
    },
    {
      id: 4,
      title: "任务 4",
    },
    {
      id: 5,
      title: "任务 5",
    },
    {
      id: 6,
      title: "任务 6",
    },
    {
      id: 7,
      title: "任务 7",
    },
    {
      id: 8,
      title: "任务 8",
    },
  ]);

  return (
    <SafeAreaView style={{ flex: 1 }}>
      <View style={styles.header}>
        <Text style={styles.header_title}>DragSortableView</Text>
      </View>
      <DragSortableView
        dataSource={data}
        parentWidth={400}
        childrenWidth={100}
        childrenHeight={50}
        marginChildrenTop={5}
        marginChildrenBottom={5}
        marginChildrenLeft={5}
        marginChildrenRight={5}
        // onDataChange={setData}
        keyExtractor={(item, index) => item.id}
        onClickItem={(data, item, index) => {
          console.log("点击了第", index, "个元素");
        }}
        onDragStart={() => console.log("Drag started")}
        onDragEnd={() => console.log("Drag end")}
        onDataChange={() => {
          console.log("数据发生变化");
        }}
        fixedItems={[0, 1]}
        delayLongPress={100}
        isDragFreely={true}
        maxScale={1.2}
        minOpacity={0.7}
        renderItem={(item, index) => {
          return (
            <View key={item.id} style={styles.box}>
              <Text style={styles.text}>{item.title}</Text>
            </View>
          );
        }}
        sortable={true}
      />
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  box: {
    // position:'relative',
    // flexDirection: "column",
    justifyContent: "center",
    alignContent: "center",
    borderRadius: 5,
    margin: 20,
    backgroundColor: "#4e71f2",
    height: 50,
    width: 100,
  },
  text: {
    fontSize: 18,
    color: "#fff",
    textAlign: "center",
  },
  header: {
    height: 48,
    justifyContent: "center",
    alignItems: "center",
    borderBottomColor: "#2ecc71",
    borderBottomWidth: 2,
  },
  header_title: {
    color: "#333",
    fontSize: 24,
    fontWeight: "bold",
  },
});
export default Dragsort;
AutoDragSortableView组件使用
//此案例Item1、Item2不支持拖拽
import React, { useState } from "react";
import { View, Text } from "react-native";
import { AutoDragSortableView } from "react-native-drag-sort";

const AutoDragSortDemo = () => {
  const [data, setData] = useState([
    { id: "1", text: "Item 1" },
    { id: "2", text: "Item 2" },
    { id: "3", text: "Item 3" },
    { id: "4", text: "Item 4" },
    { id: "5", text: "Item 5" },
    { id: "6", text: "Item 6" },
    { id: "7", text: "Item 7" },
    { id: "8", text: "Item 8" },
    { id: "9", text: "Item 9" },
    { id: "10", text: "Item 10" },
    { id: "11", text: "Item 11" },
    { id: "12", text: "Item 12" },
    { id: "13", text: "Item 13" },
    { id: "14", text: "Item 14" },
    { id: "15", text: "Item 15" },
    { id: "16", text: "Item 16" },
    { id: "17", text: "Item 17" },
    { id: "18", text: "Item 18" },
    { id: "19", text: "Item 19" },
    { id: "20", text: "Item 20" },
    { id: "21", text: "Item 21" },
    { id: "22", text: "Item 22" },
    { id: "23", text: "Item 23" },
    { id: "24", text: "Item 24" },
    { id: "25", text: "Item 25" },
    { id: "26", text: "Item 26" },
    { id: "27", text: "Item 27" },
    { id: "28", text: "Item 28" },
  ]);
  const renderHeaderView = (
    <View style={{ height: 50, backgroundColor: "#ff4d4d" }}>
      <Text style={{ fontSize: 18, color: "#fff", textAlign: "center" }}>
        标题
      </Text>
    </View>
  );
  const renderBottomView = (
    <View style={{ height: 50, backgroundColor: "#ff4d4d" }}>
      <Text style={{ fontSize: 18, color: "#fff", textAlign: "center" }}>
        底部
      </Text>
    </View>
  );

  return (
    <AutoDragSortableView
      dataSource={data}
      parentWidth={500}
      childrenWidth={100}
      childrenHeight={100}
      marginChildrenTop={20}
      marginChildrenBottom={20}
      marginChildrenLeft={20}
      marginChildrenRight={20}
      onDataChange={(data) => {
        console.log("数据发生变化");
      }}
      keyExtractor={(item, index) => item.id}
      onClickItem={(data, item, index) => {
        console.log("点击了第", index, "个元素");
      }}
      renderItem={(item, index) => {
        return (
          <View
            key={item.id}
            style={{
              width: 100,
              height: 50,
              borderRadius: 5,
              margin: 5,
              backgroundColor: "#4e71f2",
            }}
          >
            <Text style={{ fontSize: 18, color: "#fff" }}>{item.text}</Text>
          </View>
        );
      }}
      scaleDuration={500} //拖拽项缩放效果的持续时间
      slideDuration={200} //拖拽项滑动效果的持续时间
      autoThrottle={100} //自动滑动到目的地的间隔时间
      autoThrottleDuration={500} //自动滑动到目的地的持续时间
      sortable={true}
      isDragFreely={false}
      fixedItems={[0, 1]}
      delayLongPress={100}
      onDragStart={() => console.log("Drag started")}
      onDragEnd={() => console.log("Drag end")}
      renderHeaderView={renderHeaderView}
      headerViewHeight={50}
      scrollIndicatorInsets={{ top: 0, left: 0, bottom: 0, right: 0 }}
      renderBottomView={renderBottomView}
      bottomViewHeight={50}
      onScrollListener={(event) => {
        console.log("滚动事件", event);
      }}
      onScrollRef={(ref) => {
        console.log("滚动容器", ref);
      }}
    />
  );
};

export default AutoDragSortDemo;
AnySizeDragSortableView组件使用
import React, { createRef } from "react";
import {
  Text,
  TouchableOpacity,
  StyleSheet,
  View,
  Image,
  Dimensions,
  SafeAreaView,
} from "react-native";
import { AnySizeDragSortableView } from "react-native-drag-sort";

const { width } = Dimensions.get("window");
const headerViewHeight = 160;
const bottomViewHeight = 40;

const getW = (index, isWidth) =>
  isWidth ? (index % 3 === 0 ? width - 40 : (width - 60) / 2) : 80;

type State = {
  items: { text: string, width: number, height: number }[];
  movedKey: any
}

export default class AnySizeDragSortDemo extends React.Component<any, State> {
  sortableViewRef: React.RefObject<any>;
  constructor(props) {
    super(props);
    const items:State["items"] = [];
    for (let i = 0; i < 26; i++) {
      items.push({
        text: String.fromCharCode(65 + i),
        width: getW(i, true),
        height: getW(i, false),
      });
    }
    this.state = {
      items,
      movedKey: null,
    };

    this.sortableViewRef = createRef();
  }

  onDeleteItem = (item, index) => {
    const items = [...this.state.items];
    items.splice(index, 1);
    this.setState({ items });
  };

  _renderItem = (item, index, isMoved) => {
    const { movedKey } = this.state;
    return (
      <TouchableOpacity
        onLongPress={() => {
          this.setState({ movedKey: item.text });
          this.sortableViewRef.current.startTouch(item, index);
        }}
        onPressOut={() => this.sortableViewRef.current.onPressOut()}
      >
        <View
          style={[
            styles.item_wrap,
            { opacity: movedKey === item.text && !isMoved ? 1 : 0.5 },
          ]}
        >
          {
            <View style={styles.item_clear_wrap}>
              <TouchableOpacity onPress={() => this.onDeleteItem(item, index)}>
                <Image
                  source={require("../SourceLibraryDemo/data/img/clear.png")}
                  style={styles.item_clear}
                />
              </TouchableOpacity>
            </View>
          }
          <View
            style={[
              styles.item,
              {
                width: item.width,
                height: item.height,
                backgroundColor: isMoved ? "red" : "#f39c12",
              },
            ]}
          >
            {isMoved ? (
              <View style={styles.item_icon_swipe}>
                <Image
                  source={{
                    uri: "https://img0.baidu.com/it/u=4232278629,1470839503&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=746",
                  }}
                  style={styles.item_icon}
                />
              </View>
            ) : null}
            <View style={styles.item_text_swipe}>
              <Text style={styles.item_text}>{item.text}</Text>
            </View>
          </View>
        </View>
      </TouchableOpacity>
    );
  };

  render() {
    const { items } = this.state;
    const renderHeaderView = (
      <View style={styles.aheader}>
        <Image
          source={{
            uri: "https://p7.itc.cn/mpbp/pro/20200929/650b94a7b8a542fda242a6575f51d74f.jpeg",
          }}
          style={styles.aheader_img}
        />
        <View style={styles.aheader_context}>
          <Text style={styles.aheader_title}>mochixuan</Text>
          <Text style={styles.aheader_desc}>
            Android, React-Native, Flutter, React, Web。Learn new knowledge and
            share new knowledge.
          </Text>
        </View>
      </View>
    );
    const renderBottomView = (
      <View style={styles.abottom}>
        <Text style={styles.abottom_desc}>yarn add react-native-drag-sort</Text>
      </View>
    );
    return (
      <>
        <View style={styles.header}>
          <Text style={styles.header_title}>AnySize</Text>
        </View>
        <AnySizeDragSortableView
          ref={this.sortableViewRef}
          dataSource={items}
          keyExtractor={(item) => item.text}
          renderItem={this._renderItem}
          onDataChange={(data, callback) => {
            this.setState({ items: data }, () => {
              callback();
              console.log("移动了");
            });
          }}
          renderHeaderView={renderHeaderView}
          headerViewHeight={headerViewHeight}
          renderBottomView={renderBottomView}
          bottomViewHeight={bottomViewHeight}
          movedWrapStyle={styles.item_moved}
          onDragEnd={() => console.log("Drag end")}
          scrollIndicatorInsets={{ top: 1, left: 1, bottom: 1, right: 1 }}
          autoThrottle={100}
          autoThrottleDuration={500}
          areaOverlapRatio={0.5}
          childMarginTop={10}
          childMarginBottom={10}
          childMarginLeft={10}
          childMarginRight={10}
        />
      </>
    );
  }
}

const styles = StyleSheet.create({
  item_wrap: {
    position: "relative",
    paddingLeft: 20,
    paddingTop: 20,
  },
  item: {
    justifyContent: "space-around",
    alignItems: "center",
    backgroundColor: "#f39c12",
    borderRadius: 4,
  },
  item_clear_wrap: {
    position: "absolute",
    left: 10,
    top: 10,
    width: 20,
    height: 20,
    zIndex: 999,
  },
  item_clear: {
    width: 20,
    height: 20,
  },
  item_moved: {
    opacity: 0.95,
    borderRadius: 4,
  },
  item_icon_swipe: {
    width: 50,
    height: 50,
    backgroundColor: "#fff",
    borderRadius: 50 * 0.5,
    justifyContent: "center",
    alignItems: "center",
  },
  item_icon: {
    width: 30,
    height: 30,
    resizeMode: "contain",
  },
  item_text_swipe: {
    backgroundColor: "#fff",
    width: 56,
    height: 30,
    borderRadius: 15,
    justifyContent: "center",
    alignItems: "center",
  },
  item_text: {
    color: "#444",
    fontSize: 20,
    fontWeight: "bold",
  },
  header: {
    height: 48,
    justifyContent: "center",
    alignItems: "center",
    borderBottomColor: "#2ecc71",
    borderBottomWidth: 2,
  },
  header_title: {
    color: "#333",
    fontSize: 24,
    fontWeight: "bold",
  },
  aheader: {
    height: headerViewHeight,
    flexDirection: "row",
    borderBottomColor: "#2ecc71",
    borderBottomWidth: 2,
    zIndex: 100,
    backgroundColor: "#fff",
  },
  aheader_img: {
    width: headerViewHeight * 0.6,
    height: headerViewHeight * 0.6,
    resizeMode: "cover",
    borderRadius: headerViewHeight * 0.3,
    marginLeft: 16,
    marginTop: 10,
  },
  aheader_context: {
    marginLeft: 8,
    height: headerViewHeight * 0.4,
    marginTop: 10,
  },
  aheader_title: {
    color: "#333",
    fontSize: 20,
    marginBottom: 10,
    fontWeight: "bold",
  },
  aheader_desc: {
    color: "#444",
    fontSize: 16,
    width: width - headerViewHeight * 0.6 - 32,
  },
  abottom: {
    justifyContent: "center",
    alignItems: "center",
    height: bottomViewHeight,
    backgroundColor: "#fff",
    zIndex: 100,
    borderTopColor: "#2ecc71",
    borderTopWidth: 2,
  },
  abottom_desc: {
    color: "#333",
    fontSize: 20,
    fontWeight: "bold",
  },
});

约束与限制

兼容性

本文档内容基于以下版本验证通过:

  1. RNOH: 0.72.98; SDK: HarmonyOS-5.0.0(API12); IDE: DevEco Studio 5.0.3.906; ROM: NEXT.0.0.71;
  2. RNOH:0.77.18; SDK:HarmonyOS 6.0.0.47 (API Version 20); IDE:DevEco Studio 6.0.0.858; ROM:6.0.0.107;
  3. RNOH: 0.82.1; SDK: HarmonyOS-5.0.0(API12); IDE: DevEco Studio 6.0.1 Release; ROM:6.0.0.120 SP7

接口说明

DragSortableView

"Platform"列表示该属性在原三方库上支持的平台。

"HarmonyOS Support"列为 yes 表示 HarmonyOS 平台支持该属性;no 则表示不支持;partially 表示部分支持。使用方法跨平台一致,效果对标 iOS 或 Android 的效果。

Name Description Type Required Platform HarmonyOS Support
dataSource 列表的数据源数组 array Yes iOS/Android Yes
parentWidth 父容器宽度 number No iOS/Android Yes
childrenHeight 每个子项的高度 number Yes iOS/Android Yes
childrenWidth 每个子项的宽度 number Yes iOS/Android Yes
marginChildrenTop 若要为子项的最外层视图添加边距,只能使用此方法。 number No iOS/Android Yes
marginChildrenBottom 子项下边距 number No iOS/Android Yes
marginChildrenLeft 子项左边距 number No iOS/Android Yes
marginChildrenRight 子项右边距 number No iOS/Android Yes
sortable 不允许拖拽 bool No iOS/Android Yes
onClickItem 点击事件 function No iOS/Android Yes
onDragStart 拖拽开始后调用 function No iOS/Android Yes
onDragEnd 拖拽结束后调用 function No iOS/Android Yes
onDataChange 每次数据变化时都会调用此方法。 function No iOS/Android Yes
renderItem 渲染子项视图 function Yes iOS/Android Yes
fixedItems 固定项(不可移除) array No iOS/Android Yes
keyExtractor (item,index) => key function No iOS/Android Yes
delayLongPress 长按延迟 number No iOS/Android Yes
isDragFreely 是否限制拖拽空间 bool No iOS/Android Yes
onDragging 拖拽时调用 function No iOS/Android Yes
maxScale 最大缩放比例 number No iOS/Android Yes
minOpacity 最小不透明度 number No iOS/Android Yes
scaleStatus 缩放状态 string No iOS/Android Yes
scaleDuration 缩放持续时间 number No iOS/Android Yes
slideDuration 滑动持续时间 number No iOS/Android Yes

AutoDragSortableView

Name Description Type Required Platform HarmonyOS Support
dataSource 列表的数据源数组 array Yes iOS/Android Yes
parentWidth 父容器宽度 number No iOS/Android Yes
childrenHeight 每个子项的高度 number Yes iOS/Android Yes
childrenWidth 每个子项的宽度 number Yes iOS/Android Yes
marginChildrenTop 若要为子项的最外层视图添加边距,只能使用此方法。 number No iOS/Android Yes
marginChildrenBottom 子项下边距 number No iOS/Android Yes
marginChildrenLeft 子项左边距 number No iOS/Android Yes
marginChildrenRight 子项右边距 number No iOS/Android Yes
sortable 不允许拖拽 bool No iOS/Android Yes
onClickItem 点击事件 function No iOS/Android Yes
onDragStart 拖拽开始后调用 function No iOS/Android Yes
onDragEnd 拖拽结束后调用 function No iOS/Android Yes
onDataChange 每次数据变化时都会调用此方法。 function No iOS/Android Yes
renderItem 渲染子项视图 function Yes iOS/Android Yes
fixedItems 固定项(不可移除) array No iOS/Android Yes
keyExtractor (item,index) => key function No iOS/Android Yes
delayLongPress 长按延迟 number No iOS/Android Yes
isDragFreely 是否限制拖拽空间 bool No iOS/Android Yes
onDragging 拖拽时调用 function No iOS/Android Yes
maxScale 最大缩放比例 number No iOS/Android Yes
minOpacity 最小不透明度 number No iOS/Android Yes
scaleStatus 缩放状态 string No iOS/Android Yes
scaleDuration 缩放持续时间 number No iOS/Android Yes
slideDuration 滑动持续时间 number No iOS/Android Yes
autoThrottle 自动节流 number No iOS/Android Yes
autoThrottleDuration 自动节流持续时间 number No iOS/Android Yes
renderHeaderView 渲染头部视图 element No iOS/Android Yes
headerViewHeight 头部视图高度 number No iOS/Android Yes
scrollIndicatorInsets 滚动条内边距 ({top:number, left:number, bottom:number, right:number}) No iOS NO
renderBottomView 渲染底部视图 element No iOS/Android Yes
bottomViewHeight 底部视图高度 number No iOS/Android Yes
onScrollListener 滚动期间的监听回调 (event: NativeSyntheticEvent) => void No iOS/Android Yes
onScrollRef 滚动引用回调 (ref: any) => void No iOS/Android Yes

AnySizeDragSortableView

Name Description Type Required Platform HarmonyOS Support
renderItem 渲染子项视图 function Yes iOS/Android Yes
onDataChange 每次数据变化时都会调用此方法 function Yes iOS/Android Yes
renderHeaderView 渲染头部视图 element No iOS/Android Yes
headerViewHeight 头部视图高度 number No iOS/Android Yes
renderBottomView 渲染底部视图 element No iOS/Android Yes
bottomViewHeight 底部视图高度 number No iOS/Android Yes
autoThrottle 自动节流 number No iOS/Android Yes
autoThrottleDuration 自动节流持续时间 number No iOS/Android Yes
scrollIndicatorInsets 滚动条内边距 ({top:number, left:number, bottom:number, right:number}) No iOS/Android No
onScrollListener 滚动期间的监听回调 (event: NativeSyntheticEvent) => void No iOS/Android Yes
onScrollRef 滚动引用回调 (ref: any) => void No iOS/Android Yes
areaOverlapRatio 必须大于 0.5 number No iOS/Android Yes
movedWrapStyle 样式 StyleProp Yes iOS/Android Yes
childMarginTop 子项上边距 number No iOS/Android Yes
childMarginBottom 子项下边距 number No iOS/Android Yes
childMarginLeft 子项左边距 number No iOS/Android Yes
childMarginRight 子项右边距 number No iOS/Android Yes
onDragEnd 拖拽结束后调用 function Yes iOS/Android Yes
dataSource 列表的数据源数组 array Yes iOS/Android Yes
keyExtractor 项目的唯一键 (item,index) => key Yes iOS/Android Yes

遗留问题

其他

无

目录结构

/react-native-drag-sort  # 项目根目录
├── lib                            # 库源码目录(纯 JS 实现,无原生代码)
│   ├── index.js                   # 入口文件,统一导出三个拖拽排序组件
│   ├── DragSortableView.js        # 基础拖拽排序组件(等尺寸网格布局)
│   ├── AutoDragSortableView.js    # 内置 ScrollView 的拖拽排序组件(支持拖动到边缘自动滚动)
│   ├── AnySizeDragSortableView.js # 支持任意尺寸 item 的拖拽排序组件
│   ├── index.d.ts                 # TypeScript 类型声明
│   └── harmony                    # 鸿蒙适配目录(纯 JS 库无需原生适配,当前为占位)
├── example                        # 示例工程
│   ├── src/index.tsx              # RN 侧示例代码(DragSortableView 用法演示)
│   └── harmony                    # OpenHarmony 示例工程(基于 RNOH 框架)
│       └── entry/src/main
│           ├── cpp                # C++ 桥接代码(RNOH 工程模板)
│           └── ets                # ArkTS 页面与 Ability(加载 RN 示例页)
├── img                            # README 演示图片
├── README.md                      # 中文说明文档
├── README_en.md                   # 英文说明文档
├── CHANGELOG.md                   # 版本更新记录
├── buildEnv.sh                    # tgz / har 打包脚本
└── LICENSE                        # 开源协议

贡献代码

使用过程中发现任何问题都可以提交 Issue,当然,也非常欢迎提交 PR 。

开源协议

本项目基于 The Apache License (Apache) ,请自由地享受和参与开源。

项目介绍

拖拽排序组件,支持列表拖拽排序

定制我的领域