工具方法 ScreenOrientationHelper.java
java
package com.csdn.utils;
import android.app.Activity;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import com.csdn.BuildConfig;
import com.socks.library.KLog;
/**
* 屏幕方向控制工具类:支持 Activity + Fragment,封装传感器监听和横竖屏切换逻辑
*/
public class ScreenOrientationHelper implements SensorEventListener {
private static final String TAG = "ScreenOrientationHelper";
private static final float ACCEL_THRESHOLD = 3.0f; // 加速度变化阈值(防抖)
private static final long UPDATE_INTERVAL = 200; // 方向更新最小间隔(毫秒)
private Context mContext; // 基础上下文(Activity/Fragment 均可)
private Activity mHostActivity; // 实际控制屏幕方向的 Activity(Fragment 需通过 getActivity() 获取)
private final SensorManager mSensorManager;
private final Sensor mAccelerometer;
private boolean mIsFullscreen = false; // 是否处于全屏状态
private int mCurrentRotation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; // 当前屏幕方向
private long mLastUpdateTime = 0; // 上次方向更新时间
private boolean mIsSensorRegistered = false; // 传感器是否已注册
private boolean mIsFragmentAttached = false; // 是否绑定了 Fragment
// -------------------------- 构造方法(支持 Activity/Fragment) --------------------------
/**
* 构造方法(用于 Activity)
* @param activity 关联的 Activity
*/
public ScreenOrientationHelper(@NonNull Activity activity) {
this.mContext = activity;
this.mHostActivity = activity;
this.mSensorManager = (SensorManager) activity.getSystemService(Context.SENSOR_SERVICE);
this.mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
}
/**
* 构造方法(用于 Fragment)
* @param fragment 关联的 Fragment
*/
public ScreenOrientationHelper(@NonNull Fragment fragment) {
this.mContext = fragment.getContext();
this.mSensorManager = (SensorManager) fragment.getContext().getSystemService(Context.SENSOR_SERVICE);
this.mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
attachFragment(fragment); // 绑定 Fragment 生命周期
}
// -------------------------- Fragment 生命周期绑定 --------------------------
/**
* 绑定 Fragment 并监听其生命周期(自动处理 Activity 引用和资源释放)
*/
private void attachFragment(@NonNull Fragment fragment) {
mIsFragmentAttached = true;
// 获取 Fragment 所在的 Activity(确保在 onAttach 之后调用,这里通过 FragmentManager 监听)
fragment.getParentFragmentManager().registerFragmentLifecycleCallbacks(new FragmentManager.FragmentLifecycleCallbacks() {
@Override
public void onFragmentActivityCreated(@NonNull FragmentManager fm, @NonNull Fragment f, Bundle savedInstanceState) {
super.onFragmentActivityCreated(fm, f, savedInstanceState);
mHostActivity = f.getActivity(); // Fragment 关联 Activity 后,获取 Activity 引用
if (mHostActivity == null && BuildConfig.DEBUG) {
KLog.e(TAG, "Fragment 未关联 Activity,无法控制屏幕方向");
}
}
@Override
public void onFragmentDestroyed(@NonNull FragmentManager fm, @NonNull Fragment f) {
super.onFragmentDestroyed(fm, f);
release(); // Fragment 销毁时释放资源
fm.unregisterFragmentLifecycleCallbacks(this); // 解除监听
}
}, false);
}
// -------------------------- 核心功能方法 --------------------------
/**
* 设置是否全屏(控制传感器是否生效)
* @param isFullscreen true-全屏(启用传感器),false-非全屏(禁用传感器)
*/
public void setFullscreen(boolean isFullscreen) {
// 未获取到宿主 Activity 时,不执行任何操作
if (mHostActivity == null) {
if (BuildConfig.DEBUG) KLog.w(TAG, "宿主 Activity 为空,无法设置全屏状态");
return;
}
this.mIsFullscreen = isFullscreen;
if (isFullscreen) {
registerSensorListener();
} else {
unregisterSensorListener();
restorePortraitOrientation(); // 非全屏时恢复竖屏
}
}
/**
* 注册传感器监听
*/
public void registerSensorListener() {
if (mAccelerometer == null) {
if (BuildConfig.DEBUG) KLog.e(TAG, "设备不支持加速度传感器");
return;
}
if (mHostActivity == null) {
if (BuildConfig.DEBUG) KLog.w(TAG, "宿主 Activity 为空,无法注册传感器");
return;
}
if (!mIsSensorRegistered) {
boolean isRegistered = mSensorManager.registerListener(
this, mAccelerometer, SensorManager.SENSOR_DELAY_UI);
if (isRegistered) {
mIsSensorRegistered = true;
if (BuildConfig.DEBUG) KLog.d(TAG, "传感器注册成功");
} else {
if (BuildConfig.DEBUG) KLog.e(TAG, "传感器注册失败");
}
}
}
/**
* 注销传感器监听
*/
public void unregisterSensorListener() {
if (mIsSensorRegistered) {
mSensorManager.unregisterListener(this);
mIsSensorRegistered = false;
if (BuildConfig.DEBUG) KLog.d(TAG, "传感器注销成功");
}
}
/**
* 恢复竖屏方向
*/
public void restorePortraitOrientation() {
if (mHostActivity == null) return;
if (mCurrentRotation != ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
mHostActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
mCurrentRotation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
if (BuildConfig.DEBUG) KLog.d(TAG, "恢复竖屏成功");
}
}
/**
* 强制设置屏幕方向
* @param orientation 屏幕方向(如 ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)
*/
public void setScreenOrientation(int orientation) {
if (mHostActivity == null) return;
if (mCurrentRotation != orientation) {
mHostActivity.setRequestedOrientation(orientation);
mCurrentRotation = orientation;
if (BuildConfig.DEBUG) KLog.d(TAG, "设置屏幕方向:" + getOrientationName(orientation));
}
}
// -------------------------- 辅助方法 --------------------------
/**
* 获取当前屏幕方向名称(用于日志)
*/
private String getOrientationName(int orientation) {
switch (orientation) {
case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:
return "竖屏";
case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE:
return "横屏(正常)";
case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE:
return "横屏(反向)";
default:
return "未知方向";
}
}
// -------------------------- 传感器回调 --------------------------
@Override
public void onSensorChanged(SensorEvent event) {
// 非全屏、未注册传感器、无宿主 Activity 时直接返回
if (!mIsFullscreen || !mIsSensorRegistered || mHostActivity == null) return;
// 防抖处理:控制更新频率
long currentTime = System.currentTimeMillis();
if (currentTime - mLastUpdateTime < UPDATE_INTERVAL) return;
mLastUpdateTime = currentTime;
float x = event.values[0]; // x轴加速度(左右方向)
float y = event.values[1]; // y轴加速度(上下方向)
// 仅处理横屏方向切换(x轴主导且超过阈值)
if (Math.abs(x) > Math.abs(y) && Math.abs(x) > ACCEL_THRESHOLD) {
int newRotation = x < 0 ?
ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE : // 左横屏
ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; // 右横屏
setScreenOrientation(newRotation);
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// 传感器精度变化时无需处理
}
// -------------------------- 资源释放 --------------------------
/**
* 释放资源(Activity/Fragment 销毁时调用)
*/
public void release() {
unregisterSensorListener();
// 清空引用,避免内存泄漏
mContext = null;
mHostActivity = null;
if (BuildConfig.DEBUG) KLog.d(TAG, "资源释放完成");
}
// -------------------------- Getter 方法 --------------------------
public boolean isFullscreen() {
return mIsFullscreen;
}
public int getCurrentRotation() {
return mCurrentRotation;
}
public boolean isFragmentAttached() {
return mIsFragmentAttached;
}
}
Fragment 中使用
java
public class VideoFragment extends Fragment {
private ScreenOrientationHelper mOrientationHelper;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 直接传入 Fragment 构造
mOrientationHelper = new ScreenOrientationHelper(this);
}
// 示例:全屏播放时启用传感器,退出全屏时禁用
public void enterFullscreen() {
mOrientationHelper.setFullscreen(true);
}
public void exitFullscreen() {
mOrientationHelper.setFullscreen(false);
}
// (可选)如果需要手动释放,可在 onDestroy 补充(已通过生命周期回调自动处理)
@Override
public void onDestroy() {
super.onDestroy();
mOrientationHelper.release();
}
}
Activity 中使用
java
public class VideoActivity extends Activity {
private ScreenOrientationHelper mOrientationHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mOrientationHelper = new ScreenOrientationHelper(this);
}
public void toggleFullscreen(boolean isFullscreen) {
mOrientationHelper.setFullscreen(isFullscreen);
}
@Override
protected void onDestroy() {
super.onDestroy();
mOrientationHelper.release();
}
}