Android 横竖屏(手动+自动)

疫情概要

8月1日0—24时,31个省(自治区、直辖市)和新疆生产建设兵团报告新增确诊病例49例,其中境外输入病例16例(四川4例,山东3例,湖北3例,广东2例,陕西2例,上海1例,福建1例),本土病例33例(新疆30例,辽宁3例);无新增死亡病例;无新增疑似病例。

前言

新的效果涂上,手机在竖屏界面上没有点击触发App切换到横屏的功能按钮,但是却又有横屏的效果图,并且可以通过返回按钮退出横屏。经过一番思考后有了可行的方案。本篇记录该需求的具体实现过程。如要查看关于横竖屏的详细设置介绍,请查看文章 Android 动态切换全屏横屏

思路

使用手机传感器检测设备方向 + 手动/自动设置屏幕方向

关于设备方向的监听,一般想到的是SensorManager,但系统在SDK3内就添加了OrientationEventListener抽象类来帮助监听设备方向。

再通过setRequestedOrientation (int requestedOrientation)来强制指定方向。

详细过程

OrientationEventListener

public abstract class OrientationEventListener
extends Object

java.lang.Object
android.view.OrientationEventListener

Helper class for receiving notifications from the SensorManager when the orientation of the device has changed.

即:监听设备方向的帮助类。

虽然是以 Listener结尾,但它不是接口类型,是抽象类,内部封装了 SensorManager相关的逻辑,用于监听设备当前角度,通过onOrientationChanged(int orientation)方法返回。

注:记得调用OrientationEventListener.disable()取消监听(注册),避免内存泄露。若需反复监听、取消操作,可通过OrientationEventListener.enable()OrientationEventListener.disable()使监听有效/无效。

OrientationEventListener相关实现类如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
/**
* 自定义工具类
* <p>
* 实时的检测用户屏幕的位置改变,做到 重力感应 与 全屏/半屏按钮 逻辑的互容
*/
public class OrientationDetector extends OrientationEventListener {

private WeakReference<Activity> mWeakReferenceActivity;
/**
* 实时记录用户手机屏幕的位置
*/
private int mOrientation = -1;

public OrientationDetector(Activity activity) {
super(activity);
mWeakReferenceActivity = new WeakReference<>(activity);
}

@Override
public void onOrientationChanged(int orientation) {
//判null
if (mWeakReferenceActivity.get() == null || mWeakReferenceActivity.get().isFinishing()) {
return;
}
//记录用户手机上一次放置的位置
int mLastOrientation = mOrientation;

if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) {
//手机平放时,检测不到有效的角度

//重置为原始位置 -1
mOrientation = -1;
return;
}

/**
* 只检测是否有四个角度的改变
*/
if (orientation > 350 || orientation < 10) {
//0度,用户竖直拿着手机
mOrientation = 0;

} else if (orientation > 80 && orientation < 100) {
//90度,用户右侧横屏拿着手机
mOrientation = 90;

} else if (orientation > 170 && orientation < 190) {
//180度,用户反向竖直拿着手机
mOrientation = 180;

} else if (orientation > 260 && orientation < 280) {
//270度,用户左侧横屏拿着手机
mOrientation = 270;
}


//如果用户关闭了手机的屏幕旋转功能,不再开启代码自动旋转了,直接return
try {
/**
* 1 手机已开启屏幕旋转功能
* 0 手机未开启屏幕旋转功能
*/
if (Settings.System.getInt(mWeakReferenceActivity.get().getContentResolver(), Settings.System.ACCELEROMETER_ROTATION) == 0) {
return;
}
} catch (Settings.SettingNotFoundException e) {
e.printStackTrace();
}

//当检测到用户手机位置距离上一次记录的手机位置发生了改变,开启屏幕自动旋转
if (mLastOrientation != mOrientation) {
mWeakReferenceActivity.get().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}
}

}

setRequestedOrientation

Change the desired orientation of this activity. If the activity is currently in the foreground or otherwise impacting the screen orientation, the screen will immediately be changed (possibly causing the activity to be restarted). Otherwise, this will be used the next time the activity is visible.

Parameters
requestedOrientation int: An orientation constant as used in ActivityInfo#screenOrientation. Value is android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED, ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT, ActivityInfo.SCREEN_ORIENTATION_USER, ActivityInfo.SCREEN_ORIENTATION_BEHIND, ActivityInfo.SCREEN_ORIENTATION_SENSOR, ActivityInfo.SCREEN_ORIENTATION_NOSENSOR, ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE, ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT, ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE, ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT, ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR, ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE, ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT, ActivityInfo.SCREEN_ORIENTATION_FULL_USER, or ActivityInfo.SCREEN_ORIENTATION_LOCKED

即:改变活动方向。

另外配合使用setRequestedOrientation(int requestedOrientation)进行强制横竖屏切换

完整示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public class SimpleActivity extends AppCompatActivity {

private static final String TAG = "SimpleActivity";
private OrientationDetector orientationDetector;

private TextView tv;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.w(TAG, "onCreate: ");
setContentView(R.layout.activity_simple);
tv = findViewById(R.id.tv);
tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.w(TAG, "onClick: " + getResources().getConfiguration().orientation);
if (getResources().getConfiguration().orientation == ActivityInfo.SCREEN_ORIENTATION_USER) {
tv.setText("我是竖屏");
//切竖屏
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
} else {
tv.setText("我是横屏");
//切横屏
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
}
});
orientationDetector = new OrientationDetector(this);
}

@Override
protected void onResume() {
super.onResume();
orientationDetector.enable();
}

@Override
protected void onPause() {
super.onPause();
orientationDetector.disable();
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
Log.w(TAG, "onConfigurationChanged: " + newConfig);
if (newConfig.orientation == ActivityInfo.SCREEN_ORIENTATION_USER) {
tv.setText("我是横屏");
} else {
tv.setText("我是竖屏");
}
}
}
坚持原创技术分享,您的支持是对我最大的鼓励!