我正在尝试制作一个旋转的魔方,它具有每个小立方体作为触发事件的可触摸组件 - 触摸橙色、绿色和黄色上的立方体会触发正确的事件,而触摸其他颜色上的一些立方体最终会触发事件这 3 种(橙色/绿色/黄色)颜色中的一种。我该如何解决?
这是 App.js:
import React, { Component, PropTypes } from 'react';
import {
Dimensions,
PanResponder,
View,
TouchableOpacity,
Text,
} from 'react-native';
import { transformOrigin, rotateXY, rotateXZ } from './utils';
import SmallBox from './SmallBox';
const HEIGHT = Dimensions.get('window').height;
const WIDTH = Dimensions.get('window').width;
const styles = {
container: {
position: 'absolute',
left: WIDTH / 2 - 50,
top: HEIGHT / 2 - 50,
width: 100,
height: 100,
backgroundColor: 'transparent',
},
rectangle: {
position: 'absolute',
left: 0,
top: 0,
width: 100,
height: 100,
zIndex: 10,
},
smallBox: {
height: 100 / 3,
width: 100 / 3,
borderWidth: 1,
justifyContent: 'center',
alignItems: 'center',
},
};
export default class Cube extends Component {
componentWillMount() {
this.panResponder = PanResponder.create({
onMoveShouldSetPanResponder: () => true,
onPanResponderMove: this.handlePanResponderMove.bind(this),
});
}
handlePanResponderMove(e, gestureState) {
const { dx, dy } = gestureState;
const origin = { x: 0, y: 0, z: -50 };
let matrix = rotateXY(dx, dy);
transformOrigin(matrix, origin);
this.refViewFront.setNativeProps({
style: { transform: [{ perspective: 1000 }, { matrix: matrix }] },
});
//test
matrix = rotateXY(dx + 180, dy);
transformOrigin(matrix, origin);
this.refViewBack.setNativeProps({
style: { transform: [{ perspective: 1000 }, { matrix: matrix }] },
});
matrix = rotateXY(dx + 90, dy);
transformOrigin(matrix, origin);
this.refViewRight.setNativeProps({
style: { transform: [{ perspective: 1000 }, { matrix: matrix }] },
});
matrix = rotateXY(dx - 90, dy);
transformOrigin(matrix, origin);
this.refViewLeft.setNativeProps({
style: { transform: [{ perspective: 1000 }, { matrix: matrix }] },
});
matrix = rotateXZ(dx, dy - 90);
transformOrigin(matrix, origin);
this.refViewTop.setNativeProps({
style: { transform: [{ perspective: 1000 }, { matrix: matrix }] },
});
matrix = rotateXZ(-dx, dy + 90);
transformOrigin(matrix, origin);
this.refViewBottom.setNativeProps({
style: { transform: [{ perspective: 1000 }, { matrix: matrix }] },
});
}
renderRight(color) {
return (
<View
ref={(component) => (this.refViewRight = component)}
style={[styles.rectangle, color ? { backgroundColor: color } : null]}
{...this.panResponder.panHandlers}
>
<View style={{ flexDirection: 'row' }}>
<SmallBox num={1} color='yellow' position='top-left' />
<SmallBox num={1} color='yellow' position='top-middle' />
<SmallBox num={1} color='yellow' position='top-right' />
</View>
<View style={{ flexDirection: 'row' }}>
<SmallBox num={1} color='yellow' position='middle-left' />
<SmallBox num={1} color='yellow' position='middle-middle' />
<SmallBox num={1} color='yellow' position='middle-right' />
</View>
<View style={{ flexDirection: 'row' }}>
<SmallBox num={1} color='yellow' position='bottom-left' />
<SmallBox num={1} color='yellow' position='bottom-middle' />
<SmallBox num={1} color='yellow' position='bottom-right' />
</View>
</View>
);
}
renderLeft(color) {
return (
<View
ref={(component) => (this.refViewLeft = component)}
style={[styles.rectangle, color ? { backgroundColor: color } : null]}
{...this.panResponder.panHandlers}
>
<View style={{ flexDirection: 'row' }}>
<SmallBox num={1} color='blue' position='top-left' />
<SmallBox num={1} color='blue' position='top-middle' />
<SmallBox num={1} color='blue' position='top-right' />
</View>
<View style={{ flexDirection: 'row' }}>
<SmallBox num={1} color='blue' position='middle-left' />
<SmallBox num={1} color='blue' position='middle-middle' />
<SmallBox num={1} color='blue' position='middle-right' />
</View>
<View style={{ flexDirection: 'row' }}>
<SmallBox num={1} color='blue' position='bottom-left' />
<SmallBox num={1} color='blue' position='bottom-middle' />
<SmallBox num={1} color='blue' position='bottom-right' />
</View>
</View>
);
}
renderFront(color) {
return (
<View
ref={(component) => (this.refViewFront = component)}
style={[styles.rectangle, color ? { backgroundColor: color } : null]}
{...this.panResponder.panHandlers}
>
<View style={{ flexDirection: 'row' }}>
<SmallBox num={1} color='red' position='top-left' />
<SmallBox num={1} color='red' position='top-middle' />
<SmallBox num={1} color='red' position='top-right' />
</View>
<View style={{ flexDirection: 'row' }}>
<SmallBox num={1} color='red' position='middle-left' />
<SmallBox num={1} color='red' position='middle-middle' />
<SmallBox num={1} color='red' position='middle-right' />
</View>
<View style={{ flexDirection: 'row' }}>
<SmallBox num={1} color='red' position='bottom-left' />
<SmallBox num={1} color='red' position='bottom-middle' />
<SmallBox num={1} color='red' position='bottom-right' />
</View>
</View>
);
}
renderBack(color) {
return (
<View
ref={(component) => (this.refViewBack = component)}
style={[styles.rectangle, color ? { backgroundColor: color } : null]}
{...this.panResponder.panHandlers}
>
<View style={{ flexDirection: 'row' }}>
<SmallBox num={1} color='green' position='top-left' />
<SmallBox num={1} color='green' position='top-middle' />
<SmallBox num={1} color='green' position='top-right' />
</View>
<View style={{ flexDirection: 'row' }}>
<SmallBox num={1} color='green' position='middle-left' />
<SmallBox num={1} color='green' position='middle-middle' />
<SmallBox num={1} color='green' position='middle-right' />
</View>
<View style={{ flexDirection: 'row' }}>
<SmallBox num={1} color='green' position='bottom-left' />
<SmallBox num={1} color='green' position='bottom-middle' />
<SmallBox num={1} color='green' position='bottom-right' />
</View>
</View>
);
}
renderTop(color) {
return (
<View
ref={(component) => (this.refViewTop = component)}
style={[styles.rectangle, color ? { backgroundColor: color } : null]}
{...this.panResponder.panHandlers}
>
<View style={{ flexDirection: 'row' }}>
<SmallBox num={1} color='white' position='top-left' />
<SmallBox num={1} color='white' position='top-middle' />
<SmallBox num={1} color='white' position='top-right' />
</View>
<View style={{ flexDirection: 'row' }}>
<SmallBox num={1} color='white' position='middle-left' />
<SmallBox num={1} color='white' position='middle-middle' />
<SmallBox num={1} color='white' position='middle-right' />
</View>
<View style={{ flexDirection: 'row' }}>
<SmallBox num={1} color='white' position='bottom-left' />
<SmallBox num={1} color='white' position='bottom-middle' />
<SmallBox num={1} color='white' position='bottom-right' />
</View>
</View>
);
}
renderBottom(color) {
return (
<View
ref={(component) => (this.refViewBottom = component)}
style={[styles.rectangle, color ? { backgroundColor: color } : null]}
{...this.panResponder.panHandlers}
>
<View style={{ flexDirection: 'row' }}>
<SmallBox num={1} color='orange' position='top-left' />
<SmallBox num={1} color='orange' position='top-middle' />
<SmallBox num={1} color='orange' position='top-right' />
</View>
<View style={{ flexDirection: 'row' }}>
<SmallBox num={1} color='orange' position='middle-left' />
<SmallBox num={1} color='orange' position='middle-middle' />
<SmallBox num={1} color='orange' position='middle-right' />
</View>
<View style={{ flexDirection: 'row' }}>
<SmallBox num={1} color='orange' position='bottom-left' />
<SmallBox num={1} color='orange' position='bottom-middle' />
<SmallBox num={1} color='orange' position='bottom-right' />
</View>
</View>
);
}
render() {
return (
<View style={{ flex: 1, backgroundColor: '#fff5c0' }}>
<View style={styles.container}>
{this.renderLeft('blue')}
{this.renderRight('yellow')}
{this.renderFront('red')}
{this.renderBack('green')}
{this.renderTop('white')}
{this.renderBottom('orange')}
</View>
</View>
);
}
}
这是 utils.js:
import MatrixMath from 'react-native/Libraries/Utilities/MatrixMath';
export const rotateXY = (dx, dy) => {
const radX = (Math.PI / 180) * dy;
const cosX = Math.cos(radX);
const sinX = Math.sin(radX);
const radY = (Math.PI / 180) * -dx;
const cosY = Math.cos(radY);
const sinY = Math.sin(radY);
return [
cosY,
sinX * sinY,
cosX * sinY,
0,
0,
cosX,
-sinX,
0,
-sinY,
cosY * sinX,
cosX * cosY,
0,
0,
0,
0,
1,
];
};
export const rotateXZ = (dx, dy) => {
const radX = (Math.PI / 180) * dx;
const cosX = Math.cos(radX);
const sinX = Math.sin(radX);
const radY = (Math.PI / 180) * dy;
const cosY = Math.cos(radY);
const sinY = Math.sin(radY);
return [
cosX,
-cosY * sinX,
sinX * sinY,
0,
sinX,
cosX * cosY,
-sinY * cosX,
0,
0,
sinY,
cosY,
0,
0,
0,
0,
1,
];
};
//source: https://gist.github.com/jmurzy/0d62c0b5ea88ca806c16b5e8a16deb6a#file-foldview-transformutil-transformorigin-js
export const transformOrigin = (matrix, origin) => {
const { x, y, z } = origin;
const translate = MatrixMath.createIdentityMatrix();
MatrixMath.reuseTranslate3dCommand(translate, x, y, z);
MatrixMath.multiplyInto(matrix, translate, matrix);
const untranslate = MatrixMath.createIdentityMatrix();
MatrixMath.reuseTranslate3dCommand(untranslate, -x, -y, -z);
MatrixMath.multiplyInto(matrix, matrix, untranslate);
};
这是 SmallBox.js:
import React from 'react';
import {
View,
Text,
StyleSheet,
TouchableOpacity,
TouchableHighlight,
} from 'react-native';
export default function SmallBox({ num, position, color }) {
return (
<TouchableOpacity
style={styles.smallBox}
onPress={() => console.log(color, position)}
>
<Text>{num}</Text>
</TouchableOpacity>
);
}
const styles = StyleSheet.create({
smallBox: {
margin: 0.2,
height: 100 / 3,
width: 100 / 3,
borderWidth: 1,
justifyContent: 'center',
alignItems: 'center',
},
});