• android 手机姿态(2)


    需求

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

    理论

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

    实现

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

    代码
     

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

    1. import androidx.lifecycle.MutableLiveData
    2. import androidx.lifecycle.ViewModel
    3. object MySensorViewModel : ViewModel() {
    4. //竖屏角度
    5. var currentDegreePortrait = MutableLiveData(0f)
    6. //横屏角度
    7. var currentDegreeLandscape = MutableLiveData(0f)
    8. }

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

    1. import android.content.Context
    2. import android.hardware.Sensor
    3. import android.hardware.SensorEvent
    4. import android.hardware.SensorEventListener
    5. import android.hardware.SensorManager
    6. /**
    7. * @ProjectName: mydemo
    8. * @Package: esa.library.sensor
    9. * @ClassName: MySensor
    10. * @Description: java类作用描述
    11. * @Author: Administrator
    12. * @CreateDate: 2023/04/06 13:33
    13. * @UpdateUser: Administrator
    14. * @UpdateDate: 2023/04/06 13:33
    15. * @UpdateRemark: 更新说明
    16. * @Version: 1.0
    17. */
    18. class MySensor{
    19. companion object {
    20. private var instance: MySensor? = null
    21. @Synchronized
    22. fun getInstance(): MySensor {
    23. try {
    24. if (instance == null) {
    25. instance = MySensor()
    26. }
    27. } catch (ex: Exception) {
    28. instance = MySensor()
    29. }
    30. return instance!!
    31. }
    32. }
    33. //传感器管理
    34. private lateinit var sensorManager: SensorManager
    35. //传感器
    36. private lateinit var sensor: Sensor
    37. /**
    38. * @param context
    39. * @return void
    40. * @description 初始化
    41. * @author Administrator
    42. * @time 2023/04/06 13:42
    43. */
    44. fun init(context: Context) {
    45. sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
    46. val ll = Sensoreventlistener()
    47. sensorManager.registerListener(ll, null, SensorManager.SENSOR_DELAY_NORMAL)
    48. //注册加速度传感器监听
    49. val acceleSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
    50. sensorManager.registerListener(ll, acceleSensor, SensorManager.SENSOR_DELAY_NORMAL)
    51. //注册磁场传感器监听
    52. val magSensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD)
    53. sensorManager.registerListener(ll, magSensor, SensorManager.SENSOR_DELAY_NORMAL)
    54. }
    55. //加速度参数与磁场参数
    56. private var gravity: FloatArray? = null
    57. private var geomagnetic: FloatArray? = null
    58. //上一次刷新时间
    59. private var lastrefresh = System.currentTimeMillis()
    60. //刷新频率
    61. private val tik: Long = 500
    62. //方位角、俯仰角与翻滚角
    63. var values = FloatArray(3)
    64. //传感器监听类
    65. private inner class Sensoreventlistener : SensorEventListener {
    66. override fun onSensorChanged(sensorEvent: SensorEvent) {
    67. if (System.currentTimeMillis() - lastrefresh > tik) {
    68. lastrefresh = System.currentTimeMillis()
    69. try {
    70. when (sensorEvent.sensor.type) {
    71. Sensor.TYPE_ACCELEROMETER -> gravity = sensorEvent.values.clone()
    72. Sensor.TYPE_MAGNETIC_FIELD -> geomagnetic = sensorEvent.values.clone()
    73. }
    74. //计算-方位角、俯仰角与翻滚角
    75. if (gravity != null && geomagnetic != null) {
    76. val R = FloatArray(9)
    77. if (SensorManager.getRotationMatrix(R, null, gravity, geomagnetic)) {
    78. SensorManager.getOrientation(R, values)
    79. updateView()
    80. }
    81. }
    82. } catch (ex: Exception) {
    83. println(ex.toString())
    84. }
    85. }
    86. }
    87. override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {}
    88. }
    89. var currentDegreePortrait = 0f
    90. var currentDegreeLandscape = 0f //横屏角度
    91. /**
    92. * @param
    93. * @return void
    94. * @description 更新数据
    95. * @author Administrator
    96. * @time 2023/04/04 16:52
    97. */
    98. private fun updateView() {
    99. //横屏
    100. currentDegreeLandscape = ((360f + values[0] * 180f / Math.PI) % 360).toFloat()
    101. //右上横屏
    102. currentDegreeLandscape = (currentDegreeLandscape + 90) % 360
    103. //右下横屏
    104. if (values[2] > 0) {
    105. currentDegreeLandscape = (currentDegreeLandscape + 180) % 360
    106. }
    107. //竖屏
    108. currentDegreePortrait = ((360f + values[0] * 180f / Math.PI) % 360).toFloat()
    109. //判断是否有翻转
    110. //取绝对值
    111. val v2 = if (values[2] < 0) -values[2] else values[2]
    112. if (v2 > Math.PI / 2) {
    113. currentDegreePortrait = (currentDegreePortrait + 180) % 360
    114. }
    115. // //被观察者的通知更新
    116. MySensorViewModel.currentDegreePortrait.postValue(currentDegreePortrait)
    117. MySensorViewModel.currentDegreeLandscape.postValue(currentDegreeLandscape)
    118. }
    119. }

  • 相关阅读:
    不花一分钱,在 Mac 上跑 Windows(M1/M2 版)
    【统计分析和过程改进】上海道宁带来Minitab软件合集,帮助企业和组织发挥数据的价值
    Error:java: 错误: 不支持发行版本 5
    质数的判定和质因数分解
    Redis基本内容
    归并排序算法代码
    Redis 笔记 01:入门篇
    jpsall脚本
    嵌入式软件架构中抽象层设计方法
    33.高等数学
  • 原文地址:https://blog.csdn.net/tvrddmss/article/details/143214436