在不改变方向的情况下反应 Native Expo 方向监听器
React Native Expo orientation listener without changing orientation
我正在尝试检测我的 React Native 应用程序的当前方向,而无需更改方向。我做了一个相机应用程序,我只想在方向改变时翻转图标。现在我无法在不改变实际方向的情况下使用 ScreenOrientation.addOrientationChangeListener(listener)
。有什么解决办法吗?
如果我没理解错的话,要求是获取设备方向,即使实际方向没有改变,因为它被 orientation
锁定。
您可以使用 DeviceMotion
module to get the device rotation (Euler angle)
DeviceMotion.addListener(({rotation}) => {
const alpha = Math.abs(rotation.alpha);
this.setState({
orientation: alpha > 3 || (alpha > 0 && alpha < 0.5) ? 'landscape' : 'protrait'
});
});
现场演示:https://expo.io/@moshfeu/snack-dc115508-fab4-4be4-818a-5a03f89725bd
旧答案
如果我没理解错的话,你想在应用加载时获取当前方向,而不需要用户改变方向。
如果是这样,您可以从ScreenOrientation.getOrientationAsync()
which will return a Promise
with one of the possible values
获取
ScreenOrientation.getOrientationAsync().then(data => this.setState({data}));
我发现 another solution on GitHub, similar to 使用 DeviceMotion,但使用 gamma 和 beta(x 和 y 轴)而不是 alpha(z 轴)来确定设备的旋转。就我而言,我使用这种技术获得了更令人满意的结果。
isPortrait(gamma: number, beta: number) {
const ABSOLUTE_GAMMA = Math.abs(gamma);
const ABSOLUTE_BETA = Math.abs(beta);
const isGammaNegative = Math.sign(gamma) === -1;
if (ABSOLUTE_GAMMA <= 0.04 && ABSOLUTE_BETA <= 0.24) {
//Portrait mode, on a flat surface.
return true;
} else
if (
(ABSOLUTE_GAMMA <= 1.0 || ABSOLUTE_GAMMA >= 2.3) &&
ABSOLUTE_BETA >= 0.5
) {
//General Portrait mode, accounting for forward and back tilt on the top of the phone.
return true;
} else {
if (isGammaNegative) {
//Landscape mode with the top of the phone to the left.
return false;
} else {
//Landscape mode with the top of the phone to the right.
return false;
}
}
}
我在 componentDidMount 方法的侦听器中调用它 (it's good practice to check sensor availability first with DeviceMotion.isAvailableAsync()):
const sensorAvailable = await DeviceMotion.isAvailableAsync();
if (sensorAvailable) {
DeviceMotion.addListener(({ rotation }) => {
const { gamma, beta } = rotation;
this.setState({
orientation: this.isPortrait(gamma, beta) ? 'portrait' : 'landscape'
});
});
}
为了让它正常工作,我需要:
- 将代码添加到 componentDidMount:
async componentDidMount() {
if (await DeviceMotion.isAvailableAsync()) {
DeviceMotion.addListener(this.calculateRotation)
}
// ...
}
- 将代码添加到 componentWillUnmount:
componentWillUnmount() {
DeviceMotion.removeAllListeners()
}
- 添加一个方法来计算基于beta和gamma的旋转,基于a helpful answer on github:
calculateRotation = ({rotation: {beta, gamma}}) => {
let absGamma = Math.abs(gamma)
let absBeta = Math.abs(beta)
let rotate = 0
if (absGamma <= 0.04 && absBeta <= 0.24) {
// Portrait mode, on a flat surface.
rotate = 0
} else if ((absGamma <= 1.0 || absGamma >= 2.3) && absBeta >= 0.5) {
// General Portrait mode, accounting for forward and back tilt on the top of the phone.
rotate = 0
} else {
if (gamma < 0) {
// Landscape mode with the top of the phone to the left.
rotate = -90
} else {
// Landscape mode with the top of the phone to the right.
rotate = 90
}
}
this.setState({rotate})
}
- 当我需要获取当前旋转时,调用
this.state.rotate
。这表明 right-side-up 图像需要旋转多少照片。
matchPhotoRotation = (photo) => {
const {rotate} = this.state
if (rotate === 0) return photo
return ImageManipulator.manipulateAsync(
photo.uri,
[{rotate}],
)
}
我正在尝试检测我的 React Native 应用程序的当前方向,而无需更改方向。我做了一个相机应用程序,我只想在方向改变时翻转图标。现在我无法在不改变实际方向的情况下使用 ScreenOrientation.addOrientationChangeListener(listener)
。有什么解决办法吗?
如果我没理解错的话,要求是获取设备方向,即使实际方向没有改变,因为它被 orientation
锁定。
您可以使用 DeviceMotion
module to get the device rotation (Euler angle)
DeviceMotion.addListener(({rotation}) => {
const alpha = Math.abs(rotation.alpha);
this.setState({
orientation: alpha > 3 || (alpha > 0 && alpha < 0.5) ? 'landscape' : 'protrait'
});
});
现场演示:https://expo.io/@moshfeu/snack-dc115508-fab4-4be4-818a-5a03f89725bd
旧答案
如果我没理解错的话,你想在应用加载时获取当前方向,而不需要用户改变方向。
如果是这样,您可以从ScreenOrientation.getOrientationAsync()
which will return a Promise
with one of the possible values
ScreenOrientation.getOrientationAsync().then(data => this.setState({data}));
我发现 another solution on GitHub, similar to
isPortrait(gamma: number, beta: number) {
const ABSOLUTE_GAMMA = Math.abs(gamma);
const ABSOLUTE_BETA = Math.abs(beta);
const isGammaNegative = Math.sign(gamma) === -1;
if (ABSOLUTE_GAMMA <= 0.04 && ABSOLUTE_BETA <= 0.24) {
//Portrait mode, on a flat surface.
return true;
} else
if (
(ABSOLUTE_GAMMA <= 1.0 || ABSOLUTE_GAMMA >= 2.3) &&
ABSOLUTE_BETA >= 0.5
) {
//General Portrait mode, accounting for forward and back tilt on the top of the phone.
return true;
} else {
if (isGammaNegative) {
//Landscape mode with the top of the phone to the left.
return false;
} else {
//Landscape mode with the top of the phone to the right.
return false;
}
}
}
我在 componentDidMount 方法的侦听器中调用它 (it's good practice to check sensor availability first with DeviceMotion.isAvailableAsync()):
const sensorAvailable = await DeviceMotion.isAvailableAsync();
if (sensorAvailable) {
DeviceMotion.addListener(({ rotation }) => {
const { gamma, beta } = rotation;
this.setState({
orientation: this.isPortrait(gamma, beta) ? 'portrait' : 'landscape'
});
});
}
为了让它正常工作,我需要:
- 将代码添加到 componentDidMount:
async componentDidMount() {
if (await DeviceMotion.isAvailableAsync()) {
DeviceMotion.addListener(this.calculateRotation)
}
// ...
}
- 将代码添加到 componentWillUnmount:
componentWillUnmount() {
DeviceMotion.removeAllListeners()
}
- 添加一个方法来计算基于beta和gamma的旋转,基于a helpful answer on github:
calculateRotation = ({rotation: {beta, gamma}}) => {
let absGamma = Math.abs(gamma)
let absBeta = Math.abs(beta)
let rotate = 0
if (absGamma <= 0.04 && absBeta <= 0.24) {
// Portrait mode, on a flat surface.
rotate = 0
} else if ((absGamma <= 1.0 || absGamma >= 2.3) && absBeta >= 0.5) {
// General Portrait mode, accounting for forward and back tilt on the top of the phone.
rotate = 0
} else {
if (gamma < 0) {
// Landscape mode with the top of the phone to the left.
rotate = -90
} else {
// Landscape mode with the top of the phone to the right.
rotate = 90
}
}
this.setState({rotate})
}
- 当我需要获取当前旋转时,调用
this.state.rotate
。这表明 right-side-up 图像需要旋转多少照片。
matchPhotoRotation = (photo) => {
const {rotate} = this.state
if (rotate === 0) return photo
return ImageManipulator.manipulateAsync(
photo.uri,
[{rotate}],
)
}