如何仅使用React Native中的一个函数使用onLayout获取多个视图的尺寸?

时间:2019-03-04 07:56:59

标签: react-native

我有一个包含4 * 4视图框的网格场景。 我想获取每个人的尺寸,以查看用户是否在他们的手指上移动了手指。 通过为16个框编写16个单独的“ onLayout”函数,然后尝试计算用户触摸移动,我成功地完成了此过程。 另外,我编写了16个视图的UI,而不是一个干净的for循环。

因此,我最终遇到了一些混乱的脏代码,这些代码无法动态使用并且无法实现。 谁能帮我用一个函数和一个循环来清理这段代码?

这就是我所拥有的:

render() {
return (
  <View style={{justifyContent: 'center', alignItems: 'center', flex: 1}}>
      <View style={{flex : 1}}><Text>{this.state.wordObj['A']}</Text></View>
      <View onLayout={this.getExactPos} style={{flex : 4, backgroundColor: 'red', marginLeft:20,marginRight:20}} {...this._panResponder.panHandlers}  >
        <View style={{flexDirection: 'row', flex: 1 , backgroundColor: 'red', width: '100%'}}>
            <View onLayout={this.getExactPosA} style={{flex : 1, backgroundColor: 'yellow', justifyContent: 'center', alignItems: 'center'}}><Text>{this.state.Box1}</Text></View>
            <View onLayout={this.getExactPosB} style={{flex : 1, backgroundColor: 'orange', justifyContent: 'center', alignItems: 'center'}}><Text>{this.state.Box2}</Text></View>
            <View onLayout={this.getExactPosC} style={{flex : 1, backgroundColor: 'gray', justifyContent: 'center', alignItems: 'center'}}><Text>{this.state.Box3}</Text></View>
        </View>
        <View onLayout={this.getExactPosRow2} style={{flexDirection: 'row', flex: 1 , backgroundColor: 'blue' , width: '100%'}}>
            <View onLayout={this.getExactPosD} style={{flex : 1, backgroundColor: 'green', justifyContent: 'center', alignItems: 'center'}}><Text>{this.state.Box4}</Text></View>
            <View onLayout={this.getExactPosE} style={{flex : 1, backgroundColor: 'red', justifyContent: 'center', alignItems: 'center'}}><Text>{this.state.Box5}</Text></View>
            <View onLayout={this.getExactPosF} style={{flex : 1, backgroundColor: 'blue', justifyContent: 'center', alignItems: 'center'}}><Text>{this.state.Box6}</Text></View>
        </View>
        <View onLayout={this.getExactPosRow3} style={{flexDirection: 'row', flex: 1 , backgroundColor: 'green', width: '100%'}}>
            <View onLayout={this.getExactPosG} style={{flex : 1, backgroundColor: 'purple', justifyContent: 'center', alignItems: 'center'}}><Text>{this.state.Box7}</Text></View>
            <View onLayout={this.getExactPosH} style={{flex : 1, backgroundColor: 'skyblue', justifyContent: 'center', alignItems: 'center'}}><Text>{this.state.Box8}</Text></View>
            <View onLayout={this.getExactPosI} style={{flex : 1, backgroundColor: '#124567', justifyContent: 'center', alignItems: 'center'}}><Text>{this.state.Box9}</Text></View>
        </View>
      </View>
      <View style={{flex : 1}}><Text>3</Text></View>
    <Text>Hello world! - Home</Text>
    <TouchableOpacity style={{backgroundColor : 'red'}} onPress={this._signOutAsync}>
        <Text>Log Out</Text>
    </TouchableOpacity> 
  </View>
);  }

这部分是视图的onLayout函数:

getExactPos = e => {
    const { width, height, x, y } = e.nativeEvent.layout;   
    this.setState({
      gridXstart : x,
      gridXend : x + width,
      gridYstart : y,
      gridYend : y + height,
    })
    // alert(x);
  };

  getExactPosRow2 = e => {
    const { width, height, x, y } = e.nativeEvent.layout;   
    this.setState({         
      row2Y : y,        
    })       
  };

  getExactPosRow3 = e => {
    const { width, height, x, y } = e.nativeEvent.layout;   
    this.setState({         
      row3Y : y,        
    })       
  };

  getExactPosA = e => {
    const { width, height, x, y } = e.nativeEvent.layout; 
    let newArray = this.state.a;
      newArray.gridXstart = x;
      newArray.gridXend = x + width;
      newArray.gridYstart = y;
      newArray.gridYend = y + height;
    this.setState({a: newArray});
  }; 

  getExactPosB = e => {
    const { width, height, x, y } = e.nativeEvent.layout;   
    let newArray =this.state.b;
      newArray.gridXstart = x;
      newArray.gridXend = x + width;
      newArray.gridYstart = y;
      newArray.gridYend = y + height;
    this.setState({b: newArray});
  };

  getExactPosC = e => {
    const { width, height, x, y } = e.nativeEvent.layout;   
    let newArray = this.state.c;
      newArray.gridXstart = x;
      newArray.gridXend = x + width;
      newArray.gridYstart = y;
      newArray.gridYend = y + height;
    this.setState({c: newArray});
  };

  getExactPosD = e => {
    const { width, height, x, y } = e.nativeEvent.layout;   
    let newArray = this.state.d;
      newArray.gridXstart = x;
      newArray.gridXend = x + width;
      newArray.gridYstart = y;
      newArray.gridYend = y + height;
    this.setState({d: newArray});
  };

  getExactPosE = e => {
    const { width, height, x, y } = e.nativeEvent.layout;   
    let newArray = this.state.e;
      newArray.gridXstart = x;
      newArray.gridXend = x + width;
      newArray.gridYstart = y;
      newArray.gridYend = y + height;
    this.setState({e: newArray});
  };

  getExactPosF = e => {
    const { width, height, x, y } = e.nativeEvent.layout;   
    let newArray = this.state.f;
      newArray.gridXstart = x;
      newArray.gridXend = x + width;
      newArray.gridYstart = y;
      newArray.gridYend = y + height;
    this.setState({f: newArray});
  };

  getExactPosG = e => {
    const { width, height, x, y } = e.nativeEvent.layout;   
    let newArray = this.state.g;
      newArray.gridXstart = x;
      newArray.gridXend = x + width;
      newArray.gridYstart = y;
      newArray.gridYend = y + height;
    this.setState({g: newArray});
  };

  getExactPosH = e => {
    const { width, height, x, y } = e.nativeEvent.layout;   
    let newArray = this.state.h;
      newArray.gridXstart = x;
      newArray.gridXend = x + width;
      newArray.gridYstart = y;
      newArray.gridYend = y + height;
    this.setState({h: newArray});
  };

  getExactPosI = e => {
    const { width, height, x, y } = e.nativeEvent.layout;   
    let newArray = this.state.i;
      newArray.gridXstart = x;
      newArray.gridXend = x + width;
      newArray.gridYstart = y;
      newArray.gridYend = y + height;
    this.setState({i: newArray});
    //alert('asdasdas')
  };

我想使用这种循环来动态创建我的网格,并且还要使用一种onLayout功能来处理所有网格。 :

let rows = [];        
    let k = 0;
    for(let i = 0; i<4 ; i++){
        let row= [];
        for(let j = 0; j<4; j++){
           k++;
           row.push(
            <View onLayout={this.getExactPos2} style={{flex : 1, backgroundColor: 'yellow', justifyContent: 'center', alignItems: 'center'}}><Text>{this.state.Box1}</Text></View>
           )     
        }
        rows.push(
          <View style={{flexDirection: 'row', flex: 1 , backgroundColor: 'red', width: '100%'}}>{row}</View>
        )
    }

为了检测用户在盒子(如钢琴)上的触摸运动,我尝试获取用户手指在屏幕上的位置并与每个盒子的位置进行比较。那是因为我找不到任何解决方案,每个盒子本身总是监听触摸运动。

这是我处理手势的代码:我将panResponder用于父视图。

<View onLayout={this.getExactPos} style={{flex : 4, backgroundColor: 'red', marginLeft:20,marginRight:20}} {...this._panResponder.panHandlers}  >
        <View style={{flexDirection: 'row', flex: 1 , backgroundColor: 'red', width: '100%'}}>
            <View onLayout={this.getExactPosA} style={{flex : 1, backgroundColor: 'yellow', justifyContent: 'center', alignItems: 'center'}}><Text>{this.state.Box1}</Text></View>
            <View onLayout={this.getExactPosB} style={{flex : 1, backgroundColor: 'orange', justifyContent: 'center', alignItems: 'center'}}><Text>{this.state.Box2}</Text></View>
            <View onLayout={this.getExactPosC} style={{flex : 1, backgroundColor: 'gray', justifyContent: 'center', alignItems: 'center'}}><Text>{this.state.Box3}</Text></View>
        </View>
        <View onLayout={this.getExactPosRow2} style={{flexDirection: 'row', flex: 1 , backgroundColor: 'blue' , width: '100%'}}>
            <View onLayout={this.getExactPosD} style={{flex : 1, backgroundColor: 'green', justifyContent: 'center', alignItems: 'center'}}><Text>{this.state.Box4}</Text></View>
            <View onLayout={this.getExactPosE} style={{flex : 1, backgroundColor: 'red', justifyContent: 'center', alignItems: 'center'}}><Text>{this.state.Box5}</Text></View>
            <View onLayout={this.getExactPosF} style={{flex : 1, backgroundColor: 'blue', justifyContent: 'center', alignItems: 'center'}}><Text>{this.state.Box6}</Text></View>
        </View>
        <View onLayout={this.getExactPosRow3} style={{flexDirection: 'row', flex: 1 , backgroundColor: 'green', width: '100%'}}>
            <View onLayout={this.getExactPosG} style={{flex : 1, backgroundColor: 'purple', justifyContent: 'center', alignItems: 'center'}}><Text>{this.state.Box7}</Text></View>
            <View onLayout={this.getExactPosH} style={{flex : 1, backgroundColor: 'skyblue', justifyContent: 'center', alignItems: 'center'}}><Text>{this.state.Box8}</Text></View>
            <View onLayout={this.getExactPosI} style={{flex : 1, backgroundColor: '#124567', justifyContent: 'center', alignItems: 'center'}}><Text>{this.state.Box9}</Text></View>
        </View>
      </View>

这是我的panResponder函数:

componentWillMount() {
    this._panResponder = PanResponder.create({
      onMoveShouldSetPanResponder: (evt, gestureState) => true,
      onPanResponderGrant: (evt) => {
        this.setState({
          zone: '',
        });
      },
      onPanResponderMove: (evt, gestureState) => {
        const drag = this.getDirectionAndColor(gestureState);
        this.setState({
          zone: drag ,
        });                      
      },
      onPanResponderTerminationRequest: (evt, gestureState) => true,
      onPanResponderRelease: (evt, gestureState) => {
        this.setState({
          zone: 'Finished',
        });            
      },
    });
  }

这是我的计算函数:

 getDirectionAndColor = ({ moveX, moveY, dx, dy, x0, y0, stateID }) => {  

          if(
            (this.state.a.gridXstart+this.state.gridXstart < moveX)
            &&          
            (moveX < this.state.a.gridXend + this.state.gridXstart)
            &&
            (this.state.a.gridYstart+this.state.gridYstart < moveY)
            &&
            (moveY < this.state.a.gridYend + this.state.gridYstart)     
            ){           
             return this.state.Box1;
           }else if(
             (this.state.b.gridXstart+this.state.gridXstart < moveX)
             &&          
             (moveX < this.state.b.gridXend + this.state.gridXstart)
             &&
             (this.state.b.gridYstart+this.state.gridYstart < moveY)
             &&
             (moveY < this.state.b.gridYend + this.state.gridYstart)
           ){
             return this.state.Box2;
           }else if(
             (this.state.c.gridXstart+this.state.gridXstart < moveX)
             &&          
             (moveX < this.state.c.gridXend + this.state.gridXstart)
             &&
             (this.state.c.gridYstart+this.state.gridYstart < moveY)
             &&
             (moveY < this.state.c.gridYend + this.state.gridYstart)
           ){
             return this.state.Box3;
           }else if(
             (this.state.d.gridXstart+this.state.gridXstart < moveX)
             &&          
             (moveX < this.state.d.gridXend + this.state.gridXstart)
             &&
             (this.state.d.gridYstart+this.state.gridYstart+this.state.row2Y < moveY)
             &&
             (moveY < this.state.d.gridYend + this.state.gridYstart + this.state.row2Y)
           ){
             return this.state.Box4;
           }else if(
             (this.state.e.gridXstart+this.state.gridXstart < moveX)
             &&          
             (moveX < this.state.e.gridXend + this.state.gridXstart)
             &&
             (this.state.e.gridYstart+this.state.gridYstart+this.state.row2Y < moveY)
             &&
             (moveY < this.state.e.gridYend + this.state.gridYstart + this.state.row2Y)
           ){
             return this.state.Box5;
           }else if(
             (this.state.f.gridXstart+this.state.gridXstart < moveX)
             &&          
             (moveX < this.state.f.gridXend + this.state.gridXstart)
             &&
             (this.state.f.gridYstart+this.state.gridYstart+this.state.row2Y < moveY)
             &&
             (moveY < this.state.f.gridYend + this.state.gridYstart + this.state.row2Y)
           ){ 
             return this.state.Box6;
           }else if(
             (this.state.g.gridXstart+this.state.gridXstart < moveX)
             &&          
             (moveX < this.state.g.gridXend + this.state.gridXstart)
             &&
             (this.state.g.gridYstart+this.state.gridYstart+this.state.row2Y+ this.state.row2Y < moveY)
             &&
             (moveY < this.state.g.gridYend + this.state.gridYstart + this.state.row2Y+ this.state.row2Y)
           ){
             return this.state.Box7;
           }else if(
             (this.state.h.gridXstart+this.state.gridXstart < moveX)
             &&          
             (moveX < this.state.h.gridXend + this.state.gridXstart)
             &&
             (this.state.h.gridYstart+this.state.gridYstart+this.state.row2Y+ this.state.row2Y < moveY)
             &&
             (moveY < this.state.h.gridYend + this.state.gridYstart + this.state.row2Y+ this.state.row2Y)
           ){
             return this.state.Box8;
           }else if(
             (this.state.i.gridXstart+this.state.gridXstart < moveX)
             &&          
             (moveX < this.state.i.gridXend + this.state.gridXstart)
             &&
             (this.state.i.gridYstart+this.state.gridYstart+this.state.row2Y+ this.state.row2Y < moveY)
             &&
             (moveY < this.state.i.gridYend + this.state.gridYstart + this.state.row2Y+ this.state.row2Y)
           ){
             return this.state.Box9;
           }else{
             return 'No'
           }        
  };

这是我的状态:

state = { 
    zone: "Still Touchable",      
    gridXstart : 0,
    gridXend : 0,
    gridYstart : 0,
    gridYend : 0,
    row2Y: 0,
    row3Y: 0,
    Box1: 'A',Box2: 'B', Box3: 'C', Box4: 'D', Box5: 'E',Box6: 'F',Box7: 'G', Box8: 'H', Box9: 'I',
    wordObj : {},
    a : {
      gridXstart : 0,
      gridXend : 0,
      gridYstart : 0,
      gridYend : 0,
    },
    b : {
      gridXstart : 0,
      gridXend : 0,
      gridYstart : 0,
      gridYend : 0,
    },
    c : {
      gridXstart : 0,
      gridXend : 0,
      gridYstart : 0,
      gridYend : 0,
    },
    d : {
      gridXstart : 0,
      gridXend : 0,
      gridYstart : 0,
      gridYend : 0,
    },
    e : {
      gridXstart : 0,
      gridXend : 0,
      gridYstart : 0,
      gridYend : 0,
    },
    f : {
      gridXstart : 0,
      gridXend : 0,
      gridYstart : 0,
      gridYend : 0,
    },
    g : {
      gridXstart : 0,
      gridXend : 0,
      gridYstart : 0,
      gridYend : 0,
    },
    h : {
      gridXstart : 0,
      gridXend : 0,
      gridYstart : 0,
      gridYend : 0,
    },
    i : {
      gridXstart : 0,
      gridXend : 0,
      gridYstart : 0,
      gridYend : 0,
    },         
  };

请帮我一些建议。 谢谢。

1 个答案:

答案 0 :(得分:2)

您不能使用一个onLayout函数来执行此操作,因为您在当前设置中使用两个不同的函数。因此,有可能做到两个。您只需要进一步对代码进行抽象,然后就有可能使其工作。

如果我们想到的是您要像这样构造的网格,则遵循简单的命名约定XY,其中X是行,{{1 }}是该列。

Y

使用该想法,我们可以将您的两个+----+----+----+ | 11 | 12 | 13 | +----+----+----+ | 21 | 22 | 23 | +----+----+----+ | 31 | 32 | 33 | +----+----+----+ 函数修改为如下形式:

onLayout

我们将在下面的getExactPos = (e, key) => { // pass a key as well now const { width, height, x, y } = e.nativeEvent.layout; let position = {}; position.gridXstart = x; position.gridXend = x + width; position.gridYstart = y; position.gridYend = y + height; this.setState({ [key]: position }); // notice that we use the key to store it in state } getExactPosRow = (e, key) => { // pass a key as well now const { y } = e.nativeEvent.layout; this.setState({ [key]: y }); // notice that we use the key to store it in state }; 函数中设置这些函数中使用的键。现在,通过这些我们可以构造一个函数,该函数将依次构造网格:

constructViews

在此函数中,我们有一个嵌套的constructViews = () => { let rows = []; for (let i = 1; i < 4; i++) { let row = []; for (let j = 1; j < 4; j++) { let stateKey = `${i}${j}`; let styleKey = `box${stateKey}`; row.push( <View onLayout={ (e) => this.getExactPos(e, stateKey)} style={styles[styleKey]} key={stateKey}><Text>{this.state[styleKey]}</Text></View> ); } rows.push( <View onLayout={e => this.getExactPosRow(e, `${i}`)} style={styles[`row${i}`]} key={i}>{row}</View> ); } return rows; } 来构造网格。注意,我们构造了键并将其传递给我们创建的两个for-loop函数。我们可以通过动态获取正确的样式和文本来进一步扩展使用键的想法。

这是工作中的POC。这应该给您足够的力量来实现您想要的。我尚未实现任何手势响应器,请您自行决定。

onLayout

在这里您可以看到它在这种小吃https://snack.expo.io/@andypandy/dynamic-grid-using-onlayout中起作用