[英]Get phone orientation when locked into one orientation
這可能很容易與另一個問題重復,我只是在努力弄清楚要搜索什么。
我的相機應用程序被鎖定在橫向模式(在清單中),如下所示:
android:screenOrientation="landscape"
但是,我想在設備旋轉成肖像時仍然旋轉一些UI元素(盡管android仍然會在景觀中考慮它,但這是故意的)。
所以我試過這個來檢查方向
int rotation = this.getWindowManager().getDefaultDisplay()
.getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0:
Log.d("Rotation", "0");
break;
case Surface.ROTATION_90:
Log.d("Rotation", "90");
break;
case Surface.ROTATION_180:
Log.d("Rotation", "180");
break;
case Surface.ROTATION_270:
Log.d("Rotation", "270");
break;
}
不幸的是,無論我如何轉動手機,它總會返回90。 是否有更強大的方式來獲得方向,無論Android“認為”的方向是什么?
所以在我想到它之后,我意識到我可以實現一個與Android本身用來確定方向類似的算法。 我使用onSenseorChanged回調來做到這一點
public static final int UPSIDE_DOWN = 3;
public static final int LANDSCAPE_RIGHT = 4;
public static final int PORTRAIT = 1;
public static final int LANDSCAPE_LEFT = 2;
public int mOrientationDeg; //last rotation in degrees
public int mOrientationRounded; //last orientation int from above
private static final int _DATA_X = 0;
private static final int _DATA_Y = 1;
private static final int _DATA_Z = 2;
private int ORIENTATION_UNKNOWN = -1;
@Override
public void onSensorChanged(SensorEvent event)
{
Log.d(TAG, "Sensor Changed");
float[] values = event.values;
int orientation = ORIENTATION_UNKNOWN;
float X = -values[_DATA_X];
float Y = -values[_DATA_Y];
float Z = -values[_DATA_Z];
float magnitude = X*X + Y*Y;
// Don't trust the angle if the magnitude is small compared to the y value
if (magnitude * 4 >= Z*Z) {
float OneEightyOverPi = 57.29577957855f;
float angle = (float)Math.atan2(-Y, X) * OneEightyOverPi;
orientation = 90 - (int)Math.round(angle);
// normalize to 0 - 359 range
while (orientation >= 360) {
orientation -= 360;
}
while (orientation < 0) {
orientation += 360;
}
}
//^^ thanks to google for that code
//now we must figure out which orientation based on the degrees
Log.d("Oreination", ""+orientation);
if (orientation != mOrientationDeg)
{
mOrientationDeg = orientation;
//figure out actual orientation
if(orientation == -1){//basically flat
}
else if(orientation <= 45 || orientation > 315){//round to 0
tempOrientRounded = 1;//portrait
}
else if(orientation > 45 && orientation <= 135){//round to 90
tempOrientRounded = 2; //lsleft
}
else if(orientation > 135 && orientation <= 225){//round to 180
tempOrientRounded = 3; //upside down
}
else if(orientation > 225 && orientation <= 315){//round to 270
tempOrientRounded = 4;//lsright
}
}
if(mOrientationRounded != tempOrientRounded){
//Orientation changed, handle the change here
mOrientationRounded = tempOrientRounded;
}
}
它看起來比現在更復雜,但只知道它有效(我會說同樣好的系統)。 不要忘記在onResume和onPause中注冊傳感器更改事件監聽器以獲取加速度計
對於檢測方向,我使用它來注冊到sensormanager:
mSensorOrientation = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
mSensorManager.registerListener(this, mSensorOrientation, SensorManager.SENSOR_DELAY_NORMAL);
然后這個用於檢測方向的變化,在評論中你可以把你自己的方法實現。
常量:
public static final int LYING = 0;
public static final int LANDSCAPE_RIGHT = 1;
public static final int PORTRAIT = 2;
public static final int LANDSCAPE_LEFT = 3;
public void onSensorChanged(SensorEvent event) {
Sensor sensorEvent = event.sensor;
if ((sensorEvent.getType() == Sensor.TYPE_ORIENTATION)) {
float [] eventValues = event.values;
// current orientation of the phone
float xAxis = eventValues[1];
float yAxis = eventValues[2];
if ((yAxis <= 25) && (yAxis >= -25) && (xAxis >= -160)) {
if (previousOrientation != PORTRAIT){
previousOrientation = PORTRAIT;
// CHANGED TO PORTRAIT
}
} else if ((yAxis < -25) && (xAxis >= -20)) {
if (previousOrientation != LANDSCAPE_RIGHT){
previousOrientation = LANDSCAPE_RIGHT;
// CHANGED TO LANDSCAPE RIGHT
}
} else if ((yAxis > 25) && (xAxis >= -20)){
if (previousOrientation != LANDSCAPE_LEFT){
previousOrientation = LANDSCAPE_LEFT;
// CHANGED TO LANDSCAPE LEFT
}
}
}
}
在做了一些研究並嘗試了一些東西之后,當我將Sensor設置為:
mSensorOrientation = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
不推薦使用Sensor.TYPE_ORIENTATION,根據來自不同人員的一些示例代碼檢索方向,我給出了不良結果。 我真的不知道它是否合適,但它對我有用。
@panavtec對API 23的回復,使用此作為參考
class MyActivity extends Activity implements SensorEventListener {
private SensorManager sensorManager;
private float[] lastMagFields = new float[3];;
private float[] lastAccels = new float[3];;
private float[] rotationMatrix = new float[16];
private float[] orientation = new float[4];
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
}
protected void onResume() {
super.onResume();
sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD), SensorManager.SENSOR_DELAY_GAME);
sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);
}
protected void onPause() {
super.onPause();
sensorManager.unregisterListener(this);
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
public void onSensorChanged(SensorEvent event) {
switch (event.sensor.getType()) {
case Sensor.TYPE_ACCELEROMETER:
System.arraycopy(event.values, 0, lastAccels, 0, 3);
break;
case Sensor.TYPE_MAGNETIC_FIELD:
System.arraycopy(event.values, 0, lastMagFields, 0, 3);
break;
default:
return;
}
if (SensorManager.getRotationMatrix(rotationMatrix, null, lastAccels, lastMagFields)) {
SensorManager.getOrientation(rotationMatrix, orientation);
float xAxis = (float) Math.toDegrees(orientation[1]);
float yAxis = (float) Math.toDegrees(orientation[2]);
int orientation = Configuration.ORIENTATION_UNDEFINED;
if ((yAxis <= 25) && (yAxis >= -25) && (xAxis >= -160)) {
Log.d(TAG, "Portrait");
orientation = Configuration.ORIENTATION_PORTRAIT;
} else if ((yAxis < -25) && (xAxis >= -20)) {
Log.d(TAG, "Landscape Right");
orientation = Configuration.ORIENTATION_LANDSCAPE;
} else if ((yAxis > 25) && (xAxis >= -20)){
orientation = Configuration.ORIENTATION_LANDSCAPE;
Log.d(TAG, "Landscape Left");
}
}
}
}
這是@Jameo答案的略微修改的Kotlin版本。 我需要度數來計算具有鎖定方向的活動中的相機旋轉。 請你也投票給他。
private var rotationDeg: Int = 0
private var rotationRoundedClockwise: Int = 0
override fun onSensorChanged(event: SensorEvent) {
Timber.d("Sensor Changed")
val newRotationDeg = calculateNewRotationDegree(event)
//^^ thanks to google for that code
// now we must figure out which orientation based on the degrees
Timber.d("rotation: $newRotationDeg")
if (newRotationDeg != rotationDeg) {
rotationDeg = newRotationDeg
rotationRoundedClockwise = calculateRoundedRotation(newRotationDeg)
}
Timber.d("rotationRoundedClockwise: $rotationRoundedClockwise")
}
private val X_AXIS_INDEX = 0
private val Y_AXIS_INDEX = 1
private val Z_AXIS_AXIS = 2
private val ORIENTATION_UNKNOWN = -1
private fun calculateRoundedRotation(newRotationDeg: Int): Int {
return if (newRotationDeg <= 45 || newRotationDeg > 315) { // round to 0
0 // portrait
} else if (newRotationDeg in 46..135) { // round to 90
90 // clockwise landscape
} else if (newRotationDeg in 136..225) { // round to 180
180 // upside down portrait
} else if (newRotationDeg in 226..315) { // round to 270
270 // anticlockwise landscape
} else {
0
}
}
private fun calculateNewRotationDegree(event: SensorEvent): Int {
val values = event.values
var newRotationDeg = ORIENTATION_UNKNOWN
val X = -values[X_AXIS_INDEX]
val Y = -values[Y_AXIS_INDEX]
val Z = -values[Z_AXIS_AXIS]
val magnitude = X * X + Y * Y
// Don't trust the angle if the magnitude is small compared to the y value
if (magnitude * 4 >= Z * Z) {
val ONE_EIGHTY_OVER_PI = 57.29577957855f
val angle = Math.atan2((-Y).toDouble(), X.toDouble()).toFloat() * ONE_EIGHTY_OVER_PI
newRotationDeg = 90 - Math.round(angle)
// normalize to 0 - 359 range
while (newRotationDeg >= 360) {
newRotationDeg -= 360
}
while (newRotationDeg < 0) {
newRotationDeg += 360
}
}
return newRotationDeg
}
private fun getCameraRotation(): Int {
return when (rotationRoundedClockwise) {
0 -> 90
90 -> 180
180 -> 270
270 -> 0
else -> 90
}
}
這是如何傾聽事件。
override fun onCreate() {
super.onCreate()
(activity?.getSystemService(SENSOR_SERVICE) as? SensorManager)?.let {
sensorManager = it
}
}
override fun onResume() {
super.onResume()
sensorManager.registerListener(this,
sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_NORMAL)
}
override fun onPause() {
super.onPause()
sensorManager.unregisterListener(this)
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.