简体   繁体   English

活动方向在 Android 上自动更改

[英]Activity orientation changes automatically on Android

I'm developing a mobile application based on Android with minSdkVersion=15 .我正在使用minSdkVersion=15开发基于 Android 的移动应用程序。 I would like to support both orientations for tablets and only portrait for smartphones.我想支持平板电脑的两种方向,而智能手机只支持纵向。 Everything works like a charm but I'm experiencing a little bug that is driving me crazy.一切都像魅力一样,但我遇到了一个让我发疯的小错误。 When smartphone is in landscape mode and I try to trigger a new Activity, it opens in landscape mode for a while and then autorotates to portrait.当智能手机处于横向模式并且我尝试触发新活动时,它会以横向模式打开一段时间,然后自动旋转为纵向。 Each one of my activities extend a GeneralActivity class:我的每一项活动都扩展了一个 GeneralActivity 类:

public class GeneralActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // If smartphone lock orientation to portrait
        if (!Helper.isTablet(this.getApplicationContext())){
            this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        }
    }
}

I detect tablets with this function:我检测具有此功能的平板电脑:

public class Helper {
    public static boolean isTablet(Context context){
        Configuration config = context.getResources().getConfiguration()
        return config.smallestScreenWidthDp >= 600;
    }
}

I choose not to specify android:screenOrientation inside Manifest.xml because in that way I'm able to support all interface orientation for tablets.我选择不在 Manifest.xml 中指定android:screenOrientation因为这样我就能够支持平板电脑的所有界面方向。 Am I missing something?我错过了什么吗?

EDIT编辑

I decided to apply the best practice suggested in the answer by Jonathan, but the issue I described is still here.我决定应用 Jonathan 在答案中建议的最佳实践,但我描述的问题仍然存在。 Here's my repo on github: https://github.com/giacmarangoni/Android-Orientation-Test这是我在 github 上的仓库: https : //github.com/giacmarangoni/Android-Orientation-Test

I had the same problem on Android N & O and found a solution.我在 Android N & O 上遇到了同样的问题并找到了解决方案。

I still use setRequestedOrientation in the onCreate method, but I've added this for every activity in the manifest:我仍然在 onCreate 方法中使用 setRequestedOrientation,但我已经为清单中的每个活动添加了这个:

android:screenOrientation="behind"

This makes sure that the activity launches with the same orientation as the previous activity.这可确保 Activity 以与前一个 Activity 相同的方向启动。 The setRequestedOrientation afterwards will override it, but if it's the same as the previous activity you don't see anything change as the user.之后的 setRequestedOrientation 将覆盖它,但如果它与之前的活动相同,您将看不到作为用户的任何变化。

I found the right way to solve this issue by using:我找到了解决这个问题的正确方法:

android:screenOrientation="locked"

in every activity declared in the manifest with this issue.在带有此问题的清单中声明的​​每个活动中。

And keep using setRequestedOrientation() programatically to define if landscape or portrait orientation within onCreate() method,并继续以编程方式使用setRequestedOrientation()来定义 onCreate() 方法中是横向还是纵向,

Btw, in your GitHub project, I just changed the manifest adding locked orientation like this and it finally worked:顺便说一句,在你的 GitHub 项目中,我只是改变了清单,添加了这样的locked方向,它终于奏效了:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.giacomomarangoni.orientationtest">

    <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="locked">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".OtherActivity"
            android:screenOrientation="locked">
        </activity>
    </application>
</manifest>

Hope it will help you too :)希望它也能帮助你:)

Here's a good way using resources and size qualifiers.这是使用资源和大小限定符的好方法。

Put this bool resource in res/values as bools.xml or whatever (file names don't matter here):将此 bool 资源作为 bools.xml 或其他内容放在 res/values 中(文件名在这里无关紧要):

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <bool name="portrait_only">true</bool>
</resources>

Put this one in res/values-sw600dp and res/values-xlarge:把这个放在 res/values-sw600dp 和 res/values-xlarge 中:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <bool name="portrait_only">false</bool>
</resources>

See this supplemental answer for help adding these directories and files in Android Studio.有关在 Android Studio 中添加这些目录和文件的帮助,请参阅此补充答案。

Then, in the onCreate method of your Activities you can do this:然后,在您的活动的 onCreate 方法中,您可以执行以下操作:

if(getResources().getBoolean(R.bool.portrait_only)){
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}

Devices that are more than 600 dp in the smallest width direction, or x-large on pre-Android 3.2 devices (tablets, basically) will behave like normal, based on sensor and user-locked rotation, etc. Everything else (phones, pretty much) will be portrait only.在最小宽度方向上超过 600 dp 的设备,或在 Android 3.2 之前的设备(基本上是平板电脑)上的 x-large 将表现得像正常一样,基于传感器和用户锁定的旋转等。其他一切(手机,漂亮很多)将仅是肖像。

Source: Original answer来源: 原始答案

I have this solution working for me.我有这个解决方案对我有用。 In your manifest declare screen orientations portrait在您的清单中声明屏幕方向纵向

<activity android:name=".activities.MainActivity"
        android:screenOrientation="portrait">

        <intent-filter>
            <action android:name="android.intent.action.MAIN"/>

            <category android:name="android.intent.category.LAUNCHER"/>
        </intent-filter>
    </activity>

Then in your base activity in your onCreate before you call super.onCreate if the device is a tablet set the orientation to unspecified.然后在您的onCreate中的基本活动中,如果设备是平板电脑,则在调用 super.onCreate 之前将方向设置为未指定。

@Override
protected void onCreate(Bundle savedInstanceState) {
    if (!getResources().getBoolean(R.bool.portrait_only)) {
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
    }
    super.onCreate(savedInstanceState);
}

From the docs:从文档:

Unspecified: No preference specified: let the system decide the best orientation.未指定:未指定偏好:让系统决定最佳方向。 This will either be the orientation selected by the activity below, or the user's preferred orientation if this activity is the bottom of a task.这将是由下面的活动选择的方向,或者如果此活动是任务的底部,则是用户的首选方向。 If the user explicitly turned off sensor based orientation through settings sensor based device rotation will be ignored.如果用户通过设置基于传感器的设备旋转明确关闭基于传感器的方向将被忽略。 If not by default sensor based orientation will be taken into account and the orientation will changed based on how the user rotates the device.如果不是,默认情况下将考虑基于传感器的方向,并且方向将根据用户旋转设备的方式而改变。

This worked for me and so far i haven't found any drawbacks.这对我有用,到目前为止我还没有发现任何缺点。 I have only tested this in emulators and it doesn't seem that the app is starting in portrait and then rotating like it happened with the other solutions on phones.我只在模拟器中对此进行了测试,似乎该应用程序并没有像在手机上的其他解决方案那样以纵向启动然后旋转。 Anyway, i'd prefer phones to be working better than tablets just because they're used more.无论如何,我更喜欢手机比平板电脑工作得更好,因为它们使用得更多。

If you find anything not working with this solution hit me up!如果您发现任何不适用于此解决方案,请联系我!

I also faced same problem for Android N devices.对于 Android N 设备,我也遇到了同样的问题。 So to support both orientations for tablets and only portrait for phones I did the following trick:因此,为了支持平板电脑的两个方向和手机的仅纵向,我做了以下技巧:

  1. Set portrait to each activity in Manifest.为 Manifest 中的每个活动设置肖像。 Looks bad, but in this case screen will not autorotate: android:screenOrientation="portrait"看起来很糟糕,但在这种情况下屏幕不会自动旋转: android:screenOrientation="portrait"

  2. In your BaseActivity set:在您的 BaseActivity 集中:

     @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (isTablet(){ setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR); } } protected boolean isTablet() { return getResources().getBoolean(R.bool.tablet); }

In your base activity you can put something like this:在您的基本活动中,您可以放置​​如下内容:

/*  Device types. */
static int MOBILE_DEVICE = 0;
static int SEVEN_INCH_TABLET = 1;
static int TEN_INCH_TABLET = 2;

private static int deviceType = MOBILE_DEVICE;
private boolean deviceTypeDetermined = false;


@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
@Override
protected void onCreate(Bundle savedInstanceState) {

    if ( ! deviceTypeDetermined) setDeviceType();

    /* Screen rotation only for tablets. */
    if (getDeviceType() < SEVEN_INCH_TABLET) {
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        lockScreenOrientation();

    ......
}



// ---------------------------------------------------------------------------------------------
static int getDeviceType() {
    return deviceType;
}
// ---------------------------------------------------------------------------------------------


// ---------------------------------------------------------------------------------------------
private void setDeviceTypeDetermined() {
    this.deviceTypeDetermined = true;
}
// ---------------------------------------------------------------------------------------------


// ---------------------------------------------------------------------------------------------
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
private void setDeviceType() {

    /*
        Let's invest on what kind of screen our APP is invited...

        We only make a difference in 10", 7" tablets and the rest...
    */

    Display mDisplay = getWindowManager().getDefaultDisplay();
    Point mScreenResolution = new Point();

    mDisplay.getRealSize(mScreenResolution);

    int mWidthPixels = mScreenResolution.x;
    int mHeightPixels = mScreenResolution.y;

    DisplayMetrics mMetrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(mMetrics);

    float mWidthDpi = mMetrics.xdpi;
    float mHeightDpi = mMetrics.ydpi;

    float mWidthInches = mWidthPixels / mWidthDpi;
    float mHeightInches = mHeightPixels / mHeightDpi;



    double mDiagonalInches = Math.sqrt(
            (mWidthInches * mWidthInches)
                    + (mHeightInches * mHeightInches));


    if (mDiagonalInches >= 9) {

        /*
            A tablet with 8" x 5" is called a 10", but it is in fact
            9.43398". Interesting that this kind of things happens in
            the world of informatics.... ;)
        */

        MyBaseAppCompatActivity.deviceType = TEN_INCH_TABLET;
    }

    else if (mDiagonalInches >= 7) {
        MyBaseAppCompatActivity.deviceType = SEVEN_INCH_TABLET;
    }

    else
    {
        MyBaseAppCompatActivity.deviceType = MOBILE_DEVICE;
    }


    setDeviceTypeDetermined();
}
// ---------------------------------------------------------------------------------------------


// ---------------------------------------------------------------------------------------------
void lockScreenOrientation() {

    /*  Screen rotation only for tablets. */
    if (deviceType < SEVEN_INCH_TABLET ) return;

    setRequestedOrientation(getResources().getConfiguration().orientation);
}
// ---------------------------------------------------------------------------------------------


// ---------------------------------------------------------------------------------------------
void unlockScreenOrientation() {

    /*  Screen rotation only for tablets. */
    if (deviceType < SEVEN_INCH_TABLET ) return;

    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
}
// ---------------------------------------------------------------------------------------------

And in your activities in the onCreate:在你的 onCreate 活动中:

// ---------------------------------------------------------------------------------------------
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
protected void onCreate(Bundle savedInstanceState) {
    // -----------------------------------------------------------------------------------------
    super.onCreate(savedInstanceState);

    if (getDeviceType() >= SEVEN_INCH_TABLET) unlockScreenOrientation();

    setContentView(R.layout.main_activity);

    .........

// ---------------------------------------------------------------------------------------------

在menifest文件的所有活动标签中添加这一行...

 android:screenOrientation="portrait"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM