React Native (简称RN)是Facebook于2015年4月开源的跨平台移动应用开发框架,是Facebook早先开源的UI框架 React 在原生移动应用平台的衍生产物,目前支持iOS和安卓两大平台。RN使用Javascript语言,类似于HTML的JSX,以及CSS来开发移动应用,因此熟悉Web前端开发的技术人员只需很少的学习就可以进入移动应用开发领域。(百度百科)
小编有幸参与了公司APP的开发,该APP采用混合式开发,本人负责RN的几个功能的开发,其中最复杂的就是应用中心的功能,如下图所示。模块分为上下两部分,下面是所有应用,上面是下方勾选的应用,可以上下左右滑动(图中只有一行,后面改成了两行,故可以上下或者斜着滑动,偷懒就不截图了)
所以一共要实现接收数据、选择应用、调整顺序、提交这个几个功能,下面重点讲述调整顺序的代码,其他的代码可能会掠过。
1、获取数据
定一个几个变量,用于保存我的应用和所有应用,获取数据调用了原生的方法,大家用RN的获取数据的方法是一样的。
在构造器里面的变量
this.myapps = [];
this.application= [];
//获取数据
dsfectchData(){
RNBridgeManager.queryAppList((error, result) => {
if(error){
console.log("---q--->error:" + error);
}else{
var myapp = [];
for(var i=0;i<result.length;i++){
if(result[i].myAppList == 1){
myapp.push(result[i]);
console.log( i + " : " + result[i].appId);
}
}
this.myapps = myapp; //保存我的应用数据
console.log("this.myapps" + this.myapps.length);
this.application = result; // 保存所有数据
}
});
}
2、展示数据
重点来看我的应用的数据展示方式,如下图第一个红色标记的是将数据放入到一个数组中,这个数据记录
顺序;第二个红色标记用于和上一个标记中的order数组一起,用于排序和重新展示;第三个红色标记的
部分是每个可拖动的图标的定位,当然首先要将定位设定为:position = 'absolute'。绿色底标注
的为可拖动的核心,即触摸操作。
<View style={{flexDirection: 'row',height:25,backgroundColor: '#fff',alignItems: 'center',paddingTop:10,marginTop:px2pt(10)}}>
<Image
source={{uri:this.state.navbar}}
style={{width:3,height:15,marginLeft:px2pt(10)}}
/>
<Text style={styles.itemTitle}>我的应用</Text>
<Text style={styles.itemTitleDes}>(按住拖动调整顺序)</Text>
</View>
<View style={styles.containerMy}>
{this.myapps.map((item, i)=>{
this.order.push(item);
return (
<View
{...this._panResponder.panHandlers}
ref={(ref) => this.items[i] = ref}
key={i}
style={[styles.item, {top: (parseInt(i/4))*90 + 10,left:(i%4)*this.widthSreen}]}>
<Image
source={{uri:this.state.shortcut_icon_bg}}
style={styles.thumbnail}
/>
<Image
source={this._getApplicationIcons(item.appId)}
style={styles.thumbnailInside}
/>
<TextActivity text={item.appName} width={containerWidth}/>
<TouchableWithoutFeedback onPress={this._pressIcon.bind(this,this.myapps,i,1)} style={styles.buttonRightTop}>
<Image
source={{uri:this.state.shortcut_icon_del}}
style={styles.imageRightTop}
/>
</TouchableWithoutFeedback>
</View>
);
})}
</View>
3、滑动操作部分,此部分依次为
1)点击时判定是哪个图标(根据坐标)
2)判定移动位置是否已经和其他的图标有重合,如果有,则交换两个图标的位置
3)释放后的显示结果
componentWillMount(){
this._panResponder = PanResponder.create({
onStartShouldSetPanResponder: (evt, gestureState) => true,
onMoveShouldSetPanResponder: (evt, gestureState) => true,
onPanResponderGrant: (evt, gestureState) => {
const {pageX,pageY, locationX,locationY} = evt.nativeEvent;
console.log("--eric-->:pageX:" + pageX + "--pageY:" + pageY + "--locationX:" + locationX + "--locationY:" + locationY);
this.index = this._getIdByPosition(pageX,pageY);
//逻辑应该是点击的一瞬间,判定是第几个 (parseInt(i/4))*90,left:(i%4)*this.widthSreen}
this.preX = (this.index%4)*this.widthSreen;
this.preY = (parseInt(this.index/4))*90 + 10;
//get the taped item and highlight it
let item = this.items[this.index];
if(item!=null){
item.setNativeProps({
style: {
shadowColor: "#000",
shadowOpacity: 0.3,
shadowRadius: 5,
shadowOffset: {height: 0, width: 2},
elevation: 5
}
});
}
},
// 移动判定是否进入了某个图标的领域,如果进入则交换
onPanResponderMove: (evt, gestureState) => {
let left = this.preX + gestureState.dx;
let top = this.preY + gestureState.dy;
console.log("--eric-->top:" + top + ":" + gestureState.dy);
let item = this.items[this.index];
if(item!=null) {
item.setNativeProps({
style: {left: left,top: top}
});
}
let collideIndex = this._getIdByPosition(evt.nativeEvent.pageX,evt.nativeEvent.pageY);
if(collideIndex !== this.index && collideIndex !== -1) {
let collideItem = this.items[collideIndex];
if(collideItem!=null){
collideItem.setNativeProps({
style: {left: this._getLeftValueYById(this.index),top:this._getTopValueYById(this.index)}
});
//swap two values
[this.items[this.index], this.items[collideIndex]] = [this.items[collideIndex], this.items[this.index]];
[this.order[this.index], this.order[collideIndex]] = [this.order[collideIndex], this.order[this.index]];
this.index = collideIndex;
}
}
},
// 释放后的显示结果
onPanResponderTerminationRequest: (evt, gestureState) => true,
onPanResponderRelease: (evt, gestureState) => {
const shadowStyle = {
shadowColor: "#000",
shadowOpacity: 0,
shadowRadius: 0,
shadowOffset: {height: 0, width: 0,},
elevation: 0
};
let item = this.items[this.index];
//go back the correct position
if(item!=null){
item.setNativeProps({
style: {...shadowStyle, left: this._getLeftValueYById(this.index),top: this._getTopValueYById(this.index)}
});
}
console.log(this.order);
},
onPanResponderTerminate: (evt, gestureState) => {
// Another component has become the responder, so this gesture
// should be cancelled
}
});
}
完整代码