這次通過設備的 Sensor 判斷使用者是否有搖晃手機(類似微信的搖一搖功能)
- 偵測手機搖動狀況
- 搖晃後更換圖片、震動手機
- 設定 2秒內只發動一次事件(搖晃過程會一直拿到 Sensor 數據,但不希望因此在短時間內連續震動或換圖)
ShakeShake
通過 SensorManager 來獲取 Sensor,Vibrator 來震動手機。
SensorManager
要使用 Sensor 的步驟很簡短,和 system 要到 SensorManager,在要到對應的 sensor.
然後 register Listener 用來接收 sensor 拿到的數據
1 2 3 4 |
val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager val sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) sensorManager.registerListener(sensorListener, sensor, SensorManager.SENSOR_DELAY_NORMAL) |
SensorEventListener
這裡以 Accelerometer 為例,當使用者搖動手機的時候,我們就執行 shakeHandler()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
private val sensorListener = object:SensorEventListener { override fun onAccuracyChanged(p0: Sensor?, p1: Int) {} override fun onSensorChanged(event: SensorEvent?) { if(event != null){ val xValue = Math.abs(event.values[0]) // 加速度 - X 軸方向 val yValue = Math.abs(event.values[1]) // 加速度 - Y 軸方向 val zValue = Math.abs(event.values[2]) // 加速度 - Z 軸方向 if (xValue > 20 || yValue > 20 || zValue > 20) { shakeHandler() } } } } |
ShakeHandler
通過 isChangingPhoto 這個自己定屬性,來防止因為搖動過程中多次觸發事件。
當我們接收到搖動事件的時候,
就先將 isChangingPhoto 改為 true,並開始更換圖片和震動手機( changImage() / doVibrate())
然後執行一個 Handler 相隔一秒以後在將 isChangingPhoto 改為 false.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
private fun shakeHandler() { if(isChangingPhoto){ return } isChangingPhoto = true changeImage() doVibrate() Handler().postDelayed({ isChangingPhoto = false }, 1000) } private fun doVibrate() { if(Build.VERSION.SDK_INT >= 26){ vibrator.vibrate(VibrationEffect.createOneShot(100, 10)) } else { vibrator.vibrate(100) } } private fun changeImage() { when(currentImageNumber){ 0 -> layout_landImageView.setImageResource(images[1]) 1 -> layout_landImageView.setImageResource(images[2]) 2 -> layout_landImageView.setImageResource(images[3]) 3 -> layout_landImageView.setImageResource(images[4]) 4 -> layout_landImageView.setImageResource(images[0]) } if(currentImageNumber != 4){ currentImageNumber += 1 } else { currentImageNumber = 0 } } |
SensorList
和 iOS 開發環境很不一樣的是,Android 的硬件設備都來自各種不同的廠商,但在 Android 中有定義 20幾種傳感器。
其中常用的應該是陀螺儀、加速計、方向傳感器、重力傳感器等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
public static final int TYPE_ACCELEROMETER = 1; public static final int TYPE_ACCELEROMETER_UNCALIBRATED = 35; public static final int TYPE_AMBIENT_TEMPERATURE = 13; public static final int TYPE_GAME_ROTATION_VECTOR = 15; public static final int TYPE_GEOMAGNETIC_ROTATION_VECTOR = 20; public static final int TYPE_GRAVITY = 9; public static final int TYPE_GYROSCOPE = 4; public static final int TYPE_GYROSCOPE_UNCALIBRATED = 16; public static final int TYPE_HEART_BEAT = 31; public static final int TYPE_HEART_RATE = 21; public static final int TYPE_LIGHT = 5; public static final int TYPE_LINEAR_ACCELERATION = 10; public static final int TYPE_LOW_LATENCY_OFFBODY_DETECT = 34; public static final int TYPE_MAGNETIC_FIELD = 2; public static final int TYPE_MAGNETIC_FIELD_UNCALIBRATED = 14; public static final int TYPE_MOTION_DETECT = 30; public static final int TYPE_POSE_6DOF = 28; public static final int TYPE_PRESSURE = 6; public static final int TYPE_PROXIMITY = 8; public static final int TYPE_RELATIVE_HUMIDITY = 12; public static final int TYPE_ROTATION_VECTOR = 11; public static final int TYPE_SIGNIFICANT_MOTION = 17; public static final int TYPE_STATIONARY_DETECT = 29; public static final int TYPE_STEP_COUNTER = 19; public static final int TYPE_STEP_DETECTOR = 18; |
我們可以通過 getSensorList 來拿到這個設備支援的 Sensor
比如我們這裡印出 sensor 類型、廠商名稱、版本
1 2 3 4 5 |
val allSensors = sensorManager.getSensorList(Sensor.TYPE_ALL) for(sensor in allSensors){ Log.i("sensors", "${sensor.name} - ${sensor.vendor} - ${sensor.version}") } |
這是紅米手機的一個例子
1 2 3 4 5 |
Accelerometer - BOSCH - 2062500 Magnetometer - Yamaha - 35193090 Magnetometer Uncalibrated - Yamaha - 35193090 ALSPS - LiteOn - 2 ...... |
Log
我們經常通過 android.util.Log 來印出一些資訊,而常見的有這幾個 Log 方法
- Log.v – v 代表 verbose – 任何信息都會輸出
- Log.d – d 代表 debug – 輸出調試信息
- Log.i – i 代表 information
- Log.w – w 代表 warning – 輸出警告資訊
- Log.e – e 代表 error – 輸出警告資訊。
參考
- 官方文件 SensorManager
- 可以到 Github 上看對應的 Source Code