RN通过PanResponder 实现单元格拖拽

什么是PanResponder

  • PanResponder 是 React Native 实现的一套手势相应方法。PanResponder 类可以将多点触摸操作协调成一个手势。它将单点触控手势能够适应额外的触摸,并可用于识别简单的多点触控手势。
  • 默认情况下,PanResponder 会通过 InteractionManager来阻止长时间运行的JS时间打断当前的手势活动。
  • PanResponder提供一个对触摸响应系统的可预测的包装。
  • 官网介绍地址:PanResponder

实现cell的可拖动

  1. 创建 class DragCell extends Component{},绘制简单的两行四列的单元格用实现cell拖拽功能

    const cells = this.state.cells.map((elem , index)=>{
            let top = Math.floor(index /4)* this._width ; 
            let left = (index % 4) * this._width;
            // 单个 cell 布局 ,手势绑定
            return(
                
                    
                        
                        {elem.title}
                    
                
            )
        })
    
  2. 在 constructor() 定义需要使用的变量和数据

       this._width = width/4;     //单元格宽度
       this.topIndex = 0;         //开始点击所在行
       this.leftIndex = 0;        //开始点击所在列
       this.index = 0;            //开始所选cell在数组中的下标
       this.finalTopIndex = 0;    //拖拽结束所在的行
       this.finalLeftIndex = 0;   //拖拽之后所在的列
       this.finalIndex = 0;       //拖拽之后cell在数组中的下标
       this.prev_left = 0;        //cell相对父组件距离left距离
       this.prev_top = 0;         //cell相对父组件距离top距离
       this.left = 0;             //拖拽之后 cell 距离 left 的距离
       this.top = 0;              //拖拽之后 cell 距离 top 的距离
       this.state = {
         selected : 7,
         // cell数据
         cells:[{
             key:0,
             title:"A aaaa",
             icon:require('./images/day1.png'),
             size:48,
             bgColor:"#ff856c",
             hideNav:false,
         },{...}]
     }
    
  3. 在componentWillMount()中添加 PanResponder ,并根据 PanResponder 的回调更新布局和数据。

  4. 通过onPanResponderGrant(e, gestureState) => {...} 获取即将被拖拽的cell的坐标,根据坐标获取当前单元格的句柄

         onPanResponderGrant:(evt,gestureState) => {
         const {pageX,pageY} = evt.nativeEvent;
         this.topIndex = Math.floor((pageY - width*0.3) / this._width);  // 根据坐标Y获取当前所在的行
         this.leftIndex = Math.floor((pageX) / this._width);             // 根据坐标X获取当前所在的列    
         this.index = this.topIndex *4 + this.leftIndex;                 // 根据每行显示的cell个数,已经行,列,计算出cell所在数组的下标
         this.prev_left = this._width * this.leftIndex;                  // cell 距离 left 的距离
         this.prev_top = this._width * this.topIndex;                    // cell 距离 top 的距离
         this.setState({
             selected :  this.index     // 修改 state 的值
         });
         let oneCell = this.refs["cell"+this.index];
    

5.通过onPanResponderMove(e, gestureState) => {...} 计算移动的距离,根据距离计算判断是否需要更新数据,调用_endMove()方法 , 移动的距离符合更新条件就对数组更新,通过setState数组刷新单元格列表。

    _endMove(evt,gestureState){
        this.finalTopIndex  = Math.floor(this.top / this._width + 0.5);        // 拖拽之后计算所在 列
        this.finalLeftIndex = Math.floor(this.left /this._width + 0.5);        // 拖拽之后计算所在 行
        //判断是否需要移动
        if((-1 < this.finalTopIndex) && (this.finalTopIndex <5) && (-1 < this.finalLeftIndex) && this.finalLeftIndex <4){
            this.finalIndex = this.finalTopIndex * 4 +this.finalLeftIndex ;
            // 数组数据替换
            let cells = this.state.cells;
            let moveCell =  cells[this.index];
            cells.splice(this.index ,1);
            cells.splice(this.finalIndex , 0 ,moveCell) ; 
            this.setState({
                cells
            })
            if(this.finalIndex != this.index){
                this.index =  this.finalIndex;
                this.setState({
                    selected : this.finalIndex,
                })
            }
            LayoutAnimation.configureNext(this.animations);
        }else{
            LayoutAnimation.configureNext(this.animations);
        }
    }
  1. 使用 Component

    render(){
            return(
                           
                    
                
            )
        } 
    

运行就可以实现简单的单元格拖拽了 ,效果如下:
dragCellDemo.gif

完整代码下载地址

你可能感兴趣的:(RN通过PanResponder 实现单元格拖拽)