Android手机支持屏幕旋转功能,手机屏幕旋转直接引发了我们的App视图变化,我们选择怎样去处理手机的翻转以及当我们的手机屏幕发生了旋转的时候我们选择何种策略去进行处理视图直接影响了我们的App的用户体验。今天我们一起来学习一下手机屏幕旋转的相关知识。
设置屏幕方向切换的属性
为了使Activity在屏幕旋转方向适应不同的场合,在AndroidManifest文件的activity标签下提供了android:screenOrientation属性用于满足不同的屏幕旋转需求。
- unspecified:默认值,该属性支持的屏幕旋转方向与具体的设备有关;
- user:用户当前的首选方向,通常与unspecified的效果相同;
- behind:与当前Activity在回退栈中下面的那个窗口的方向一致;
- landspace:使屏幕永远保持横屏,手机正常方向逆时针旋转90度;
- portrait:使屏幕永远保持竖屏,即手机的正常方向;
- reverseLandscape:师屏幕永远保持反向横屏,手机正常方向顺时针旋转90度;
- sensorLandscape:系统会利用Android设备的传感器切换到横屏或反向横屏;
- sensorPortrait:系统会利用Android设备的传感器切换到竖屏或反向竖屏;
- sensor:系统会利用Android设备的传感器切换到相应的方向,理论上是4个,但很多设备只支持3个;
- fullSensor:使系统支持4个方向的屏幕旋转;
- nosensor:不会发生屏幕的旋转,但有可能会发生Activity的销毁和重建(与unspecified策略相同)。
阻止Activity的销毁和重建
在默认情况下,当我们的手机屏幕发生旋转的情况下,当前的Activity会被销毁,接着重新创建该Activity,当我们在屏幕旋转时不需要改变布局的话(后面会讲如何在屏幕旋转时改变布局)这样的做法显然有点多余。Android支持开发人员在activity标签下设置android:configChanges以处理Android设备的设置变化。
在API 12(即Android 3.1)以下我们需要设置android:configChanges=”orientation”即可阻止Activity的销毁和重建,在API 12以上我们需要设置android:configChanges=”orientation|screenSize”
改变布局,获得良好用户体验
由于Android设备的长和高一般不同,当我们手机的屏幕方向发生改变后如果继续沿用之前的布局有可能会降低用户体验,下面介绍一下如何在屏幕旋转时改变布局。当我的手机出于横屏时,Android会找到并使用res/layout-land目录下的布局文件,这样我们就知道如何处理了。举一个简单的例子,在手机竖屏时我们手机屏幕顶端有一排tab,当手机翻转后将tab标签置于左侧以获得良好的用户体验:
在Android工程之下的res/layout目录中为新建布局文件activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >
<RadioGroup
android:id="@+id/main_radioGroup"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<RadioButton
android:id="@+id/main_radio0"
android:checked="true"
android:text="ShowOne"
style="@style/radio_style" />
<RadioButton
android:id="@+id/main_radio1"
android:text="ShowTwo"
style="@style/radio_style" />
<RadioButton
android:id="@+id/main_radio2"
android:text="ShowThree"
style="@style/radio_style" />
</RadioGroup>
<TextView
android:id="@+id/textView1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textSize="20sp"
android:text="TextView" />
</LinearLayout>
接下来在res/layout-land目录(若没有该目录,可以直接新建该目录)下创建activity_main.xml文件,布局如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
tools:context=".MainActivity" >
<RadioGroup
android:id="@+id/main_radioGroup"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical" >
<RadioButton
android:id="@+id/main_radio0"
android:checked="true"
android:text="ShowOne"
android:layout_width="100dp"
style="@style/radio_style" />
<RadioButton
android:id="@+id/main_radio1"
android:text="ShowTwo"
android:layout_width="100dp"
style="@style/radio_style" />
<RadioButton
android:id="@+id/main_radio2"
android:text="ShowThree"
android:layout_width="100dp"
style="@style/radio_style" />
</RadioGroup>
<TextView
android:id="@+id/textView1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textSize="20sp"
android:text="TextView" />
</LinearLayout>
需要注意的是:我们不能阻止Activity销毁和重建,否则布局不会发生改变。
保存Activity状态
为了防止Activity在旋转过程中丢失数据,我们可以在设备旋转前保存下数据:
- 覆盖onSaveInstanceState将我们的数据保存在Bundle下;
- 在onCreate方法中获取数据
package com.example.rotatetest;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.RadioGroup.OnCheckedChangeListener;
import android.widget.TextView;
public class MainActivity extends Activity {
private RadioGroup mRadioGroup;
private TextView mTextView;
private static final String LAST_CHOICE = "last_choice";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRadioGroup = (RadioGroup) findViewById(R.id.main_radioGroup);
mTextView = (TextView) findViewById(R.id.textView1);
//获取销毁前选择的RadioButton的Id
int checkId = R.id.main_radio0;
if (savedInstanceState != null) {
checkId = savedInstanceState.getInt(LAST_CHOICE);
}
((RadioButton) findViewById(checkId)).setChecked(true);
switch (mRadioGroup.getCheckedRadioButtonId()) {
case R.id.main_radio0:
mTextView.setText("Show One");
break;
case R.id.main_radio1:
mTextView.setText("Show Two");
break;
case R.id.main_radio2:
mTextView.setText("Show Three");
break;
default:
break;
}
mRadioGroup.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
// TODO Auto-generated method stub
switch (checkedId) {
case R.id.main_radio0:
mTextView.setText("Show One");
break;
case R.id.main_radio1:
mTextView.setText("Show Two");
break;
case R.id.main_radio2:
mTextView.setText("Show Three");
break;
default:
break;
}
}
});
}
@Override
protected void onSaveInstanceState(Bundle outState) {
// TODO Auto-generated method stub
super.onSaveInstanceState(outState);
//保存选择RadioButton的Id
outState.putInt(LAST_CHOICE, mRadioGroup.getCheckedRadioButtonId());
}
}
监听屏幕旋转事件
有时我们希望在设备发生旋转的时候可以得到通知以便我们处理一下事情,下面来看看如何捕获该通知。屏幕方向改变属于Android设备的设置改变,我们可以在onConfigurationChanged方法中获得。
- 在AndroidManifest文件中声明Activity要捕获的事件类型 android:configChanges=”orientation|screenSize”
- 重写Activity中的onConfigurationChanged方法
@Override
public void onConfigurationChanged(Configuration newConfig) {
// TODO Auto-generated method stub
super.onConfigurationChanged(newConfig);
if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
Toast.makeText(MainActivity.this, "现在是竖屏", Toast.LENGTH_SHORT)
.show();
}
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
Toast.makeText(MainActivity.this, "现在是横屏", Toast.LENGTH_SHORT)
.show();
}
}