什么是PanResponder
- PanResponder 是 React Native 实现的一套手势相应方法。PanResponder 类可以将多点触摸操作协调成一个手势。它将单点触控手势能够适应额外的触摸,并可用于识别简单的多点触控手势。
- 默认情况下,PanResponder 会通过 InteractionManager来阻止长时间运行的JS时间打断当前的手势活动。
- PanResponder提供一个对触摸响应系统的可预测的包装。
- 官网介绍地址:PanResponder
实现cell的可拖动
-
创建 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( <View ref={"cell"+index} {...this._panResponder.panHandlers} key={elem.key} style={[styles.touchCell,{top,left}]} underlayColor="#eee"> <View style={styles.cellContainer}> <Image style={styles.cellIcon} source={elem.icon}></Image> <Text style={styles.cellTitle}>{elem.title}</Text> </View> </View> ) })
-
在 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, },{...}] }
在componentWillMount()中添加 PanResponder ,并根据 PanResponder 的回调更新布局和数据。
-
通过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);
}
}
-
使用 Component
render(){ return( <View style={{flex:1}}> <DragCell/> </View> ) }