美文网首页Android开发经验谈安卓开发Android开发
Android实现摇晃手机的监听(摇一摇)

Android实现摇晃手机的监听(摇一摇)

作者: 蓝不蓝编程 | 来源:发表于2018-11-28 15:38 被阅读83次

    背景

    项目中,需要在某些界面监听用户摇晃动作做出相应的反应。下面分Kotlin和Java两种给出具体的代码。

    实现方案(Kotlin)

    1. 新增SensorManagerHelper.kt
    class SensorManagerHelper(private val context: Context) : SensorEventListener {
        // 速度阈值,当摇晃速度达到这值后产生作用
        private val SPEED_SHRESHOLD = 5000
        // 两次检测的时间间隔
        private val UPTATE_INTERVAL_TIME = 50
        // 传感器管理器
        private var sensorManager: SensorManager? = null
        // 传感器
        private var sensor: Sensor? = null
        // 重力感应监听器
        private var onShakeListener: OnShakeListener? = null
        // 手机上一个位置时重力感应坐标
        private var lastX: Float = 0.toFloat()
        private var lastY: Float = 0.toFloat()
        private var lastZ: Float = 0.toFloat()
        // 上次检测时间
        private var lastUpdateTime: Long = 0
    
        init {
            start()
        }
    
        /**
         * 开始检测
         */
        fun start() {
            // 获得传感器管理器
            sensorManager = context
                .getSystemService(Context.SENSOR_SERVICE) as SensorManager
            if (sensorManager != null) {
                // 获得重力传感器
                sensor = sensorManager!!.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
            }
            // 注册
            if (sensor != null) {
                sensorManager!!.registerListener(
                    this, sensor,
                    SensorManager.SENSOR_DELAY_GAME
                )
            }
        }
    
        /**
         * 停止检测
         */
        fun stop() {
            sensorManager!!.unregisterListener(this)
        }
    
        // 摇晃监听接口
        interface OnShakeListener {
            fun onShake()
        }
    
        // 设置重力感应监听器
        fun setOnShakeListener(listener: OnShakeListener) {
            onShakeListener = listener
        }
    
        /**
         * 重力感应器感应获得变化数据
         * android.hardware.SensorEventListener#onSensorChanged(android.hardware
         * .SensorEvent)
         */
        override fun onSensorChanged(event: SensorEvent) {
            // 现在检测时间
            val currentUpdateTime = System.currentTimeMillis()
            // 两次检测的时间间隔
            val timeInterval = currentUpdateTime - lastUpdateTime
            // 判断是否达到了检测时间间隔
            if (timeInterval < UPTATE_INTERVAL_TIME) return
            // 现在的时间变成last时间
            lastUpdateTime = currentUpdateTime
            // 获得x,y,z坐标
            val x = event.values[0]
            val y = event.values[1]
            val z = event.values[2]
            // 获得x,y,z的变化值
            val deltaX = x - lastX
            val deltaY = y - lastY
            val deltaZ = z - lastZ
            // 将现在的坐标变成last坐标
            lastX = x
            lastY = y
            lastZ = z
            val speed = Math.sqrt((deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ).toDouble()) / timeInterval * 10000
            // 达到速度阀值,发出提示
            if (speed >= SPEED_SHRESHOLD) {
                onShakeListener!!.onShake()
            }
        }
    
        override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {}
    
    }
    
    1. 调用
    SensorManagerHelper sensorHelper = SensorManagerHelper(this)
        sensorHelper.setOnShakeListener(object : SensorManagerHelper.OnShakeListener {
            override fun onShake() {
                Toast.makeText(this@MainActivity, "不要摇俺啦,好晕哦!", Toast.LENGTH_SHORT).show()
            }
        })
    

    实现方案(Java)

    1. 新增SensorManagerHelper.java
    public class SensorManagerHelper implements SensorEventListener {
    
        // 速度阈值,当摇晃速度达到这值后产生作用
        private final int SPEED_SHRESHOLD = 5000;
        // 两次检测的时间间隔
        private final int UPTATE_INTERVAL_TIME = 50;
        // 传感器管理器
        private SensorManager sensorManager;
        // 传感器
        private Sensor sensor;
        // 重力感应监听器
        private OnShakeListener onShakeListener;
        // 上下文对象context
        private Context context;
        // 手机上一个位置时重力感应坐标
        private float lastX;
        private float lastY;
        private float lastZ;
        // 上次检测时间
        private long lastUpdateTime;
    
        public SensorManagerHelper(Context context) {
            this.context = context;
            start();
        }
    
        /**
         * 开始检测
         */
        public void start() {
                    // 获得传感器管理器
                    sensorManager = (SensorManager) context
                    .getSystemService(Context.SENSOR_SERVICE);
            if (sensorManager != null) {
                // 获得重力传感器
                sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
            }
            // 注册
            if (sensor != null) {
                sensorManager.registerListener(this, sensor,
                        SensorManager.SENSOR_DELAY_GAME);
            }
        }
    
        /**
         * 停止检测
         */
        public void stop() {
            sensorManager.unregisterListener(this);
        }
    
        /**
         * 摇晃监听接口
         */
        public interface OnShakeListener {
            void onShake();
        }
    
        /**
         * 设置重力感应监听器
         */
        public void setOnShakeListener(OnShakeListener listener) {
            onShakeListener = listener;
        }
    
        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
        }
    
        /**
         * 重力感应器感应获得变化数据
         * android.hardware.SensorEventListener#onSensorChanged(android.hardware
         * .SensorEvent)
         */
        @Override
        public void onSensorChanged(SensorEvent event) {
            // 现在检测时间
            long currentUpdateTime = System.currentTimeMillis();
            // 两次检测的时间间隔
            long timeInterval = currentUpdateTime - lastUpdateTime;
            // 判断是否达到了检测时间间隔
            if (timeInterval < UPTATE_INTERVAL_TIME) return;
            // 现在的时间变成last时间
            lastUpdateTime = currentUpdateTime;
            // 获得x,y,z坐标
            float x = event.values[0];
            float y = event.values[1];
            float z = event.values[2];
            // 获得x,y,z的变化值
            float deltaX = x - lastX;
            float deltaY = y - lastY;
            float deltaZ = z - lastZ;
            // 将现在的坐标变成last坐标
            lastX = x;
            lastY = y;
            lastZ = z;
            double speed = Math.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ
                    * deltaZ)
                    / timeInterval * 10000;
            // 达到速度阀值,发出提示
            if (speed >= SPEED_SHRESHOLD) {
                onShakeListener.onShake();
            }
        }
    }
    
    1. 调用
    SensorManagerHelper sensorHelper = new SensorManagerHelper(this);
    sensorHelper.setOnShakeListener(() -> ToastUtil.showToast(ContextUtil.get(), "不要摇俺啦,好晕哦!"));
    

    onDestroy方法中停止监听
    sensorHelper.stop()

    如果只是某个界面监听摇晃,那就只在某个界面中增加;如果是整个app监听,建议在Application中添加监听(因app全生命周期监听,故不再需要增加停止监听方法)。

    1. 效果图(摇晃手机后)


      image.png
    2. demo代码(Kotlin)
      https://gitee.com/cxyzy1/shakeMonitorDemo

    安卓开发技术分享: https://www.jianshu.com/p/442339952f26

    相关文章

      网友评论

        本文标题:Android实现摇晃手机的监听(摇一摇)

        本文链接:https://www.haomeiwen.com/subject/nhxzqqtx.html