React Native实现应用中心图标拖动功能

      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
        }
    });
}

 完整代码

https://github.com/EricLoveMia/ApplicationCenterOfRN.git

评论 38
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值