Android应用:横竖屏切换总结

眨眼间,已经到了2016你年春节前,离上一篇博客的时间已经有6个月多,回想起这半年的种种,不得不说,学习和工作实在是太忙了,或许这就是程序员的真实写照吧。

写博客之初,主要的目的还是为了把自己的学习痕迹记录下来,写的东西比较基础,也不多,算是一种督促,希望能坚持地学习下去,因为学识不存在暴发户,靠的是积累。如果对自己过去半年的学习给个评价,我还是比较满意的,前期定下来的目标都基本都达到了。单凭这个,我就觉得今年的新年会是个好年。

说完过去,那么接着就是将来。因为现在的工作环境上外网不大方便,而且作为开发的主干之一,还是比较忙的,可见用来扩展学习的时间也不会很多。所以,往后若有空更新博客,都是以记录为主,记录工作中遇到的一些问题的解决方法,无论是简单还是困难的,无论是原创还是转载。下面是正题。

一、横竖屏的应用

首先,手机横竖长度的悬殊差距,注定了app横竖屏的表现的差异化。老实说,目前绝大多数android的App在产品设计之初都是在竖屏的基础上进行设计的(也就是单手操作),并无专门地去考虑切换横屏后的用户体验。这些App若是允许切换横屏操作,而用户的手机又设置了允许自动旋转,那么用户在使用这些App的时候很可能会经常碰到横屏的情况,结果不言而知,App给用户的体验就有了折扣。

所以,碰到这种情况下,不妨根据设计时针对的屏幕模式,固定App的展示方向,正如很多手机游戏固定只能横屏。

二、禁止APP内横竖屏切换

让App禁止掉横竖屏的切换,这就需要通过在AndroidManifest.xml中设置activity中的android:screenOrientation属性值来实现。

该android:screenOrientation属性,他有以下几个参数:
"unspecified":默认值,由系统来判断显示方向.判定的策略是和设备相关的,所以不同的设备会有不同的显示方向.
"landscape":横屏显示(宽比高要长)
"portrait":竖屏显示(高比宽要长)
"user":用户当前首选的方向
"behind":和该Activity下面的那个Activity的方向一致(在Activity堆栈中的)
"sensor":有物理的感应器来决定。如果用户旋转设备这屏幕会横竖屏切换。
"nosensor":忽略物理感应器,这样就不会随着用户旋转设备而更改了("unspecified"设置除外)。

比如下列设置
android:screenOrientation="portrait"
则无论手机如何变动,拥有这个属性的activity都将是竖屏显示。
android:screenOrientation="landscape",为横屏显示。

上述修改也可以在Java代码中通过类似如下代码来设置

1 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

三、手动触发APP的横竖屏切换

由上面描述可知,当android:screenOrientation为默认值"unspecified"或"sensor"等时,就会有系统根据设备 的旋转情况来触发横竖屏的切换,那么有没有方法我们手动在程序中触发横竖屏的变换呢,显然上面为我们提供的 setRequestedOrientation就是系统提供的一个入口,下面我们给出一个按键的方式来触发的案列:

 1 public class MainActivity extends Activity implements OnClickListener {
 2
 3      private Button mBtnLandscape;
 4
 5      private Button mBtnPortrait;
 6
 7      @Override
 8      protected void onCreate(Bundle savedInstanceState) {
 9
10          super.onCreate(savedInstanceState);
11
12          setContentView(R.layout.activity_main);
13
14          mBtnLandscape = (Button) findViewById(R.id.but_landscape);
15
16          mBtnPortrait = (Button) findViewById(R.id.but_portrait);
17
18          mBtnLandscape.setOnClickListener(this);
19
20          mBtnPortrait.setOnClickListener(this);
21
22      }
23
24      @Override
25      public void onClick(View v) {
26
27                  if(v == mBtnLandscape){
28
29                              setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
30
31                  }else{
32
33                              setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
34
35                  }
36
37      }
38
39      @Override
40      public void onConfigurationChanged(Configuration newConfig) {
41
42          super.onConfigurationChanged(newConfig);
43
44          String message=newConfig.orientation==Configuration.ORIENTATION_LANDSCAPE ? "屏幕设置为:横屏" : "屏幕设置为:竖屏";
45
46          Toast.makeText(this, message, Toast.LENGTH_LONG).show();
47
48      }
49 }

需要注意的是,手动调用时,无视AndroidManifest中关于screenOrientation的设置;另外上述代码中的onConfigurationChanged要被调用到也是需要条件的,在这里,只给代码,不做讨论,后面再给出一个相关的补充说明。

四、重启Activity的横竖屏切换

在上面的案列中,缺省状态下,Activity每次横竖屏切换(包括用setRequestedOrientation调用)都会重新调用一轮 onPause-> onStop-> onDestory-> onCreate->onStart->onResume操作,从而销毁原来的Activity对象,创建新的Activity对象,这是因 为通常情况下软件在横竖屏之间切换,界面的高宽会发生转换,从而可能会要求不同的布局。具体的布局切换可以通过如下两种方法来实现:

1)在res目录下建立layout-land和layout-port目录,相应的layout文件名不变,比如main.xml。layout- land是横屏的layout,layout-port是竖屏的layout,其他的不用管,横竖屏切换时程序自己会调用Activity的 onCreate方法,从而根据当前横竖屏情况自动加载响应的布局。

2)假如布局资源是不一样又不按照如上设置,则需要通过java代码来判断当前是横屏还是竖屏然后来加载相应的xml布局文件(比如mainP为竖屏 mainL为横屏)。因为当屏幕变为横屏的时候,系统会重新呼叫当前Activity的onCreate方法,你可以把以下方法放在你的onCreate 中来检查当前的方向,然后可以让你的setContentView来载入不同的layout xml。



 1 @Override
 2 protected void onCreate(Bundle icicle) {
 3
 4     super.onCreate(icicle);
 5
 6     int mCurrentOrientation = getResources().getConfiguration().orientation;
 7
 8     if (mCurrentOrientation == Configuration.ORIENTATION_PORTRAIT) {
 9
10         // If current screen is portrait
11
12         Log.i("info", "portrait"); // 竖屏
13
14         setContentView(R.layout.mainP);
15
16     } else if (mCurrentOrientation == Configuration.ORIENTATION_LANDSCAPE) {
17
18         // If current screen is landscape
19
20         Log.i("info", "landscape"); // 横屏
21
22         setContentView(R.layout.mainL);
23
24     }
25
26     init();// 初始化,赋值等操作
27
28     findViews();// 获得控件
29
30     setListensers();// 设置控件的各种监听方法
31
32 }

上面只是对布局切换做了描述,实际上由于重启Activity在未加处理的情况下必然导致数据的丢失和重新获取,这样用户体验会非常差。为此就要在切换前对数据进行保存,切换重启后对数据进行恢复,具体操作的步骤如下:

 1 // 重写Activity.onRetainNonConfigurationInstance(),用户横竖屏切换前保存数据
 2 @Override
 3 public Object onRetainNonConfigurationInstance() {
 4
 5     final MyDataObject data = collectMyLoadedData();
 6
 7     return data;
 8
 9 }
10
11 // 在onCreate()函数中调用getLastNonConfigurationInstance(),获取onRetainNonConfigurationInstance()保存的数据
12 @Override
13 public void onCreate(Bundle savedInstanceState) {
14
15     super.onCreate(savedInstanceState);
16
17     setContentView(R.layout.main);
18
19     final MyDataObject data = (MyDataObject) getLastNonConfigurationInstance();
20
21     if (data == null) {
22         data = loadMyData();
23     }
24 }

五、非重启Activity的横竖屏切换

虽然重启Activity为我们提供了保存数据和读取数据的方式,但是如此一来程序会显得有些繁琐,所以有时候程序员往往就不想让Activity重 启,Android也为我们提供了解决方案,就是通过onConfigurationChanged拦截横竖屏变换,从而进行必要的重新布局和切换操作。 操作步骤如下:

首先,manifest中为相应的Activity设置android:configChanges属性,从而让Activity不延续上述的重建流程,具体如下:

Andorid 3.2以前的SDK可以使用如下配置
android:configChanges="orientation|keyboardHidden"

而Adnroid 3.2以后的SDK必须添加一个screenSize属性,具体如下
android:configChanges="keyboardHidden|orientation|screenSize"
或者
android:configChanges="orientation|screenSize"

其次,在Activity或View的onConfigurationChanged(Configuration
newConfig)函数中获取当前横竖屏参数。至于其调用顺序跟touch事件的传递顺序相似,不过他没有消费事件的概念,会顺次调用到每一个
onConfigurationChanged函数。下面是重写Activity的例子:

 1 //布局分别在layout-land和layout-port目录中的同名main.xml时
 2 @Override
 3
 4 public void onConfigurationChanged (Configuration newConfig){
 5
 6     super.onConfigurationChanged(newConfig);
 7
 8     setContentView(R.layout.main);
 9
10     findViews();
11
12     setListensers();
13
14 }
15
16 //布局为不按照layout-land和layout-port目录,而自定义名字时
17 @Override
18 public void onConfigurationChanged (Configuration newConfig){
19
20     super.onConfigurationChanged(newConfig);
21
22     int mCurrentOrientation = getResources().getConfiguration().orientation;
23
24     if ( mCurrentOrientation == Configuration.ORIENTATION_PORTRAIT ) {
25
26         // If current screen is portrait
27
28         setContentView(R.layout.mainP);
29
30         findViews();
31
32         setListensers();
33
34     } else if ( mCurrentOrientation == Configuration.ORIENTATION_LANDSCAPE ) {
35
36         //If current screen is landscape
37
38         setContentView(R.layout.mainL);
39
40         findViews();
41
42         setListensers();
43
44     }
45 } 

当然有时候连布局都不用更改的话,就可以直接对原有控件进行调用操作了,比如:

 1 public class MainActivity extends Activity {
 2
 3     private TextView textView;
 4
 5     @Override
 6     public void onCreate(Bundle savedInstanceState) {
 7
 8         super.onCreate(savedInstanceState);
 9
10         setContentView(R.layout.main);
11
12         Log.i("--Main--", "onCreate");
13
14         textView=(TextView)findViewById(R.id.tv_id);
15
16     }
17
18     @Override
19     public void onConfigurationChanged(Configuration newConfig) {
20
21         super.onConfigurationChanged(newConfig);
22
23         Log.i("--Main--", "onConfigurationChanged");
24
25         if(newConfig.orientation==Configuration.ORIENTATION_LANDSCAPE){
26
27             textView.setText("当前屏幕为横屏");
28
29         }else{
30
31             textView.setText("当前屏幕为竖屏");
32
33         }
34     }
35 }

需要注意的是,onConfigurationChanged函数中只能获得横竖屏切换后的参数,在该函数中获取不到新的Layout和控件的尺寸位置信息,如果要处理尺寸和位置信息,必须通过消息异步或者延时调用,下面是一个App在横竖屏切换时需要重新设置popupWindow位置的代码:



 1 @Override
 2 protected void onConfigurationChanged(Configuration newConfig) {
 3
 4     super.onConfigurationChanged(newConfig);
 5
 6     //View中不用创建Handler,可直接调用post操作
 7
 8     //new Handler().postDelayed(new Runnable() {
 9
10     //    @Override
11     //    public void run() {
12
13     //        updatePopup();
14
15     //    }
16
17     //}, 500);
18
19     postDelayed(new Runnable() {
20
21         @Override
22         public void run() {
23
24             updatePopup();      //
25
26         }
27
28     }, 500);//如果不在post中,而是直接调用,那么弹出位置就会有问题
29
30 }

虽然上面没有看到对布局的显式调用进行重新布局,照理控件的对象没有被销毁,但是控件在横竖屏切换时应该是需要进行重新layout和measure,然 后再进行重绘的,否则不会引发弹出框位置的变化,至于如何调用重新layout、measure和Draw操作,在这里就不多展开了。

六、对于AndroidManifest.xml设置的补充、

经过上面代码演示,我们可以看到具体实现涉及到了Manifest工程配置里面具体Activity的screenOrientation和 configChanges两个参数,这两个参数screenOrientation的优先级是高于configChanges,即假如 screenOrientation设置为固定横竖屏时,那么configChanges参数无论怎么设都没有办法引发横竖屏切换,除非在代码中手动调用 setRequestedOrientation函数进行修改。

screenOrientation属性在前面已经讲过了,而关于configChanges属性设置有如下选项:



描述


mcc


IMSI移动台的国家代码(MCC)发生变化——一个SIM被探测到并且更新MCC


mnc


IMSI移动台的网络代码(MNC)发生变化——一个SIM被探测到并且更新MNC


locale


区域发生变化——用户选择了一个文本需要显示的新语言


touchscreen


触摸屏发生变化。(这个通常不会发生。)


keyboard


键盘类型发生变化——例如:用户插入了外接键盘。


keyboardHidden


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


navigation


导航类型(轨迹球或dpad)发生变化。(通常不会发生。)


screenLayout


屏幕布局发生变化——这个会导致显示不同的Activity。


fontScale


字体缩放因子发生变化——用户选择了新的字体大小。


uiMode


当UI模式发生改变的时候——当用户放置设备到桌子或/汽车或夜间模式改变的时候可以引起UI模式变化。阅读UiModeManager。在API级别8时引入。


orientation


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


screenSize



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


smallestScreenSize



理屏幕大小的变化。不管方向的变化,仅仅在实际物理屏幕打包变化的时候,如:外接显示器。这个配置项的变化引起在smallestWidth
configuration里的变化。然而,如果你的程序目标API级别是12或更低,你的Activity将自己处理这个变化(这个变化不会引起
Activity的重启,甚至在Android 3.2或更新的设备上)在API级别13里加入的。


layoutDirection


布局方向变化。例如书写方式从左向右(LTR)转换为从右向左(RTL)

从上述这个表我们可以看到除了横竖屏,包括语言、网络、键盘和外设等变化都可以被onConfigurationChanged函数监控到。

结合网上的整理,小结跟这几配置相关的情景:

1)不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次(我
在三星4.0设备上发现切横屏和竖屏都是执行一次,而并非这里说的有执行两次的情况,不知道是否以前版本手机会这样?);

2)设置Activity的android:configChanges="orientation"时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次;

3)设置Activity的android:configChanges="orientation|keyboardHidden"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法。

注:上述描述是在Android3.2以前,如果缺少了keyboardHidden选项,不能防止Activity的销毁重启,也就不能执行
onConfigurationChanged方法了。在3.2之后,必须加上screenSize属性才可以屏蔽调用Activity的生命周期(我在
一些设备上亲测可以不需要keyboardHidden,只要screenSize就可以了,但是保险起见还是继续保留keyboardHidden
吧)。

七、对于setRequestedOrientation函数的补充说明

在上述(二)对于手动触发横竖屏切换的时候,我们用到了setRequestedOrientation,那时只是简单做了下演示,后来发现还是需要做下补充说明的:

首先在非重启Activity模式下:

手动调用setRequestedOrientation之后,假如会引发横竖屏切换(即请求的横竖屏要求与当前的横竖屏情况不一致,就会引发切换),那
么会立即调用onConfigurationChanged函数;假如不会引发横竖屏切换(请求前后一致),那么也就不会调用到
onConfigurationChanged函数。

这个手动调用setRequestedOrientation的地方也可以在Activity中的任何地方,即也可以在
onConfigurationChanged中调用,但是一旦指定为横屏或竖屏完成这个变换之后,后面不论屏幕如何进行怎么翻转变化,都不会再触发横竖
屏切换了,也即等同于在manifest中设置了android:screenOrientation属性为横屏或竖屏。如果要恢复为响应横竖屏随物理传
感器设备变换,那么就需要手动调用类似如下代码进行恢复:

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);

其次在重启Activity模式下:

手动调用setRequestedOrientation发出横竖屏设定请求之后,假如需要进行横竖屏切换(即请求前后横竖屏状态不一致),则会对Activity进行销毁并重启;假如不需要需要进行横竖屏切换,则Activity维持现状不变;

手动调用setRequestedOrientation一次,完成变换之后,也跟上面非重启一样,相当于在manifest中设置了android:screenOrientation属性为横屏或竖屏。要想恢复也需要重新调用类似上面非重启的调用。

下面一个例子:

让App启动的时候是横屏的话就横屏表示,纵屏的话就纵屏表示,然后手机切换横竖屏就不能用了该怎么解决呢?利用上述原理,就可以解决。

参考博客地址:http://www.cnblogs.com/franksunny/p/3714442.html

时间: 2024-10-13 19:19:57

Android应用:横竖屏切换总结的相关文章

Android模拟器横竖屏切换

搞了这么长时间的android开发,却对一些基础的东西一直模棱两可...就比如这个onPause和onStop.如果从一个界面,跳到另一个界面,那么是调用哪个呢? 经过我的实验.搞清楚了.onPause是有活动状态变为非活动状态.onStop()是变为不可见.那么从一个页面跳到另一个页面就是依次调用onPause,onStop.看下程序: package com.example.fuhe; import android.os.Bundle; import android.app.Activity

Android Configuration横竖屏切换时Activity生命周期调用

问题:横竖屏切换时Activity的生命周期? 测试环境:华为mate7 package com.virglass.beyond.activity; import android.app.Activity; import android.content.res.Configuration; import android.os.Bundle; import com.virglass.beyond.utils.LogUtil; /** * 系统设置更改 * @author Administrator

浅析Android的横竖屏切换

上周有个项目需求在横竖屏中控制不一样的布局,我当时采用的方法是写在同一套布局中,监听手机横竖屏的切换事件,来控制布局中各个控件的显示或者隐藏. 这个方法相对来说还行.上几篇帖子中我也说了怎么判断当前手机是横屏模式还是竖屏模式,这里再把工具类贴一下给大家看看: public static boolean isScreenChange(Context mContext) { Configuration mConfiguration = mContext.getResources().getConfi

Android之横竖屏切换内容丢失问题解决方法

注意: 在横屏竖屏切换过程中,Activity会被重新创建 onCreate方法会重新执行 如果没有id的组件如编辑框等则横屏填写的编辑框中的数据,写到一半后如果竖屏显示, 数据会丢失 谷歌解决方案: 如果拥有id 会在第一次创建Activity,执行完onCreate()方法之后把id组件中对应的值临时保存存起来, 在旋转后再次创建Activity时 但是是在    执行完onCreate()方法之后!!!!!执行完之后!!!! 根据id找到对应的值填写上去 版权声明:本文为博主原创文章,未经

Android 禁止横竖屏切换

xml设置竖屏显示<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.himi" android:versionCode="1" android:versionName="1.0"&

[Android Pro] 横竖屏切换时,禁止activity重新创建,android:configChanges=&quot;keyboardHidden|orientation&quot; 不起作用

referece to : http://blog.csdn.net/mybook1122/article/details/24978025 这个网上搜索,很多结果都是: AndroidManifest.xml android:configChanges="keyboardHidden|orientation" 但是,实际上很多手机上,这个根本不起作用.这是为什么呢? 因为,但多数人陈陈相因,文章直接转,都没有结果自己实践. 在低版本上,这个是可以起作用.在android 4.0 以上

Android横竖屏切换重载问题与小结

(转自:http://www.cnblogs.com/franksunny/p/3714442.html) (老样子,图片啥的详细文档,可以下载后观看 http://files.cnblogs.com/franksunny/635350788930000000.pdf) Android手机或平板都会存在横竖屏切换的功能,通常是由物理重力感应触发的,但是有时候也不尽然,通常在设置里面我们可以对手机的横竖屏切换进行关闭,操作界面如下 只需要点击下“屏幕旋转”按钮就可以关闭横竖屏切换了. 一.禁止AP

Android 横竖屏切换小结

转自:http://www.cnblogs.com/franksunny/p/3714442.html (老样子,图片啥的详细文档,可以下载后观看 http://files.cnblogs.com/franksunny/635350788930000000.pdf) Android手机或平板都会存在横竖屏切换的功能,通常是由物理重力感应触发的,但是有时候也不尽然,通常在设置里面我们可以对手机的横竖屏切换进行关闭,操作界面如下 只需要点击下“屏幕旋转”按钮就可以关闭横竖屏切换了. 一.禁止APP内

屏幕方向 横竖屏切换

屏幕方向的控制 屏幕方向是对Activity而言的,你可以在AndroidManifest.xml 文件中,通过activity的android:screenOrientation属性进行设定.在此配置的值会反映在Activity的getRequestedOrientation()方法的返回值中,与之对应的setRequestedOrientation()方法可以动态改变该属性的值. 另外, 还可以通过Configuration对象来取得Activity当前的显示方向 取值: unspecifi

Android实战技巧之二十四:横竖屏切换

这几年一直在做手机上和电视盒的App,几乎没有考虑过横竖屏切换的问题.电视盒好说,横屏不变,你要是给它设计个竖屏人家也没机会使:而手机上的应用就不好说了,有些界面你设计了横竖屏兼容可能是为了表示你的功能强大.但是按照惯例,或许也是设计师图省事,我们只是做一个方案.就像目前主流的App都只有竖屏一个模式,比如微信.京东和招商银行.我截了几张图表示一下. 但是像地图之类的应用,也许横屏会显示的更友好一些.请看腾讯地图的设计如下: 细心的你会发现,地图的横竖屏的样式几乎是一样的布局,调整起来还是比较容