Android横竖屏设置

  默认情况下,当用户手机的”屏幕旋转”选项打开后,旋转手机方向,手机屏幕也会跟随旋转的方向进行横竖屏切换.

设置屏幕旋转的方式有两种:

.AndroidManifest.xml设置


  如果activity默认是某种模式的,直接在AndroidManifest.xml中的对应activity项中,添加相应的代码即可实现

  如:

    android:screenOrientation="unspecified" 跟随系统屏幕旋转方向等(默认)

    android:screenOrientation="landscape" 强制横屏

    android:screenOrientation="portrait" 强制竖屏

.代码动态设置


  如果需要动态设置activity的在屏幕上的显示方向,可以调用系统提供的api函数:setRequestedOrientation(@ActivityInfo.ScreenOrientationint requestedOrientation).

  requestedOrientation主要对应的值:

   ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED

   ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE

   ActivityInfo.SCREEN_ORIENTATION_PORTRAIT


.android:screenOrientation的详细参数


  


.android:configChanges设置(自行处理配置变更)


  当我们设置的旋转方式是跟随系统的,既android:screenOrientation="unspecified",这时如果屏幕方向发生改变,Activity会被销毁,然后重新创建Activity.

  (重启行为旨在通过利用与新设备配置匹配的备用资源自动重新加载您的应用,来帮助它适应新配置.)

  重启并恢复大量数据不仅成本高昂,影响性能,而且给用户留下糟糕的使用体验.

  

  如果不想Activity被销毁,需要在AndroidManifest.xml中配置android:configChanges

  例如:

     

   注意:从 Android 3.2API级别 13)开始,当设备在纵向和横向之间切换时,“屏幕尺寸”也会发生变化.因此,在开发针对API 级别 13或更高版本(正如 minSdkVersion 和 targetSdkVersion 属性中所声明)的应用时,若要避免由于设备方向改变而导致运行时重启,则除了 "orientation" 值以外,您还必须添加 "screenSize" .也就是说,您必须声明android:configChanges="orientation|screenSize".但是,如果您的应用面向API 级别 12 或更低版本,则Activity 始终会自行处理此配置变更(即便是在Android 3.2 或更高版本的设备上运行,此配置变更也不会重启Activity.)

   加上这段代码后,如果再旋转手机屏幕,Activity就不会再被销毁了,而是会回调activity中的onConfigurationChanged方法,这时就需要在这里处理相关逻辑.

.android:configChanges的详细参数


  

.关于使用横竖屏等多套资源


    

  如上图,我们是可以在Res下同时配置多套资源文件的,layout是默认的资源文件,layout-land是横屏下的资源文件.(value等资源也可以配置多套)


  如果没有配置android:configChanges设置,既没有自行处理配置变更,activity被销毁重建后,会自动去加载相应目录下的资源,这个开发者只需要同时准备了多套资源就行,而不用在运行时关注配置的变更(屏幕方向旋转等).


  如果配置android:configChanges设置,既自行处理配置变更,activity会在被创建时就去加载相应资源文件下的资源,也就是如果是横屏进来的,就会加载layout-land下的资源文件.后面配置的变更(屏幕方向旋转等)activity不会再去加载资源(即使配置了多套资源),这时就需要在onConfigurationChanged方法中根据Configuration参数去自行刷新相应的资源文件了.


.获取当前屏幕横竖屏状态


  通过getResources().getConfiguration().orientation可以拿到当前屏幕方向的状态值

  Configuration.ORIENTATION_LANDSCAPE 表示的是横屏


.关于onConfigurationChanged方法


 onConfigurationChanged回调不仅仅在activity中有,fragmentview,viewgroup等都会有


 以下是onConfigurationChanged的回调流程:


 1.activity


  在ActivityThread中收到配置变化的消息,然后在handleActivityConfigurationChangedperformConfigurationChanged处理,回调到activity.


  如果有多个activity,只会回调正在runningactivity,其他的activity只有重新激活并且屏幕状态和当前状态不一样时才会回调(官方只说了回调正在runningactivity,但是测试证明点击返回后其他的activity也会回调)


final voidhandleActivityConfigurationChanged(ActivityConfigChangeData data) {

ActivityClientRecord r =mActivities.get(data.activityToken);

if (r == null || r.activity == null) {

return;

}


if (DEBUG_CONFIGURATION) Slog.v(TAG,"Handle activity config changed: "

+ r.activityInfo.name);


r.tmpConfig.setTo(mCompatConfiguration);

if (data.overrideConfig != null) {

r.overrideConfig =data.overrideConfig;

r.tmpConfig.updateFrom(data.overrideConfig);

}

performConfigurationChanged(r.activity,r.tmpConfig);


freeTextLayoutCachesIfNeeded(r.activity.mCurrentConfig.diff(mCompatConfiguration));


mSomeActivitiesChanged = true;

}


private static voidperformConfigurationChanged(ComponentCallbacks2 cb, Configurationconfig) {

// Only for Activity objects, check thatthey actually call up to their

// superclass implementation. ComponentCallbacks2 is an interface, so

// we check the runtime type and actaccordingly.

Activity activity = (cb instanceofActivity) ? (Activity) cb : null;

if (activity != null) {

activity.mCalled = false;

}


boolean shouldChangeConfig = false;

if ((activity == null) ||(activity.mCurrentConfig == null)) {

shouldChangeConfig = true;

} else {


// If the new config is the same asthe config this Activity

// is already running with then don'tbother calling

// onConfigurationChanged

int diff =activity.mCurrentConfig.diff(config);

if (diff != 0) {

// If this activity doesn't handleany of the config changes

// then don't bother callingonConfigurationChanged as we're

// going to destroy it.

if((~activity.mActivityInfo.getRealConfigChanged() & diff) == 0) {

shouldChangeConfig = true;

}

}

}


if (DEBUG_CONFIGURATION) Slog.v(TAG,"Config callback " + cb

+ ": shouldChangeConfig="+ shouldChangeConfig);

if (shouldChangeConfig) {

cb.onConfigurationChanged(config);


if (activity != null) {

if (!activity.mCalled) {

throw newSuperNotCalledException(

"Activity "+ activity.getLocalClassName() +

" did not callthrough to super.onConfigurationChanged()");

}

activity.mConfigChangeFlags = 0;

activity.mCurrentConfig = newConfiguration(config);

}

}

}


 2.fragment


  (1)Activity中的处理


public voidonConfigurationChanged(Configuration newConfig) {

if (DEBUG_LIFECYCLE) Slog.v(TAG,"onConfigurationChanged " + this + ": " +newConfig);

mCalled = true;


mFragments.dispatchConfigurationChanged(newConfig);


if (mWindow != null) {

// Pass the configuration changedevent to the window

mWindow.onConfigurationChanged(newConfig);

}


if (mActionBar != null) {

// Do this last; the action bar willneed to access

// view changes from above.

mActionBar.onConfigurationChanged(newConfig);

}

}


  (2)FragmentController中转发


public voiddispatchConfigurationChanged(Configuration newConfig) {

mHost.mFragmentManager.dispatchConfigurationChanged(newConfig);

}


  (3)FragmentManager中分发到activity中的所有fragment


public voiddispatchConfigurationChanged(Configuration newConfig) {

if (mAdded != null) {

for (int i=0; i<mAdded.size(); i++){

Fragment f = mAdded.get(i);

if (f != null) {

f.performConfigurationChanged(newConfig);

}

}

}

}


 3.ViewGroup



 通过looper发送MSG_RESIZED_REPORT的消息,ViewRootImpl中接受并处理消息,然后调用ViewGroup或者ViewdispatchConfigurationChanged再调用onConfigurationChanged.


@Override

public voiddispatchConfigurationChanged(Configuration newConfig) {

super.dispatchConfigurationChanged(newConfig);

final int count = mChildrenCount;

final View[] children = mChildren;

for (int i = 0; i < count; i++) {

children[i].dispatchConfigurationChanged(newConfig);

}

}



注意:

  在没有配置android:configChanges,activitya 跳转到b,旋转屏幕,b会马上销毁重新创建,a需要重新返回到a会才会销毁重新创建.

04-0515:14:21.225 17379-17379/? D/xxx: BrowserActivity onCreate

04-0515:14:36.434 17379-17379/com.android.browser D/xxx:BrowserSearchActivity onCreate

//横屏

04-0515:20:14.627 17379-17379/com.android.browser D/xxx:BrowserSearchActivity onDestroy

04-0515:20:14.654 17379-17379/com.android.browser D/xxx:BrowserSearchActivity onCreate

//点击返回

04-0515:20:19.219 17379-17379/com.android.browser D/xxx: BrowserActivityonDestroy

04-0515:20:19.248 17379-17379/com.android.browser D/xxx: BrowserActivityonCreate

04-0515:20:19.448 17379-17379/com.android.browser D/xxx:BrowserSearchActivity onDestroy

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值