安卓传感器横竖屏切换

工具方法 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();
    }
}
相关推荐
用户693717500138443 分钟前
21.Kotlin 接口:接口 (Interface):抽象方法、属性与默认实现
android·后端·kotlin
just today1 小时前
价值投资还是短线投资?
经验分享
丝斯20111 小时前
AI学习笔记整理(19)—— AI核心技术(深度学习3)
人工智能·笔记·学习
im_AMBER1 小时前
Leetcode 66 几乎唯一子数组的最大和
数据结构·笔记·学习·算法·leetcode
TRSsd1 小时前
如何把视频转为二维码?用于展示宠物训练
经验分享
QING6181 小时前
Jetpack Compose 中 Flow 收集详解 —— 新手指南
android·kotlin·android jetpack
客梦1 小时前
数据结构-图结构
java·数据结构·笔记
泓博1 小时前
Android截屏汇报问题
android
_李小白1 小时前
【Android FrameWork】第二十一天:AudioFlinger
android