当活动方向被锁定时检测设备方向

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,并且需要传感器作为功能 ma​​nifest.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()
    


【讨论】:

以上是关于当活动方向被锁定时检测设备方向的主要内容,如果未能解决你的问题,请参考以下文章

iOS设备方向无视方向锁定

即使设备已锁定方向,如何进行方向检测

如何在不锁定活动方向的情况下锁定片段方向?

如何在纵向锁定设备时获取设备方向

按钮锁定到指南。为啥位置会随着方向变化?

如何为 React Native 锁定设备方向