android 手机姿态(2)

需求

记录拍照时手机的朝向,用指南针可以解决,但有些手机会在仰角超过90度(即仰拍,屏幕朝下时)不能记录正确的方向。

理论

通过用手机的陀螺仪,根据加速度、磁场数据计算手机姿态,通过观察者模式通知状态变化

实现

通过陀螺仪获取://方位角、俯仰角与翻滚角,通过计算获取手机姿态,包括以下:屏幕方向:竖屏、横屏(右上)、横屏(右下),是否仰拍:俯拍、仰拍。

代码

MySensorViewModel用于记录角度,通知观察者

Kotlin 复制代码
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel

object MySensorViewModel : ViewModel() {

    //竖屏角度
    var currentDegreePortrait = MutableLiveData(0f)

    //横屏角度
    var currentDegreeLandscape = MutableLiveData(0f)

}

主要代码,用于监控设备姿态变化,计算后更新ViewModel

Kotlin 复制代码
import android.content.Context
import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
import android.hardware.SensorManager

/**
 * @ProjectName: mydemo
 * @Package: esa.library.sensor
 * @ClassName: MySensor
 * @Description: java类作用描述
 * @Author: Administrator
 * @CreateDate: 2023/04/06 13:33
 * @UpdateUser: Administrator
 * @UpdateDate: 2023/04/06 13:33
 * @UpdateRemark: 更新说明
 * @Version: 1.0
 */
class MySensor{

    companion object {
        private var instance: MySensor? = null

        @Synchronized
        fun getInstance(): MySensor {
            try {
                if (instance == null) {
                    instance = MySensor()
                }
            } catch (ex: Exception) {
                instance = MySensor()
            }
            return instance!!
        }
    }

    //传感器管理
    private lateinit var sensorManager: SensorManager

    //传感器
    private lateinit var sensor: Sensor

    /**
     * @param context
     * @return void
     * @description 初始化
     * @author Administrator
     * @time 2023/04/06 13:42
     */
    fun init(context: Context) {
        sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
        val ll = Sensoreventlistener()
        sensorManager.registerListener(ll, null, SensorManager.SENSOR_DELAY_NORMAL)

        //注册加速度传感器监听
        val acceleSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
        sensorManager.registerListener(ll, acceleSensor, SensorManager.SENSOR_DELAY_NORMAL)
        //注册磁场传感器监听
        val magSensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD)
        sensorManager.registerListener(ll, magSensor, SensorManager.SENSOR_DELAY_NORMAL)
    }

    //加速度参数与磁场参数
    private var gravity: FloatArray? = null
    private var geomagnetic: FloatArray? = null

    //上一次刷新时间
    private var lastrefresh = System.currentTimeMillis()

    //刷新频率
    private val tik: Long = 500

    //方位角、俯仰角与翻滚角
    var values = FloatArray(3)

    //传感器监听类
    private inner class Sensoreventlistener : SensorEventListener {
        override fun onSensorChanged(sensorEvent: SensorEvent) {
            if (System.currentTimeMillis() - lastrefresh > tik) {
                lastrefresh = System.currentTimeMillis()
                try {
                    when (sensorEvent.sensor.type) {
                        Sensor.TYPE_ACCELEROMETER -> gravity = sensorEvent.values.clone()
                        Sensor.TYPE_MAGNETIC_FIELD -> geomagnetic = sensorEvent.values.clone()
                    }
                    //计算-方位角、俯仰角与翻滚角
                    if (gravity != null && geomagnetic != null) {
                        val R = FloatArray(9)
                        if (SensorManager.getRotationMatrix(R, null, gravity, geomagnetic)) {
                            SensorManager.getOrientation(R, values)

                            updateView()
                        }
                    }
                } catch (ex: Exception) {
                    println(ex.toString())
                }
            }
        }

        override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {}
    }

    var currentDegreePortrait = 0f
    var currentDegreeLandscape = 0f //横屏角度

    /**
     * @param
     * @return void
     * @description 更新数据
     * @author Administrator
     * @time 2023/04/04 16:52
     */
    private fun updateView() {

        //横屏
        currentDegreeLandscape = ((360f + values[0] * 180f / Math.PI) % 360).toFloat()
        //右上横屏
        currentDegreeLandscape = (currentDegreeLandscape + 90) % 360
        //右下横屏
        if (values[2] > 0) {
            currentDegreeLandscape = (currentDegreeLandscape + 180) % 360
        }

        //竖屏
        currentDegreePortrait = ((360f + values[0] * 180f / Math.PI) % 360).toFloat()

        //判断是否有翻转
        //取绝对值
        val v2 = if (values[2] < 0) -values[2] else values[2]
        if (v2 > Math.PI / 2) {
            currentDegreePortrait = (currentDegreePortrait + 180) % 360
        }

//        //被观察者的通知更新
        MySensorViewModel.currentDegreePortrait.postValue(currentDegreePortrait)
        MySensorViewModel.currentDegreeLandscape.postValue(currentDegreeLandscape)
    }
}
相关推荐
东坡大表哥12 分钟前
【Android】常见问题集锦
android
V+zmm101341 小时前
社区养老服务小程序ssm+论文源码调试讲解
java·服务器·前端·javascript·小程序·毕业设计·1024程序员节
ShuQiHere2 小时前
【ShuQiHere】️ 深入了解 ADB(Android Debug Bridge):您的 Android 开发利器!
android·adb
魔法自动机3 小时前
Unity3D学习FPS游戏(9)武器音效添加、创建敌人模型和血条
android·学习·游戏
Lyqfor4 小时前
Redis学习:BitMap/HyperLogLog/GEO案例 、布隆过滤器BloomFilter、缓存预热+缓存雪崩+缓存击穿+缓存穿透
java·数据库·redis·学习·算法·缓存·1024程序员节
未来之窗软件服务5 小时前
业绩代码查询实战——php
android·开发语言·php·数据库嵌套
开心呆哥5 小时前
【Android Wi-Fi 操作命令指南】
android·python·pytest
睡觉谁叫6 小时前
一文解秘Rust如何与Java互操作
android·java·flutter·跨平台
五条凪15 小时前
从零开始的LeetCode刷题日记:70. 爬楼梯
数据结构·算法·leetcode·职场和发展·1024程序员节
----云烟----16 小时前
如何更改Android studio的项目存储路径
android·ide·android studio