如何在 React Native 中使用 onLayout 获取多个视图的尺寸?



>我有一个网格场景,其中包含 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>
);  }

这部分是视图的布局函数:

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>

这是我的泛响应器函数:

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

请帮我一些建议。 谢谢。

您不能使用一个onLayout函数来做到这一点,因为您在当前设置中使用两个不同的函数。所以可以用两个人来做。你只需要进一步抽象代码,然后就可以让它工作了。

如果我们想到您正在构建的网格,如果我们遵循直接的命名约定,我们可以很容易地找到网格中的每个单元格XY,其中X是行,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来构造网格。请注意,我们构造键并将其传递给我们创建的两个onLayout函数。我们可以通过动态获取正确的样式和正确的文本来进一步扩展使用键的想法。

这是在工作 POC 中。这应该足以让您实现您想要的内容。我还没有实现任何手势响应器,将留给您。

import React from 'react';
import { Text, View, StyleSheet, Button } from 'react-native';
export default class App extends React.Component {
state = {
box11: 'Box 11',
box12: 'Box 12',
box13: 'Box 13',
box21: 'Box 21',
box22: 'Box 22',
box23: 'Box 23',
box31: 'Box 31',
box32: 'Box 32',
box33: 'Box 33'
}
getExactPos = (e, key) => {
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 });
}
getExactPosRow = (e, key) => {
const { y } = e.nativeEvent.layout;
this.setState({
[key]: y
});
};
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;
}
render () {
return (
<View style={{ justifyContent: 'center', alignItems: 'center', flex: 1 }}>
<View style={{ flex: 1 }}></View>
<Button onPress={() => console.log(this.state)} title={'console log state'} />
<View style={{ flex: 4, backgroundColor: 'red', marginLeft: 20, marginRight: 20 }} >
{this.constructViews()}
</View>
<View style={{ flex: 1 }}></View>
</View>
);
}
}
const styles = StyleSheet.create({
row1: { flexDirection: 'row', flex: 1, backgroundColor: 'red', width: '100%' },
row2: { flexDirection: 'row', flex: 1, backgroundColor: 'blue', width: '100%' },
row3: { flexDirection: 'row', flex: 1, backgroundColor: 'green', width: '100%' },
box11: { flex: 1, backgroundColor: 'yellow', justifyContent: 'center', alignItems: 'center' },
box12: { flex: 1, backgroundColor: 'orange', justifyContent: 'center', alignItems: 'center' },
box13: { flex: 1, backgroundColor: 'gray', justifyContent: 'center', alignItems: 'center' },
box21: { flex: 1, backgroundColor: 'green', justifyContent: 'center', alignItems: 'center' },
box22: { flex: 1, backgroundColor: 'red', justifyContent: 'center', alignItems: 'center' },
box23: { flex: 1, backgroundColor: 'blue', justifyContent: 'center', alignItems: 'center' },
box31: { flex: 1, backgroundColor: 'purple', justifyContent: 'center', alignItems: 'center' },
box32: { flex: 1, backgroundColor: 'skyblue', justifyContent: 'center', alignItems: 'center' },
box33: { flex: 1, backgroundColor: '#124567', justifyContent: 'center', alignItems: 'center' }
});

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

相关内容

  • 没有找到相关文章

最新更新