Activity横竖屏切换的那些事

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gdutxiaoxu/article/details/62235974

讲解之前需要说明的是

  • 旋转屏幕:在系统的自动旋转屏幕开启的情况下,我们旋转屏幕
  • 手动设置屏幕:我们自己去调用Activity的 setRequestedOrientation 方法。

设置屏幕的方向

简介

描述

unspecified

默认值。系统自动选择屏幕方向

behind

跟activity堆栈中的下面一个activity的方向一致

landscape

横屏方向,显示的宽比高长

portrait

竖屏方向,显示的高比宽长

sensor

由设备的物理方向传感器决定,如果用户旋转设备,这屏幕就会横竖屏切换

nosensor

忽略物理方向传感器,这样就不会随着用户旋转设备而横竖屏切换了(”unspecified”设置除外)

user

用户当前首选的方向

reverseLandscape

API 9 以上,反向横屏

reversePortrait

API 9 以上,反向竖屏

sensorLandscape

API 9 以上,横屏,但是可以根据 物理方向传感器来切换正反向横屏

sensorPortrait

API 9 以上,竖屏,但是可以根据 物理方向传感器来切换正反向竖屏

fullSensor

API 9 以上,上下左右四个方向,由物理方向传感器决定

locked

API 18 以上,锁死当前屏幕的方向

官网文档地址

第一种

我们可以在AndroidManifest 清单文件里面制定Activity的方向

<activity
    android:name=".view.main.MainActivity"

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

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

这样横竖屏切换的时候不会重新创建Activity

第二种

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

Android:android:configChanges

如果我们不配置configuration ,当 configuration 发生变化的时候,activity会自动处理它。反之,如果我们配置了相应的 configuration,当新的 configuration 发生变化的时候,会回调 Activity 的 onConfigurationChanged() 方法。

下面我们一起来看一下几个常用的值得介绍,其他不常用的hi请自行查阅文档。官网地址:

描述

keyboardHidden

键盘的可访问性发生变化——例如:用户发现了硬件键盘。

orientation

屏幕方向发生变化——用户旋转了屏幕。注意:如果应用程序的目标API级别是13或更高(通过属性minSdkVersion和属性targetSdkVersion声明),你也需要声明配置项screenSize,因为这将在设备选择肖像和屏幕方向时发生改变。

screenLayout

屏幕布局发生变化——这个会导致显示不同的Activity。屏幕方向发生变化——用户旋转了屏幕。注意:如果应用程序的目标API级别是13或更高(通过属性minSdkVersion和属性targetSdkVersion声明),你也需要声明配置项screenSize,因为这将在设备选择肖像和屏幕方向时发生改变。

screenSize

当前可用屏幕大小发生变化。这代表一个当前可用大小的变化,和当前的比率相关,因此当用户选择不同的画面和图像,会发生变化。然而,如果你的程序目标API级别是12或更低,你的Activity总是会自己处理这个配置变化(这个变化不会引起Activity的重启,甚至在Android 3.2或更新的设备上)。在API级别13里加入的。

android:configChanges 常用配置

在Android 3.2以后,如果我们进行下列的配置 ,这样的话横竖屏不会重新创建Activity,但是会调用 onConfigurationChanged()方法

<activity
    android:name=".view.main.MainActivity"
    android:configChanges="keyboardHidden|orientation|screenSize"
    >
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>

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

在api 3.2 以前,我们只需这样配置即可,android:configChanges=”keyboardHidden|orientation”。

<activity
    android:name=".view.main.MainActivity"
    android:configChanges="keyboardHidden|orientation"
    >
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>

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

小结

当我们进行了上述的配置,

  • 竖屏 》 横屏 onConfigurationChanged()方法会调用一次
  • 横屏 》 竖屏 onConfigurationChanged()方法也会调用一次

因此我们通常可以进行相应的处理

public void onConfigurationChanged(Configuration newConfig) {  

    super.onConfigurationChanged(newConfig);  

    if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {  
        // 加入横屏要处理的代码  
    } else if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {  
        // 加入竖屏要处理的代码  
    }  
}

如果我们同时设置了 android:configChanges=”keyboardHidden|orientation|screenSize” 和 android:screenOrientation=”portrait”,那又会是怎样的呢?

如果我们打开系统的自动旋转屏幕,旋转屏幕,系统不会发生变化,也不会调用 Activity 的 onConfigurationChanged 方法。

当我们手动调用 setRequestedOrientation() 方法去改变屏幕的方向的时候,还是会调用 onConfigurationChanged 方法的


扩展

设置全屏模式

// 去掉ActionBar
requestWindowFeature(Window.FEATURE_NO_TITLE);  
// 设置全屏
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);

在实际项目中,我们通常会固定我们应用的屏幕方向,只对一些特定的需要切换屏幕的Activity做处理,那我们如何统一设置屏幕的方向呢?

  • 第一种方法,复制张贴,在AndroidManifest清单文件里面的每一个Activity标签增加如下标签。
<activity android:name=".MainActivity"
          android:screenOrientation="portrait"
         >

</activity>
  • 第二种方法,刚开始我直接在 AppTheme 里面 设置 android:screenOrientation,但是没有效果,刚开始我也很纳闷,后面查阅了官网文档,描述如下,才解决了疑问. Specify the orientation an activity should be run in. If not specified, it will run in the current preferred orientation of the screen. This attribute is supported by the element.
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="android:screenOrientation">portrait</item>
</style>

即这种方法不可取

  • 第三种方法,在BaseActivity里面动态设置
public class BaseActivity extends AppCompatActivity {


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
    }

}

同时列出这三种方法,最主要的目的不是为了告诉大家有这几种方法可以统一设置屏幕的方向,最重要的是告诉大家一种思想吧。通常在xml 文件可以设置的,在java 代码也可以设置。

利用系统的加载机制自动帮我们加载相应的布局

如果大家在资源目录res 中添加了 layout-land(横向布局文件夹) 和 layout-port (竖想布局文件夹),重启Activity模式的横竖屏切换,

可能有人会有这样的疑问,当我们设置了Activity的方向为竖屏或者横屏的时候,旋转屏幕并不会重新调用Activity的各个生命周期,那我们要怎样检测呢?

其实很简单,那就是利用我们的传感器,然后根据旋转的方向做相应的处理

//注册重力感应器  屏幕旋转
mSm = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mSensor = mSm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mSm.registerListener(mOrientationSensorListener, mSensor, SensorManager.SENSOR_DELAY_UI);
public class OrientationSensorListener implements SensorEventListener {
    private static final int _DATA_X = 0;
    private static final int _DATA_Y = 1;
    private static final int _DATA_Z = 2;

    public static final int ORIENTATION_UNKNOWN = -1;
    private boolean sensor_flag = true;

    public static final String TAG = "xujun";

    int mLastAngle=-1;
    AngleChangleListener mAngleChangleListener;

    public OrientationSensorListener(AngleChangleListener angleChangleListener){
        mAngleChangleListener=angleChangleListener;
    }

    @Override
    public void onAccuracyChanged(Sensor arg0, int arg1) {
        // TODO Auto-generated method stub

    }


    @Override
    public void onSensorChanged(SensorEvent event) {

        float[] values = event.values;

        int orientation = ORIENTATION_UNKNOWN;
        float X = -values[_DATA_X];
        float Y = -values[_DATA_Y];
        float Z = -values[_DATA_Z];

        /**
         * 这一段据说是 android源码里面拿出来的计算 屏幕旋转的 不懂 先留着 万一以后懂了呢
         */
        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;
            }
        }

        if (orientation > 225 && orientation < 315) {  //横屏
            sensor_flag = false;
        } else if ((orientation > 315 && orientation < 360) || (orientation > 0 &&
                orientation < 45)) {  //竖屏
            sensor_flag = true;
        }
//        Log.i(TAG, "onSensorChanged: orientation=" + orientation+"   mLastAngle="+mLastAngle);
        if(mLastAngle!=orientation && mAngleChangleListener!=null){
            mAngleChangleListener.onChange(orientation);
            mLastAngle=orientation;
        }

    }
}

设备旋转时保存Activity的交互状态

大家先看一下Activity的生命周期,我们知道如果我们不配置Activity的方向或者Activity的 android:configchang 属性的时候,每次旋转屏幕,Activity都会重新被创建出来。那我们要如何保存我们当前的状态呢。

其实我们可以考虑在 onPause() 或者在 onStop() 里面保存我们相应的数据,再在onCreate() 方法里面判断 savedInstanceState 是否有缓存我们的数据即可。 至于选择在onPause() 还是 onStop() 保存数据,得看具体的需求分析。 onPause() 在界面失去焦点的时候会回调, onStop() 方法在界面完全不可见的时候会回调。

private static final String KEY_INDEX = "index";
private int mCurrentIndex = 0;

@Override
protected void onCreate(Bundle savedInstanceState) {
    if (savedInstanceState != null) {
        mCurrentIndex = savedInstanceState.getInt(KEY_INDEX, 0);
    }
}

@Override
protected void onPause(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putInt(KEY_INDEX, mCurrentIndex);
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Hongten

android开发-TextView控件学习

public class MainActivity extends Activity{

1402
来自专栏向治洪

Android优化之Hardware Layer

项目中越来越多的动画,越来越多的效果导致了应用性能越来越低。该如何提升。 简介 在View播放动画的过程中每一帧都需要被重绘。如果使用view layer...

2889
来自专栏理论坞

那些你不知道的Photoshop冷知识⑤——CC2015评测专题

笔者在探索新版本时,首先注意的便是首选项的变化,可以发现这次更新之后首选项侧边栏多了不少东西,点进去之后才发现原来是进行了重新分类,那么有哪些好玩的功能呢?介绍...

864
来自专栏androidBlog

Android打造不一样的新手引导页面(二)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gdutxiaoxu/article/details...

1201
来自专栏Android先生

Android爬坑之旅:软键盘挡住输入框问题的终极解决方案

开发做得久了,总免不了会遇到各种坑。 而在Android开发的路上,『软键盘挡住了输入框』这个坑,可谓是一个旷日持久的巨坑——来来来,我们慢慢看。

2202
来自专栏菩提树下的杨过

Flash/Flex学习笔记(6):制作基于xml数据源的flv视频播放器

今天折腾了大半天,总算搞出了一个功能简单的视频播放器,可以向公司领导交差了 :) 步骤: 1.Flash CS4 中 先拖一个"FLVPlayback"组件到舞...

2425
来自专栏练小习的专栏

canvas生成图片

今天接到个小需求:前端生成个二维码并且以img标签的方式在web上展示出来。 二维码就不用说了,搜一下实现的各种插件一大堆,这里我用基于jquery的qrcod...

3046
来自专栏Java后端技术

欠的债,这一次都还给你们

  前段时间,写的一篇关于博客园主题皮肤分享的文章,一经发出便受到了极大的热捧,后来很多网友留言说,想要让我分享现在的模板,毕竟现在这个模板已经比之前分享的那个...

1393
来自专栏程序员的碎碎念

你用JavaGUI做的课程设计是这样子的吗?

很多人学完《Java基础教程》后,接着一般都会用GUI来做一下课程设计,多数同学通常选择用插件WindowBuilder来设计程序的界面,认为用插件做会更快更...

5098
来自专栏分享达人秀

两分钟掌握数值选择器NumberPicker

上一期学习了日期选择器DatePicker和时间选择器TimePicker,是不是感觉非常简单,本期继续来学习数值选择器NumberPicker 。 一...

2176

扫码关注云+社区

领取腾讯云代金券