kotlin、jetpack compose、Android加速度传感器调用

复制代码
package com.example.myball

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.example.myball.ui.theme.MyBallTheme
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewmodel.compose.viewModel
import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
import android.hardware.SensorManager
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.*
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalContext

class MainActivity : ComponentActivity() {
    // 定义屏幕宽度和高度变量
    private var screenWidth = 0f
    private var screenHeight = 0f
    // 定义传感器管理器变量
    private lateinit var sensorManager: SensorManager
    // 定义加速度传感器变量
    private var sensor: Sensor? = null
    // 使用 mutableStateOf 保存当前位置状态
    private var currentPosition by mutableStateOf(Offset.Zero)  // 直接保存位置状态
    // 新增传感器监听器
    private val sensorListener = object : SensorEventListener {
        // 当传感器数据发生变化时调用
        override fun onSensorChanged(event: SensorEvent?) {
            event?.let {
                // 检查传感器类型是否为加速度传感器
                if (it.sensor.type == Sensor.TYPE_ACCELEROMETER) {
                    // 直接更新位置
                    currentPosition = Offset(
                        x = (currentPosition.x - it.values[0] * 15f),  // 根据x轴加速度更新x位置
                        y = (currentPosition.y + it.values[1] * 15f)   // 根据y轴加速度更新y位置
                    )
                }
            }
        }
        // 当传感器精度发生变化时调用
        override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {}
    }
    // Activity创建时调用
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 启用边缘到边缘模式
        enableEdgeToEdge()
        // 获取屏幕宽度和高度
        val displayMetrics = resources.displayMetrics
        screenWidth = displayMetrics.widthPixels.toFloat()
        screenHeight = displayMetrics.heightPixels.toFloat()
        // 获取传感器管理器
        sensorManager = getSystemService(SENSOR_SERVICE) as SensorManager
        // 获取加速度传感器
        sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
        // 设置内容视图
        setContent {
            MyBallTheme {
                BallGame(currentPosition)  // 传递当前位置
            }
        }
    }
    // 添加生命周期回调(同之前)
    override fun onResume() {
        // 调用父类的onResume方法,确保Activity的正常生命周期继续执行
        super.onResume()
        // 使用安全调用操作符let来处理可能为null的sensor对象
        sensor?.let {
            // 获取SensorManager实例,并注册传感器监听器
            // 第一个参数是传感器监听器,用于处理传感器数据变化
            // 第二个参数是要注册的传感器对象
            // 第三个参数是传感器数据更新的延迟,SENSOR_DELAY_GAME表示游戏级别的延迟,大约为20ms
            sensorManager.registerListener(sensorListener, it, SensorManager.SENSOR_DELAY_GAME)
        }
    }

// 重写onPause方法,该方法在Activity暂停时被调用
    override fun onPause() {
    // 调用父类的onPause方法,确保父类中的逻辑得以执行
        super.onPause()
    // 取消注册传感器监听器,以停止接收传感器数据
        sensorManager.unregisterListener(sensorListener)
    }
}

@Composable
fun BallGame(position: Offset) {
    // 定义小球的尺寸
    val ballSize = 60f
    // 获取当前设备的配置信息
    val config = LocalConfiguration.current

    // 使用Canvas绘制小球
    Box(modifier = Modifier
        .fillMaxSize()
        .background(Color.Black) // 使用 Box 设置黑色背景
    ){
        Canvas(modifier = Modifier.fillMaxSize()) {
            // 添加边界限制(确保小球在屏幕内)
            val maxX = size.width - ballSize * 2
            val maxY = size.height - ballSize * 2
            val clampedPosition = position.copy(
                x = position.x.coerceIn(0f, maxX),
                y = position.y.coerceIn(0f, maxY)
            )

            drawCircle(
                color = Color.Red,
                radius = ballSize,
                center = clampedPosition + Offset(ballSize, ballSize)
            )
        }
    }

}
相关推荐
yi诺千金10 分钟前
Android U 自由窗口(浮窗)——启动流程(system_server侧流程)
android
清空mega2 小时前
第11章 网络编程
android·网络
自动化BUG制造器2 小时前
Android UI 线程不一定是主线程
android
无知的前端3 小时前
一文读懂-Jetpack与AndroidX
android·kotlin·android jetpack
河铃旅鹿4 小时前
Android开发-java版:SQLite数据库
android·数据库·笔记·学习·sqlite
旋律逍遥4 小时前
《Framework 开发》3、开发工具及命令行知识装备
android
啦啦9117145 小时前
安卓手机/平板/TV版 Rotation强制横屏显示工具!免ROOT可用!再推荐突破手机限制的3款神器
android·智能手机·电脑
宏集科技工业物联网5 小时前
从出厂到交付:能源设备运输如何实现全程风险可视化?
运输监测·智能物流·加速度传感器·设备运输·振动监测·冲击监测
汤面不加鱼丸5 小时前
flutter实践:混合app在部分android旧机型上显示异常
android·flutter
_李小白7 小时前
【Android FrameWork】延伸阅读:ActivityManagerService启动Activity
android