当活动方向被锁定时检测设备方向
Posted
技术标签:
【中文标题】当活动方向被锁定时检测设备方向【英文标题】:Detect device orientation when Activity orientation is locked 【发布时间】:2014-04-17 10:51:33 【问题描述】:在我的项目中,我必须锁定活动的方向。 (我无法重新创建活动)
我想在用户更改设备方向时显示一条消息: “视图被锁定在这个位置......”
我可以使用此代码轻松锁定方向:
if(version >= Build.VERSION_CODES.JELLY_BEAN_MR2)
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);
else
int orientation = activity.getResources().getConfiguration().orientation;
if(orientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
else
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
使用此代码,视图被锁定,但我无法检测到用户何时更改设备方向。
如果我使用以下代码:
@Override
public void onConfigurationChanged(Configuration newConfig)
//Check if the orientation has change
if(newConfig.orientation != mOrientation)
Toast.makeText(this, "Message for user", Toast.LENGTH_SHORT).show();
//Try to lock the view but not working
newConfig.orientation = mOrientation;
//Obligatory line that reload the view and cannot be delete
//(is the biggest prolem of this code)
super.onConfigurationChanged(newConfig);
如果有人知道锁定视图并检测设备方向变化的方法,那真的会对我有所帮助。
谢谢大家
【问题讨论】:
【参考方案1】:也可以用SensorManager
解决。这是一个简单的演示,展示了如何将锁定活动的图像方向保持正确为纵向:
主活动:
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Surface;
import android.widget.ImageView;
public class MainActivity extends AppCompatActivity
private ImageView img;
private SensorManager mSensorManager;
private Sensor mOrientation;
float value_0 = -10000;
float value_1 = -10000;
private SensorEventListener mOrientationSensorListener = new SensorEventListener()
int orientation = -1;
@Override
public void onSensorChanged(SensorEvent event)
int value ;
if(value_0 == event.values[0] && value_1==event.values[1])
return;
// Log.d("values:", "values:" + event.values[0]+", "+event.values[1]);
if (event.values[1] > 0 && event.values[0] == 0)
value = Surface.ROTATION_0;//portrait
if (orientation != value)
updateImageRotation(value);
Log.d("orientation", "portrait + update");
orientation = value;
Log.d("orientation", "portrait ");
if (event.values[1] < 0 && event.values[0] == 0)
value = Surface.ROTATION_180;//portrait reverse
if (orientation != value)
updateImageRotation(value);
Log.d("orientation", "portrait reverse + update");
orientation = value;
Log.d("orientation", "portrait reverse");
if (event.values[0] > 0 && event.values[1] == 0)
value = Surface.ROTATION_90;//portrait reverse
if (orientation != value)
updateImageRotation(value);
Log.d("orientation", "landscape + update");
orientation = value;
Log.d("orientation", "landscape");
if (event.values[0] < 0 && event.values[1] == 0)
value = Surface.ROTATION_270;//portrait reverse
if (orientation != value)
updateImageRotation(value);
Log.d("orientation", "landscape + update");
orientation = value;
Log.d("orientation", "landscape reverse");
value_0=event.values[0];
value_1=event.values[1];
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy)
;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
img = (ImageView) findViewById(R.id.img);
// Get sensor manager
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
// Get the default sensor of specified type
mOrientation = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
@Override
protected void onResume()
super.onResume();
if (mOrientation != null)
mSensorManager.registerListener(mOrientationSensorListener, mOrientation,
SensorManager.SENSOR_DELAY_GAME);
@Override
protected void onPause()
super.onPause();
if (mOrientation != null)
mSensorManager.unregisterListener(mOrientationSensorListener);
private void updateImageRotation(int degree)
switch (degree)
case Surface.ROTATION_0:
img.setRotation(0);
break;
case Surface.ROTATION_90:
img.setRotation(90);
break;
case Surface.ROTATION_180:
img.setRotation(180);
break;
case Surface.ROTATION_270:
img.setRotation(270);
break;
在清单中。方向锁定为portrait
,并且需要传感器作为功能
manifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest package="permissionsmngr.com.apipas.rotationmanage"
xmlns:android="http://schemas.android.com/apk/res/android">
<uses-feature
android:name="android.hardware.sensor.accelerometer"
android:required="true"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:screenOrientation="portrait"
>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:id="@+id/activity_main"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_
android:layout_
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="permissionsmngr.com.apipas.rotationmanage.MainActivity">
<ImageView
android:layout_centerInParent="true"
android:id="@+id/img"
android:layout_
android:layout_
android:src="@mipmap/ic_launcher"
/>
</RelativeLayout>
【讨论】:
为什么选择 SensorEventListener 而不是 SensorEventListener2? @chinmish 没什么特别的 .. 只是对接收 onFlushCompleted 不感兴趣 您好,这是如何工作的?我的意思是,我看到 event.values[0] 和 event.values[1] 从正数变为负数,反之亦然,但它们永远不会完全 == 0【参考方案2】:下面的代码对我有用。
MainActivity.java:
public class MainActivity extends Activity
@Override
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
startService( new Intent(this, Receiver.class) );
BackgroundService.java
public class Receiver extends Service
private static final String BCAST_CONFIGCHANGED = "android.intent.action.CONFIGURATION_CHANGED";
@Override
public IBinder onBind(Intent intent)
return null;
@Override
public void onCreate()
IntentFilter filter = new IntentFilter();
filter.addAction(BCAST_CONFIGCHANGED);
this.registerReceiver(mBroadcastReceiver, filter);
@Override
public void onDestroy()
@Override
public void onStart(Intent intent, int startid)
public BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver()
@Override
public void onReceive(Context context, Intent myIntent)
if ( myIntent.getAction().equals( BCAST_CONFIGCHANGED ) )
if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE)
else
;
Manifestfile.xml
<service android:name=".Receiver">
<intent-filter>
<action android:name="android.intent.action.CONFIGURATION_CHANGED"/>
</intent-filter>
</service>
【讨论】:
谢谢。但是这个解决方案的问题是,如果我锁定视图 CONFIGURATION_CHANGED 意图,就不再需要调用了。 (我认为当视图被锁定时改变设备的方向不要改变配置)【参考方案3】:您可以简单地使用OrientationEventListener
从传感器获取方向 (用 Kotlin 编写):
class MainActivity : AppCompatActivity()
private var orientationEventListener: OrientationEventListener? = null
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
...
orientationEventListener = object : OrientationEventListener(context)
override fun onOrientationChanged(orientation: Int)
// orientation is in degrees
// Show "The View is locked in this position ..." message if orientation is between 45° and 315°
viewModel.showViewIsLocked(orientation in 45..315)
override fun onResume()
super.onResume()
orientationEventListener?.enable()
override fun onPause()
orientationEventListener?.disable()
super.onPause()
【讨论】:
以上是关于当活动方向被锁定时检测设备方向的主要内容,如果未能解决你的问题,请参考以下文章